Loop Until Array Has Data - iphone

I need to setup some sort of loop that runs until an array has data in it. A little bit of background information: the application talks to the server and gets some information and populates that information into an array. Only when that information is populated into the array can the view get changed to the next view (because the view is populated with information from the array).
How would I create this loop? I'm currently using an NSTimer but that is not suitable for my needs.
Thanks in advance!

When you say looping until I assume you really mean wait until.
First of if this waiting is to be done on the main thread just forget about it, never block the main thread.
Instead of a loop you probably want to use a lock, and wait for the condition. This requires a shared lock between the code where you wait for the array to populate, and the code where you populate the array.
First create a shared condition lock like this:
typedef enum {
MYConditionStateNoObjects,
MYConditionStateHaveObjects
} MYConditionState;
...
sharedArray = [[NSMutableArray alloc] init];
sharedLock = [[NSConditionLock alloc] initWithCondition:MYConditionStateNoObjects];
Your method that populates the array should then do:
[sharedLock lockWhenCondition:MYConditionStateNoObjects];
// Your stuff to get the objects to add here.
[sharedArray addObjectsFromArray:theObjectsToAdd];
[sharedLock unlockWithCondition:MYConditionStateHaveObjects];
And the receiver that should wait until the array has objects do this:
[sharedLock lockWhenCondition:MYConditionStateHaveObjects];
// ... Do something with the objects you got here
[sharedArray removeAllObjects];
[sharedLock unlockWithCondition:MYConditionStateNoObjects];

You can try using the following libraries: http://allseeing-i.com/ASIHTTPRequest/How-to-use and look for the asynchronous part
Asynchronous means that you won't block the main thread and wait for a response to come back.

If I got the idea, you need to handle the moment, when data from server was added to the array. So why you don't want to use KVO functionality? It will allow you to add observer which will listen for array content change.

Related

Is it possible to make a method operate sequentially?

