Loading 20+ plist files into memory at app launch - ios

Following up on my question here, I have 22 plist files that I'd like to load at launch time. Right now, it works, but as you can imagine the launch is very slow.
What can I do to best minimize the launch time?
Can I load each one in a seperate thread using NSOperationQueue? I've also read that converting the plists to binary will help.

You can use NSOperationQueue, performSelectorInBackground or Grand Central Dispatch (once you know how to use the later you'll use that very often as it makes threading very easy). The main point is simply is to not load them on the main thread and to load them one after another (if you try to load them all at once each in its own thread performance is likely to not be good either). When the loading is done, call a method on your main thread to assign the result.
For example:
yourQueue = dispatch_queue_create("plist load queue", NULL);
for (filename in plistFilesToLoad) {
dispatch_async(yourQueue, ^{
// This part will be executed in a thread,
// each block after the other.
NSDictionary *dict = [self loadPlist:filename];
dispatch_async(dispatch_get_main_queue(), ^{
// Assign the result on the main thread.
[self finishedLoading:filename withDictionary:dict];
});
});
}
The dispatch_async calls come back quickly, so the loop itself will be executed quickly. But GCD will then execute each block one after another on a separate thread.

Related

Too many objects to delete in Parse, blocks UI: Doesnt respond, cancel deletion

I am trying to delete elements from Parse after filtering. Everything works fine when the number of elements is relatively small. However, when it increases, the problem arises. Basically, I am filtering among hundreds of elements stored in Parse. Among those, hundreds will have to be deleted.
Here are my codes:
dispatch_async(dispatch_get_main_queue(), {
var x2 = self.X as [NSArray]
for po2 in CULA {
var arr2 = po2 as! NSArray
if contains(x2, arr2) {
}
else {
PFUser.currentUser()!["myLocation"]?.removeObject(arr2)
} } })
I am using a dispatch_async at the beginning because I want this part to be executed last and separately from the codes above as the filtering occurs. I think the removeObject function is one that blocks activity, however I dont know how to get around that.
Any idea ?
Thanks a lot,
You can use the deleteInBackground method that will delete all of your objects async and not muddle up your main thread or your UI.
You are absolutely dispatching to a queue, but the main queue, which is also hte UI queue. Try putting it in a queue that will be processed by a thread that is not the main UI thread.
Here's a simple snippet that can illestrate how to dispatch for async processing off of the UI thread (and then if UI updates based on the async processing how to queue it for processing on the main UI thread)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 { //take off main ui thread to prevent any blocking
//Do work
dispatch_async(dispatch_get_main_queue(), {//put back on to the main ui thread
}
}
There's a whole world to understand within Grand Central Dispatch, but for your above snippet, simply queue it up to be processed off the main ui thread.

I'm not sure if I'm using NSOperationgQueue's addOperationWithBlock incorrectly

I've been using NSOperationQueue's addOperationWithBlock: to run code in background threads, like so:
self.fetchDataQueue = NSOperationQueue()
for panel in self.panels {
self.fetchDataQueue.addOperationWithBlock() {
() -> Void in
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
//Background code
}
}
}
I'm concerned that I may be doing this wrong. I can't see a way that the fetch queue would be able to know when an operation is done, since there's no completion to call, and I'm not confident it's tracking activity across threads to make sure it's still going.
And the point of using this is so that I don't queue them up in single file and take much longer to process, and so I don't run them all at once and use too much memory.
EDIT: I'm aware that I don't need to be doing dispatch_async, but it's simply an example of some block-based code I may call which may do the same thing, or a web request which may get back after a delay.
Well, your code will run in a background block. If you are using a queue to make sure that one operation only starts when the next one is finished, you may be in trouble: The block that you happen to the NSOperationQueue has finished as soon as it has dispatched the background code to GCD, not when the background code has actually finished which may be much later.

XML Parser is blocking main thread

I have an XML Parser that when it starts it makes the whole app freeze until it is finished, I call the parser using:
xmlParser = [[XMLParser alloc] loadXMLByURL:#"http://abdelelrafa.com/test2.xml"];
What is the best way to have the XML parser work without disrupting the main thread?
I want to know if using another thread is the best option, or using something else.
If you're going to use initWithContentsOfURL you definitely should do your work off of the main thread, and then pick back up on the main thread once you have the init result.
Depending on the size of your document, you may find it better to first get the contents of the URL as NSData using an NSURLConnection, which does its work without blocking the main thread, and then calling [XMLParser initWithData] once you have the data. This has the added benefit that you can actually deal with networking errors separately from XML errors.
Try using GCD to do this operation for you:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
xmlParser = [[XMLParser alloc] loadXMLByURL:#"http://abdelelrafa.com/test2.xml"];
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI
});
});
Enter a dispatch_async on a new queue, in this block do all tour network operations/xml parsing then create another dispatch_async this time on the main queue so you can update UI elements or callback for completion/failure

dispatch_async on main_queue?

