NSURL *documentURL = [[[NSBundle mainBundle] resourceURL] URLByAppendingPathComponent:#"item_70_1_3.ppt"];
PSPDFDocument *document = [PSPDFDocument documentWithURL:documentURL];
NSURL *tempURL = PSPDFTempFileURLWithPathExtension(#"flattened_signaturetest", #"pdf");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[[PSPDFProcessor defaultProcessor] generatePDFFromDocument:document pageRange:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, document.pageCount)] outputFileURL:tempURL options:#{kPSPDFProcessorAnnotationTypes : #(PSPDFAnnotationTypeAll)} progressBlock:^(NSUInteger currentPage, NSUInteger numberOfProcessedPages, NSUInteger totalPages) {
// Access UI only from main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[PSPDFProgressHUD showProgress:(numberOfProcessedPages+1)/(float)totalPages status:PSPDFLocalize(#"Preparing...")];
});
} error:NULL];
// completion
dispatch_async(dispatch_get_main_queue(), ^{
[PSPDFProgressHUD dismiss];
PSPDFDocument *flattenedDocument = [PSPDFDocument documentWithURL:tempURL];
PSPDFViewController *pdfController = [[PSPDFViewController alloc] initWithDocument:flattenedDocument];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:pdfController];
[self presentViewController:navController animated:YES completion:NULL];
});
});
i open a empty content using above code : (
The PSPDFProcessor feature is experimental. Please try if the PPT file works if you open it with Safari, it uses mostly Apple's libraries and they can fail for certain files. The code here looks like it's simply copied from my examples in PSPDFCatalog and is thus fine.
Related
I'm using TBXML to parse an http-XML file and display the contents in a UILabel & UIImageView .
The call to the XML is done with an async request.
When i view the logs the last log element in the succesblock is printed immediately. The changes in the UILabel & UIImageview are only visible after a few seconds.
How can i let IOS refresh the UI straight after finishing processing the XML ?
// Create a success block to be called when the async request completes
TBXMLSuccessBlock successBlock = ^(TBXML *tbxmlDocument) {
// If TBXML found a root node, process element and iterate all children
NSLog(#"PROCESSING ASYNC CALLBACK");
if (tbxmlDocument.rootXMLElement)
[self traverseElement:tbxmlDocument.rootXMLElement];
myArticle.Body = [[StringCleaner sharedInstance] cleanedString:myArticle.Body];
// myArticle.Body = [myArticle.Body stringByConvertingHTMLToPlainText];
self.articleBody.text = myArticle.Body;
self.articleBody.numberOfLines= 0;
self.articleBody.lineBreakMode = UILineBreakModeWordWrap;
[self.articleBody sizeToFit];
// set scroll view size
self.articleBodyScrollView.contentSize = CGSizeMake(self.articleBodyScrollView.contentSize.width, self.articleBody.frame.size.height);
NSURL *url = [NSURL URLWithString:myArticle.Photo];
NSData *data = [NSData dataWithContentsOfURL:url];
if (data != NULL)
{
UIImage *image = [UIImage imageWithData:data];
// articlePhoto = [[UIImageView alloc] initWithImage:image];
[self.articlePhoto setImage:image];
}else {
NSLog(#"no data");
}
NSLog(#"FINISHED PROCESSING ASYNC");
// [self printArticles];
};
// Create a failure block that gets called if something goes wrong
TBXMLFailureBlock failureBlock = ^(TBXML *tbxmlDocument, NSError * error) {
NSLog(#"Error! %# %#", [error localizedDescription], [error userInfo]);
};
// tbxml = [[TBXML alloc] initWithURL:[NSURL URLWithString:someXML]];
tbxml = [[TBXML alloc] initWithURL:[NSURL URLWithString:records]
success:successBlock
failure:failureBlock];
Sounds like your trying to update UI but not on UI thread. Wrap your UILabel and UIImageView updates into a dispatch_async on the main thread, e.g.:
dispatch_async(dispatch_get_main_queue(), ^
{
[self.articlePhoto setImage:image];
});
Hello everyone, I want to create if loop that running asynchoursly with this code:
NSString *care = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://localhost/untitled.txt"]];
if (care == #"ONRED") { //untitled.txt = ONRED
[red_on setHidden:NO];
[red_off setHidden:YES];
}
How I can run the if statement like a loop?
If I get you right, you can put those statements in a method and call performSelectorInBackground:
(void)asyncMethod {
NSString *care = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://localhost/untitled.txt"]];
if (care == #"ONRED") { //untitled.txt = ONRED
[red_on setHidden:NO];
[red_off setHidden:YES];
}
}
// in some other method
[self performSelectorInBackground:#selector(asyncMethod) withObject:nil];
Another option is to use the grand central dispatch (as described in this answer):
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
NSString *care = [[NSString alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://localhost/untitled.txt"]];
if (care == #"ONRED") { //untitled.txt = ONRED
[red_on setHidden:NO];
[red_off setHidden:YES];
}
});
am trying to do a simple AVAudioPlayer based application to play 2 different music upon button pressed, there is 2 views, the first is the home view contains 2 buttons,each button set a song which is named as integer(1.mp3, 2.mp3.....etc)and here'e the code
#import "podHome.h"
#import "podMusic.h"
#import "ArabAppDelegate.h"
#implementation podHome
#synthesize song1;
#synthesize tabi;
int CurrentPlay;
NSString *Currenttxt;
-(IBAction)uae{
CurrentPlay=1;
Currenttxt=#"uae";
podMusic *newContro=[[podMusic alloc] init];
[newContro setCurrentPlay1:CurrentPlay setCurrentText:Currenttxt];
ArabAppDelegate *theDelegate = (ArabAppDelegate*)[[UIApplication sharedApplication] delegate];
tabi = theDelegate.tabcontrolPod;
tabi.selectedIndex = 1;
[newContro release];
}
-(IBAction)libya{
CurrentPlay=2;
Currenttxt=#"uae";
podMusic *newContro=[[podMusic alloc] init];
[newContro setCurrentPlay1:CurrentPlay setCurrentText:Currenttxt];
ArabAppDelegate *theDelegate = (ArabAppDelegate*)[[UIApplication sharedApplication] delegate];
tabi = theDelegate.tabcontrolPod;
tabi.selectedIndex = 1;
[newContro release];
}
these tow (IBActions) are linked to the two buttons when pressing on one of them it will change to the other view and start playing the song
- (void)viewWillAppear:(BOOL)animated {
if((played == 1)&&(isBacked==FALSE)){
NSString *filePath = [[NSBundle mainBundle] pathForResource:texting
ofType:#"txt"];
NSString *filenameString = [NSString stringWithContentsOfFile:filePath usedEncoding:nil error:nil];
CurrentTex.text = filenameString;
AudioSessionInitialize(NULL, NULL, NULL, NULL);
UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory,sizeof(sessionCategory), &sessionCategory);
AudioSessionSetActive(YES);
playBtnBG = [[UIImage imageNamed:#"play-pod.png"] retain];
pauseBtnBG = [[UIImage imageNamed:#"pause-pod.png"] retain];
[playButton setBackgroundImage:pauseBtnBG forState:UIControlStateNormal];
[self registerForBackgroundNotifications];
updateTimer = nil;
duration.adjustsFontSizeToFitWidth = YES;
currentTime.adjustsFontSizeToFitWidth = YES;
progressBar.minimumValue = 0.0;
NSString *path=[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%d",CurrentPlay] ofType:#"mp3"];
self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];
[player stop];
//self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
if (self.player)
{
[self updateViewForPlayerInfo:player];
[self updateViewForPlayerState:player];
player.numberOfLoops = 0;
player.delegate = self;
}
[self startPlaybackForPlayer:player];
fileName.text= [[NSString alloc]initWithFormat:#"%#", songName];
// [fileURL release];
// CurrentPlay = 0;
isBacked = TRUE;
}
[super viewWillAppear:animated];
}
- (void)setCurrentPlay1:(int)varP setCurrentText:(NSString *)varT{
CurrentPlay = varP;
texting = varT;
played = 1;
isBacked = FALSE;
}
but the problem is that when the song is playing and am back to home view and pressing on the other song's button, it starts to play with the first one at the same time, i think the first should stop to begin the other, what should i release to do that???
My guess is that you have two instances of the AVAudioPlayer, and when you set them both to play, they both do!
One solution would be to tell other players to stop when you activate a new one, but that will quickly become troublesome as the number of players increases.
Instead you;'d be better of just setting up one player, and change it's song in accordance to what button was pressed. That way, there is no chance that two music tracks will play at the same time.
In your first button action write like this.
if(player2.isPlaying)
{
[player2 stop];
}
in the same way do the same thing in second button action like this.
if(player1.isPlaying)
{
[player1 stop];
}
In the application I'm creating, I load a long page of HTML into a webView and then print it to a PDF using the following:
-(void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
{
if ([frame isEqual:[[self doc] mainFrame]])
{
NSMutableData *newData = [[NSMutableData alloc] init];
NSPrintInfo *newInfo = [NSPrintInfo sharedPrintInfo];
NSView *docView = [[[[self doc] mainFrame] frameView] documentView];
NSPrintOperation *newPrintOp = [NSPrintOperation PDFOperationWithView:docView insideRect:docView.bounds toData:newData printInfo:newInfo];
BOOL runPrint = [newPrintOp runOperation];
if (!runPrint)
{
NSLog(#"Print Failed");
}
PDFDocument *newDoc = [[PDFDocument alloc] initWithData:newData];
[newData release];
[self setPdf:newDoc];
//Other code here
}
}
The problem is that when I look at newDoc, it is a huge PDF of a single page. What I would prefer would be the printing acting the same as it does from the "save as PDF..." dialog - that is, splitting the PDF into multiple reasonably-sized pages.
Does anyone know how to accomplish this?
I attempted inserting the following after NSPrintInfo *newInfo = [NSPrintInfo sharedPrintInfo];
[newInfo setVerticalPagination:NSAutoPagination];
[newInfo setHorizontalPagination:NSAutoPagination];
NSAutoPagination is described in the docs as the following:
NSAutoPagination
The image is divided into equal-sized rectangles and placed in one column of pages.
Available in Mac OS X v10.0 and later.
Declared in NSPrintInfo.h.
This had no effect on the printed PDF.
You get a file with one large page because + PDFOperationWithView: method doesn't support pagination at all. For that reason calling - setVerticalPagination: or - setHoriziontalPagination: doesn't change anything.
You could try use "classical" + printOperationWithView:printInfo: method, configure it to save PDF to temporary location and then create PDFDocument with contents of obtained file. I hope that fragment of code below will help.
NSMutableDictionary *dict = [[NSPrintInfo sharedPrintInfo] dictionary];
[dict setObject:NSPrintSaveJob forKey:NSPrintJobDisposition];
[dict setObject:temporaryFilePath forKey:NSPrintSavePath];
NSPrintInfo *pi = [[NSPrintInfo alloc] initWithDictionary:dict];
[pi setHorizontalPagination:NSAutoPagination];
[pi setVerticalPagination:NSAutoPagination];
NSPrintOperation *op = [NSPrintOperation printOperationWithView:[[[webView mainFrame] frameView] documentView] printInfo:pi];
[pi release];
[op setShowsPrintPanel:NO];
[op setShowsProgressPanel:NO];
if ([op runOperation] ){
PDFDocument *doc = [[[PDFDocument alloc] initWithURL:[NSURL fileURLWithPath: temporaryFilePath]] autorelease];
// do with doc what you want, remove file, etc.
}
I have a UITableView consisting of roughly 10 subclassed UITableViewCells named TBPostSnapCell. Each cell, when initialised, sets two of its variables with UIImages downloaded via GCD or retrieved from a cache stored in the user's documents directory.
For some reason, this is causing a noticeable lag on the tableView and therefore disrupting the UX of the app & table.
Please can you tell me how I can reduce this lag?
tableView... cellForRowAtIndexPath:
if (post.postType == TBPostTypeSnap || post.snaps != nil) {
TBPostSnapCell *snapCell = (TBPostSnapCell *) [tableView dequeueReusableCellWithIdentifier:snapID];
if (snapCell == nil) {
snapCell = [[[NSBundle mainBundle] loadNibNamed:#"TBPostSnapCell" owner:self options:nil] objectAtIndex:0];
[snapCell setPost:[posts objectAtIndex:indexPath.row]];
[snapCell.bottomImageView setImage:[UIImage imageNamed:[NSString stringWithFormat:#"%d", (indexPath.row % 6) +1]]];
}
[snapCell.commentsButton setTag:indexPath.row];
[snapCell.commentsButton addTarget:self action:#selector(comments:) forControlEvents:UIControlEventTouchDown];
[snapCell setSelectionStyle:UITableViewCellSelectionStyleNone];
return snapCell;
}
TBSnapCell.m
- (void) setPost:(TBPost *) _post {
if (post != _post) {
[post release];
post = [_post retain];
}
...
if (self.snap == nil) {
NSString *str = [[_post snaps] objectForKey:TBImageOriginalURL];
NSURL *url = [NSURL URLWithString:str];
[TBImageDownloader downloadImageAtURL:url completion:^(UIImage *image) {
[self setSnap:image];
}];
}
if (self.authorAvatar == nil) {
...
NSURL *url = [[[_post user] avatars] objectForKey:[[TBForrstr sharedForrstr] stringForPhotoSize:TBPhotoSizeSmall]];
[TBImageDownloader downloadImageAtURL:url completion:^(UIImage *image) {
[self setAuthorAvatar:image];
}];
...
}
}
TBImageDownloader.m
+ (void) downloadImageAtURL:(NSURL *)url completion:(TBImageDownloadCompletion)_block {
if ([self hasWrittenDataToFilePath:filePathForURL(url)]) {
[self imageForURL:filePathForURL(url) callback:^(UIImage * image) {
_block(image); //gets UIImage from NSDocumentsDirectory via GCD
}];
return;
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(queue, ^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
dispatch_async(dispatch_get_main_queue(), ^{
[self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)];
_block(image);
});
});
}
First thing to try is converting DISPATCH_QUEUE_PRIORITY_HIGH (aka ONG MOST IMPORTANT WORK EVER FORGET EVERYTHING ELSE) to something like DISPATCH_QUEUE_PRIORITY_LOW.
If that doesn't fix it you could attempt to do the http traffic via dispatch_sources, but that is a lot of work.
You might also just try to limit the number of in flight http fetches with a semaphore, the real trick will be deciding what the best limit is as the "good" number will depend on the network, your CPUs, and memory pressure. Maybe benchmark 2, 4, and 8 with a few configurations and see if there is enough pattern to generalize.
Ok, lets try just one, replace the queue = ... with:
static dispatch_once_t once;
static dispatch_queue_t queue = NULL;
dispatch_once(&once, ^{
queue = dispatch_queue_create("com.blah.url-fetch", NULL);
});
Leave the rest of the code as is. This is likely to be the least sputtery, but may not load the images very fast.
For the more general case, rip out the change I just gave you, and we will work on this:
dispatch_async(queue, ^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
dispatch_async(dispatch_get_main_queue(), ^{
[self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)];
_block(image);
});
});
Replacing it with:
static dispatch_once_t once;
static const int max_in_flight = 2; // Also try 4, 8, and maybe some other numbers
static dispatch_semaphore_t limit = NULL;
dispatch_once(&once, ^{
limit = dispatch_semaphore_create(max_in_flight);
});
dispatch_async(queue, ^{
dispatch_semaphore_wait(limit, DISPATCH_TIME_FOREVER);
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
// (or you might want the dispatch_semaphore_signal here, and not below)
dispatch_async(dispatch_get_main_queue(), ^{
[self writeImageData:UIImagePNGRepresentation(image) toFilePath:filePathForURL(url)];
_block(image);
dispatch_semaphore_signal(limit);
});
});
NOTE: I haven't tested any of this code, even to see if it compiles. As written it will only allow 2 threads to be executing the bulk of the code in your two nested blocks. You might want to move the dispatch_semaphore_signal up to the commented line. That will limit you to two fetches/image creates, but they will be allowed to overlap with writing the image data to a file and calling your _block callback.
BTW you do a lot of file I/O which is faster on flash then any disk ever was, but if you are still looking for performance wins that might be another place to attack. For example maybe keeping the UIImage around in memory until you get a low memory warning and only then writing them to disk.