Navigation taking time - ios

I am navigating by clicking a button to a viewcontroller where I am loading webview,but after clicking the button it is taking some time,how to navigate faster and load webview faster,please help.I have only the following code in second viewcontroller.
-(void)viewWillAppear:(BOOL)animated{
self.navigationController.navigationBarHidden=YES;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://myurl"]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.wb loadRequest:request] ;
});
});
}

Try this code
-(void)viewWillAppear:(BOOL)animated{
self.navigationController.navigationBarHidden=YES;
dispatch_queue_t jsonParsingQueue = dispatch_queue_create("jsonParsingQueue", NULL);
// execute a task on that queue asynchronously
dispatch_async(jsonParsingQueue, ^{
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://myurl"]];
dispatch_async(dispatch_get_main_queue(), ^{
[self.wb loadRequest:request] ;
});
});
}

If I understand your question, there isn't much you can do to make if faster. That request speed is based on internet speed (Over which you don't have much of a control).
Also the request already happens asynchronously, so there's no need to do that yourself.

You are combining two things as you navigate to your webview
loading and displaying a view
Retrieving data from the internet
You can only directly influence the first one, the second one is well beyond your control.
By performing the asynchronous NSURLRequest from within the viewWillAppear method, you are telling iOS to delay showing the view until the internet has given you all the data it needs.
A better approach is to configure all the visual elements of your new view, display that view in the interface, and then AFTER the new view is visible, perform your NSURLRequest.
Adding a UIActivityIndicator may also help your users realize that your app was snappy and responsive, and the delay they are experiencing is from the internet.
Perhaps the easiest way to fix this would be to move your code over to
- (void)viewDidLoad {}

Related

iOS stringByEvaluatingJavaScriptFromString - UI freeze

In my iOS app (a kind of flashCard application) I'm using a UIWebView and once the webview content loading is finished I need to perform some UI operations (changes).
I'm checking for this in webViewDidFinishLoad.
When a user taps on a card it will flip and different content is gets loaded. I am using the code below in this flipAction as well as in swipeAction (when user moves from one card to another) to check:
if (![[myWebView stringByEvaluatingJavaScriptFromString:#"document.readyState"] isEqualToString:#"complete"])
{
[self performSelector:#selector(myCustomMethod:) withObject:self afterDelay:3.0];
}
Sometimes, not always, my UI will freeze on the above if condition and after that the UI will not respond further. The app must be manually killed and relaunched.
Do I need to call stringByEvaluatingJavaScriptFromString: method other than thread?
or what may be the cause for this?
You can try background thread
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
// async operation
// Call your method here
dispatch_sync(dispatch_get_main_queue(), ^{
// Update UI here
});
});

iOS - How to display a large number of images in sequence

I am working on an app that needs to flip through 300 or so images in sequence, with a 2 second delay between images.
These images are barcodes that are generated on the fly during the display. They are not stored images.
The display is in a navigation controller and I would like the user to be able to click the 'back' button without the app crashing from a selector being sent to an instance that no longer exists.
I know that it is possible to animate a UIImageView, but I don't want to create an large array of images because of memory issues.
I'd like to do this in a loop where I generate the barcode, display the image, delay 2 seconds, and then repeat with the next image.
The following code works, but crashes if you click the 'back' button, with a 'message sent to deallocated instance' error.
NSSet *dataSet = [self fetchDataSet];
for (MyBarCode *data in dataSet) {
// display barcode in UIImageView
[self updateBarCodeImage:data ];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: 2.0]];
}
There doesn't seem to be a way to cancel this timer, or I could do that in viewWillDisapear.
What's the right way to do this?
Please don't just point me to the animationImages examples. I've already seen all of them and -- again -- I don't want to have to hold all these images in memory during the animation. If there's a way to generate the images on the fly during animation, now that would be interesting.
I think something like this should work:
__weak ViewController *bSelf = self;
NSSet *dataSet = [self fetchDataSet];
dispatch_queue_t myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(myQueue, ^{
__strong ViewController *sSelf = bSelf;
for (BoardingPass *data in dataSet) {
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[sSelf updateBarCodeImage:data]
});
}
});
UPDATED:
Well I am not sure what exactly you are looking for. If you are talking about a simple animation than yes, Cocos 2D would be overkill. In that case I suggest doing this tutorial which gave me a lot of ideas on a project I was working on some time back:
http://www.raywenderlich.com/2454/how-to-use-uiview-animation-tutorial

webViewDidFinishLoad blocks main thread