I have seen this code snippet:
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomeNetworkStuff];
});
This doesn't look like making much sense to me.
EDIT: To clarify the conditions of my question:
The call to dispatch_async is performed from the main thread.
The sent message doSomeNetworkStuff is the heavy lifting worker task.
... and is not only the UI-updating task.
Dispatch, sure, but using the main queue would just pull the dispatched task back to the ui thread and block it.
Please, am I missing something?
Thanks.
dispatch_async lets your app run tasks on many queues, so you can increase performance.
But everything that interacts with the UI must be run on the main thread.
You can run other tasks that don't relate to the UI outside the main thread to increase performance.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Add some method process in global queue - normal for data processing
dispatch_async(dispatch_get_main_queue(), ^(){
//Add method, task you want perform on mainQueue
//Control UIView, IBOutlet all here
});
//Add some method process in global queue - normal for data processing
});
Swift 3:
DispatchQueue.global(attributes: .qosBackground).async {
print("This is run on the background queue")
DispatchQueue.main.async {
print("This is run on the main queue, after the previous code in outer block")
}
}
when you want to do some Webservicecall or something you dispatch a async call like this below:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//Call your webservice here , your app will not freeze at all
});
Now, suppose you want to update or push a ViewController from your dispatched thread, if you directly push viewcontroller from this, app will or may get crashed,as such UI updates should be done in main thread of app,below is the answer for this then.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
//Call your webservice here , your app will not freeze at all
//To update UIFrom dispatched Thread:
dispatch_async(dispatch_get_main_queue,^{
//Push view controller here
});
});
for detail visit : blackberrymastercracks.blogspot.in
It depends from where this code is being called. Means if its calling from main queue then it doesn't make sense. (Note: it will not cause a crash but it will just add a task in main queue ).
If this code is written in background thread then this is a converging point for the application. Like you are getting data from web service in background thread then wants to update it on UI then you can call it.
-(void) backgroundThreadFunction {
//Some stuff on background thread.
dispatch_async(dispatch_get_main_queue(), ^{
//Wants to update UI or perform any task on main thread.
[self doSomeNetworkStuff];
});
}
You can find more details over apple documentation https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html
or from this answer also https://stackoverflow.com/a/19822753/505735
Do post me if its still unclear. I will write a detailed answer.
You'll usually see that syntax inside of another dispatch_async call that runs on a background thread. This is because all updates to the UI should happen on the main thread, not in the background.
I lost track of this question, but as it still gets traction, I'll post an answer to this (using swift)
Assumptions: I do know that UI work has to be done on the main thread.
//
// We are on the main thread here.
// The following will schedule the closure on the main thread after ALL other
// routines currently scheduled on the main thread are done.
//
DispatchQueue.main.async {
//
// So here we are back on the main thread AFTER all routines on the main
// thread have completed.
//
// If the following call does NOT dispatch onto a background thread
// it will block the UI and it was really bad programming.
//
// Thus, for now and for the benefit of the doubt, let's assume
// `doSomeNetworkStuff()` DOES dispatch to a background thread.
//
// This can only make sense if the the func `doSomeNetworkStuff()`
// relies on results of code paths following this current
// `DispatchQueue.main.async(... we are here ...)`.
//
// If `doSomeNetworkStuff()` does NOT depend on any other code paths:
// Why not directly scheduling it directly on a background thread?
// Which is unnecessary, as as stated above it MUST dispatch on to the
// background anyways.
//
// Moreover, there is few possibility that `doSomeNetworkStuff()` does
// depend on other codepaths, because `self` is already captured by
// the closure.
//
self.doSomeNetworkStuff()
}
Taking all this together IMHO the original code does not make very much sense. It could be replaced with:
// We are on the main thread here
self.doSomeNetworkStuff()
The original async dispatch onto the main thread to then dispatch to background should be wasteful and confusing (obviously).
Unfortunately I am not in the position anymore to try this out with the original code base.
Am I missing an idea here?

How to lazy/async load various elements(data in labels) in a View?

I have a ViewController with various labels. Each of these labels get dynamically populated at the run time based on various regex parsing logic running on an html page. The problem is, each regex match is taking 2-3 seconds and I have 8 such labels so that means i have to wait somewhere around 20-25 seconds before the view shows up!
This is a very very bad user experience. I want that to make this less painful for the user and therefore want to load each label independently as and when they get the data after the regex is processed and not wait for all 8 labels to finish retrieving their regex matches.
Any way this can be achieved in ios 5?
Create a separate function which calculates the values that you need.
(You probably already have this anyway for code readability/maintainability.)
Run this thread in a background thread.
When you are ready to actually set the text, make sure that you do it on the main thread:
Here is an example:
- (void)calculateLabelText {
NSString *label1Text = // However you calculate this...
dispatch_async(dispatch_get_main_queue(), ^(void) {
self.label1.text = label1Text;
});
NSString *label2Text = // However you calculate this...
dispatch_async(dispatch_get_main_queue(), ^(void) {
self.label2.text = label2Text;
});
}
In viewDidLoad, add this:
[self performSelectorInBackground:#selector(calculateLabelText) withObject:nil];
Use Grand Central Dispatch (GCD). It'll handle queues and threading etc for you. There's no need to create a method just for one set of operations that happens once, and regardless, dispatch_async() is faster than performing a selector on a background thread and you get to keep your existing code structure - you just wrap it up in a nice concurrent bundle that won't block the main thread :)
// get a reference to the global concurrent queue (no need to create our own).
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
for each label's regex operation {
dispatch_async(queue, ^{
// your regex here for one
// execute back in the main thread since UIKit only operates in the main thread.
dispatch_async(dispatch_get_main_queue(), ^{
[myLabel setText:<result of operations>];
});
});
}
if you want to use this, you have to pay some attention to get your code separated. one part do data loading work, the other one set data to controls. and you have to make sure that you sqlite (i assume u used this db) cool with multi thread.

Resources