I have only included the code relevant to this label within the program.
In my viewDidLoad method I have
[startLabel setHidden:NO];
startLabel.text = #"Touch to Begin";
In the touchesBegan method I then have
startLabel.text = #"Loading . .";
[self fillArrays];
Then in the fill Arrays method I fill the arrays and then hide the label -
self.myArray = [NSArray arrayWithObjects:
[UIImage imageNamed:#"Frame 1.png"], . .etc etc etc . . . nil]];
[startLabel setHidden:YES];
However, the text is not updated before the Array is loaded. Resulting in the "Loading . . " text never appearing. As it seems to be implemented after the Array is filled.
At the same time the setHidden bool is set to YES, thus one never sees the label.
I wish for the startLabel to update before the method begins to fill the Array as this takes some time. i.e. for the method to Operate sequentially.
Is this possible?
Thank You
You don't need multithreading, that's overcomplicating things. The problem is that until your code returns, UIKit isn't going to update the user interface, so you're scheduling the user interface update, loading the arrays, then returning control to UIKit, which then performs the user interface update. What you need to do is schedule the user interface update, return control to UIKit and then load the arrays in the next iteration of the run loop. To do that, you can use performSelector:withObject:afterDelay: with a zero delay, which executes the method call in the next run loop iteration. This should do the trick:
startLabel.text = #"Loading . .";
[self performSelector:#selector(fillArrays) withObject:nil afterDelay:0];
You need to load the arrays on a different thread to that of your GUI updates.
See this article: http://evilrockhopper.com/2010/01/iphone-development-keeping-the-ui-responsive-and-a-background-thread-pattern/
The function you want is performSelectorInBackground
That way your UI updates and your Background work can be done at the same time.
You can run another function which updates the label on the main thread as well in a similar way:
performSelectorOnMainThread
That way you load arrays in the background, and you update your UI on the main thread (which is good because I Think the UIKit is not thread safe.

removeAllObjects not removing if action is fast

I am using a search bar in my app and display some results below from an ext API.
The contents first get stored in an array "xyz" and each time the user types in the search bar, I removeAllObjects and reload the table.
The results are correct if the user types slow i.e. [xyz removeAllObjects] works fine...However if the user types very fast, [xyz removeAllObjects] does not seem to have any effect and duplicate items get appended to the array..
I am not sure how to fix this. Please help me. Thank you.
removeAllObjects is an entirely serial operation; that method doesn't return until the array is empty.
Therefore, there must be a thread in play and you are quite likely accessing a mutable array from multiple threads. Mutable arrays aren't thread safe. Fix the exclusivity and you'll fix your problem.
The easiest way is to separate the array being displayed from the array being computed. As soon as the computation is done, move the computed array to the display array and never mutate it again.
Why not create a new NSArray, point the results at that, and then release the old array. That way having duplicates will be impossible. Something like:
NSArray *newArray = [someObject newSearchResults];
NSArray *oldArray = xyz;
xyz = [newArray retain];
[oldArray release];

Perform Selector In Background and get the return string

I am trying to perform a selector which returns an NSString in the background thread, and the NSString returned will depend on the input object albumlink.
I am performing it in the background, as it takes a while to shorten the URL.
I would really appreciate if you could tell me how I could get the return string.
My code to perform that selector is:
[self performSelectorInBackground:#selector(shortenURL:) withObject:albumlink];
You can write another method in your class (let's call it -handleResponse:(NSString *)response), and then from the backgrounded process you can call:
[self performSelectorOnMainThread:#selector(handleResponse:) withObject:#"My response string" waitUntilDone:NO];
You can't get a function's return value outside of the thread it runs in. The whole point of doing something in a background thread is that it's taken out of the normal flow for the main thread, so there's no place for it to return to.. The most sensible approach is to create a block that's performed in the background (either through NSOperation or GCD directly) which updates either updates the value on the main thread — if you need to store the value afterward — or which just does whatever you were going to do with the value if it was only going to be used in one branch of code.

UITableView and NXXMLParser ... Calling Hierarchy

I am stuck in a strange situation , i am getting data from the website using XML files and i am filling an Array (NSMutableArray Type) that i later use to display the data on Table View. The problem is that functions related to UITableView are called earlier and at that time the Array is not filled, this cause the program to crash. When this function is executed arrayData is empty and count functions returns nothing. Is there any way that i call NSXMLParser functions earlier than the UITableView functions.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrayData count];
}
Thanks,
Taimur
The array would return 0 if it existed but without containing any objects - so the app shouldn't crash. This means your array has not been initialized yet. You have propably added a pointer to your array as an instance variable and maybe as property, but you still need to create the actual object towards which that pointer should point.
So, if we're dealing with a property of a viewcontroller subclass here, add something like this to your viewDidLoad method:
NSMutableArray *newArray = [[NSMutableArray alloc] init];
self.arrayData = newArray;
[newArray release];
Your situation is not strange at all - it is extremely common when developing apps with asynchronous data loading requirements.
NSXMLParser is a SAX (event-driven) parser - it will parse data when the data is available. It is up to you when you choose to display your table, but obviously if you try to display it before the XML data is available then you will have to take steps to prevent a crash, or at the very least a bad user experience. Typically you would display an activity spinner or a "loading data..." message until the data is ready, and in a background thread load the XML. Once loaded, the BG thread should signal to the UI thread that the data is ready, and perhaps invoke reloadData on the table to load the data.

Core Data - How to check if a managed object's properties have been deallocated?

I've created a program that uses core data and it works beautifully.
I've since attempted to move all my core data methods calls and fetch routines into a class that is self contained. My main program then instantiates that class and makes some basic method calls into that class, and the class then does all the core data stuff behind the scenes. What I'm running into, is that sometimes I'll find that when I grab a managed object from the context, I'll have a valid object, but its properties have been deallocated, and I'll cause a crash. I've played with the zombies and looked for memory leaks, and what I have gathered is it seems that the run loop is probably responsible for deallocating the memory, but I'm not sure.
Is there a way to determine if that memory has been deallocated and force the core data to get it back if I need to access it? My managedObjectContext never gets deallocated, and the fetchedResultsController never does, either.
I thought maybe I needed to use the [managedObjectContext refreshObject:mergeData:] method, or the [managedObjectContext setRetainsRegisteredObjects:] method. Although, I'm under the impression that last one may not be the best bet since it will be more memory intensive (from what I understand).
These errors only popped up when I moved the core data calls into another class file, and they are random when they show up.
Any insight would be appreciated.
-Ryan
Sounds to me like you are not retaining objects you want to keep hanging around. If you are doing something like this:
NSArray *array = [moc executeFetchRequest:request error:&error];
you do not own the returned array and it will most likely disappear when the current autorelease pool is drained. This will occur when the run loop finishes processing the current event.
All this is speculation. If you want a proper answer, you need to post your code.
It's hard to know what the problem is based on your description, but you might want to look at the Core Data memory management guide. You shouldn't have to worry about memory management for managed objects and their entities (they're fetched and faulted automatically). When you talk about "properties," do you mean custom properties backed by ivars? If so, these should be released in didTurnIntoFault and allocd as needed (probably in the accessor).
I was struggling with a similar issue. I'm using a managed object class and want to set its properties dependent on user input. But the sometimes the properties and sometimes the whole managed object were deallocated.
After reading the Apple documentation http://developer.apple.com/library/IOs/#documentation/Cocoa/Conceptual/CoreData/Articles/cdMemory.html the chapter "The Role of the Managed Object Context" I learned that managed objects are released each run loop completes.
And there is the golden advice to set
[myMangedObjectContext setRetainsRegisteredObjects:YES];
(I had to set it in the init method (initWithNibName for me) of my view controller.)
You should also regard to retain only the objects you need to as explained in the documentation. But read it yourself.
If I'm not right please correct me.
I also made a class that handles all my CoreData fetching and stuff. I ran into a couple of gotcha's, so here are some tips. (If I am making any memory management errors in these examples, please let me know.)
Two things:
1) Made a "fetchFiredObject" method in the CoreData handler class. So when I want to get a managedObject that has all its variables and is a "fully feathered bird" so to speak, instead of doing:
aManagedObject *myManagedObject = [myCoreDataHandler.managedObjectStorageArray objectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
instead I do:
aManagedObject *myManagedObject = [myCoreDataHandler fetchFiredObjectAtIndex:1];
int x = myManagedObject.someVariable.intValue;
And in myCoreDataHandler's fetchFiredObjectAtIndex:i method, we're going into the array, finding the object key at index i, then doing a fetchRequest for that object key, and returning the freshly-fetched managedObject so that it won't have been faulted or deallocated, etc. :D
2) When I create a new child viewController, I populate its "myCoreDataHandler" value from the parent upon creation. However, this happens on a subsequent line of code after the line of code that creates the new viewController. Therefore, any code in the child's viewDidLoad that tries to use myCoreDataHandler's methods will return empty objects because viewDidLoad completes before the parent's next line of code where it sets the values of globals in the child object. So make sure you are not accessing your "Core Data handling object" from within viewDidLoad or anything local methods called by viewDidLoad! Instead call them from the parent after creating the new viewController.