I just noticed that webViewDidFinishLoad method blocks an entire application, so i can't even touch any buttons.
I need to parse the resulting page of the UIWebView and it can take a lot of time. So what's the best way to parse it without blocking an entire application? Maybe create another thread?
Parse it in the background using GCD:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// Get the contents from the UIWebView (in the main thread)
NSString *data = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.textContent"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Parse the data here
dispatch_sync(dispatch_get_main_queue(), ^{
// Update the UI here
});
});
}
It's normal -webViewDidFinishLoad to be called on the main thread. What you need to do is to get the html and do the parsing operation by dispatching it to another queue.

Is it possible to "pause" a thread and let another operation proceed first?

I set up 2 UIWebViews, the first is controlling the second. They are communicating though ajax requests.
I want to load a website in the second WebView and then proceed with other tasks. Unfortunately this is crashing. It is crashing because the Web Thread is being occupied by the first right after it gets a response. The second has no time to load the web page and causes a deadlock.
I want to delay the response until the second WebView has fully loaded the web page. Currently the second WebView starts loading right after the first WebView gets and response (thats when the Web Thread is being released).
Is it possible to "suspend"/"pause" the current (first WebView) execution until the second WebView has finished loading? This means to start the execution of the second WebView as well.
events:
First WebView sends command to load web page (using synchronous AJAX command)
Web Thread blocked by task of first WebView
Execution of command and computation of Response
Returning Response
Second WebView starts Loading of web page
deadlock
I want event 5 to be before event 4. Is this possible?
Solution:
As you can read in the comments I've solved my problem by making then work concurrently. Basically I had to make use of the Grand Central Dispatch (GCD). Another option would be to implement it with NSOperationQueues which gives you more control about the flow of execution, but tends to be more complicated to implement.
helpful literature:
Apple: Concurrency Programming Guide
Multithreading and Grand Central Dispatch on iOS for Beginners Tutorial
How To Use NSOperations and NSOperationQueues
Now, this is may require some tweaking, but it should give you a good place to start.
Basically, we create a concurrent GCD queue and dispatch 2 async calls to load HTML strings with the contents of your 2 different URLS.
When the requests complete they will load their html strings into your web views. Note that the first UIWebView will only load its data if the second UIWebView has already been loaded.
__weak ViewController *bSelf = self;
dispatch_queue_t webQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(webQueue, ^{
NSError *error;
bSelf.html1 = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://google.com"] encoding:NSASCIIStringEncoding error:&error];
if( !bSelf.secondLoaded)
{
dispatch_sync(dispatch_get_main_queue(), ^{
[bSelf.webView1 loadHTMLString:bSelf.html1 baseURL:nil];
});
}
});
dispatch_async(webQueue, ^{
NSError *error;
bSelf.html2 = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://amazon.com"] encoding:NSASCIIStringEncoding error:&error];
bSelf.secondLoaded = YES;
dispatch_sync(dispatch_get_main_queue(), ^{
[bSelf.webView2 loadHTMLString:bSelf.html2 baseURL:nil];
if( bSelf.html1 != nil )
{
[bSelf.webView1 loadHTMLString:bSelf.html1 baseURL:nil];
}
});
});
Yes, the two best ways to do this would be to use either Grand Central Dispatching (GCD) or NSOperation and NSOperationQueue.
The explanation of this is quite long, but I would direct you to read something like this. You can find a lot of other resources if you search for these terms in google.
Have you tried something like this?
- (void)viewDidLoad
{
[super viewDidLoad];
self.webView.delegate = self;
self.webView2.delegate = self;
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"yourURL"]]];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (webView == self.webView)
{
if (!self.webView.isLoading)
{
[self.webView2 loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"yourURL"]]];
}
}
}

GCD, order of execution?

Assume we have one UIVewcontroller, call it A, in the viewdidload of that VC we add to it two UIViewcontrollers( B,C ). now to make the UI smooth in the Viewdidload of A we do some GCD work
dispatch_queue_t queue = dispatch_queue_create("CustomQueue", NULL);
dispatch_async(queue, ^{
// Create views, do some setup here, etc etc
// Perform on main thread/queue
dispatch_async(dispatch_get_main_queue(), ^{
// this always has to happen on the main thread
[self.view addSubview:myview1];
[self.view addSubview:myview2];
[self.view addSubview:myview3];
});
});
Now based on this code, am I guaranteed that the views will be added in the same order? view 1 , then 2 , then 3?
I am noticing that arbitrarily some views shows up before others !!
Your problem is almost certainly this part:
dispatch_async(queue, ^{
// Create views, do some setup here, etc etc
You cannot do anything view-related (or really anything UIKit-related) on a background thread. Period.

Resources