Is it possible to make a method operate sequentially? - iphone

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.

Related

Multithreading with NSThread

I'm newbie with this so forgive me with any mistakes...
My situation:
- (id)initWith... //Some arguments
There's an initialization method that returns an object. It does a lot of work to set its instance variables with the values of the arguments. To maximize performance I divide the job in two threads. One thread sets a set of related variables and the other thread another bunch of them.
- (id)initWith:arguments {
self = [super init];
if (self) {
[NSThread detachNewThreadSelector:#selector(setFirstSetOfVariables:) toTarget:self withObject:argObject];
[self setSecondSetOfVariables:arguments];
//Check if the thread finished its work and return the value
return self;
}
To make it easy think both sets of vars that the method has to set don't have any relationship. Then my question is: how do I check if the first thread finished? I could create a BOOL var but I'd have to create a loop to check. I could also call a method to say it's ready. But as I don't know a lot of it, I don't know wether a method invoked inside a thread would be run in the main thread or in the other. Sorry. Thank you for any info.
You can do it this way to simplify the whole thing
ComplicatedObject *myComplicatedObject = [ComplicatedObject alloc] init;
[myComplicatedObject setLongTimeTakingVariables];
and in the ComplicatedObject create a method like
-(void)setLongTimeTakingVariables{
dispatch_async(dispatch_get_global_queue(),^{ All of your code can go here. Infact you need not split it into two sections, because it will happen in the background and your userinterface will not get affected }
But if you want to split then you can do
dispatch_async(dispatch_get_global_queue((DISPATCH_QUEUE_PRIORITY_LOW, 0)),^{
some work here
}
dispatch_async(dispatch_get_global_queue((DISPATCH_QUEUE_PRIORITY_LOW, 0)),'{
some other work here
}
Read the Concurrency Programming Guide and every thing is explained very clearly.

Loop Until Array Has Data

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.

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 performance issue

I have a UITableView which gets data from a server and updates in every 1 second(using performSelectorOnMainThread). Since this blocks main thread sometimes its not easy to scroll the table and its painfull for the user. Also i cant reduce my refresh interval also.
What are the possible solutions for this problem?
I would only refresh the visible cells as the data changes, and the others as they appear so it will be less consuming than updating the hole UITablaView
you can get the visible cells using ( from UITableView):
- (NSArray *)visibleCells
and you can update the remaining cells as they appear using UITableViewDelegate Protocol
– tableView:willDisplayCell:forRowAtIndexPath:
and i think this should make it a bit faster.
Hold your data in a mutable array or similar structure then asyncronously update that array with an NSURLConnection. You can call reloadData on the tableview to redraw the table when the NSURLConnection is done.
You would probably just call the NSUrlConnection from an NSTimer at whatever interval you prefer.
instead of calling performSelectorOnMainThread function of NSThread call
detachNewThreadSelector function. In this way your thread will not block the main thread
[NSThread detachNewThreadSelector:#selector(aMethod:) toTarget:[MyObject class] withObject:nil];
in toTarget: method you can write self instead of [MyObject class]
also in Implementation selector write #synchronize(self) for eg.
-(void)aMethod
{
#synchronize(self) {
//write your whole code here
}
}
I have done the same thing in my application its work perfectly
Use GCD with queues (serial or global queues). This is the apple recommended way now.
dispatch_async(dispatch_get_main_queue(), ^{
//do UI updates
});

How can I pause/restart a loop in objective-c

Would like to execute some code in a loop, but I want to pause it while a uiscrollview is scrolling.
I've created a BOOL named isScrolling that is set to "YES" in the scrollViewDidScroll method and is set to "NO" in the scrollViewDidEndDecelerating method.
I'd like to put the loop in the scrollViewDidEndDecelerating method, but have it paused when isScrolling == YES and then restart it when isScrolling == NO.
I am looping through an array, so I'd like the loop to pick up where it left off in the array.
For example, here's a simple loop that continually counts higher by increments of 1 that I placed in the viewDidAppear method:
for (int i = 1; i > 0; i++) {
NSLog(#"i = %d", i);
if (isScrolling == YES) {
NSLog(#"break");
break;
}
}
But, all scrolling is disabled while this loop is running for some reason so I can't cancel it.
How can I do this?
Thanks!
You say this loop is within viewDidLoad, which means it's being executed by the main application thread (and thus the "UI thread). If that's the case, there's nothing you can do. Your UI isn't going to be doing anything at all while that loop is running because it's the same thread executing the loop.
Without knowing more about what it is you're actually doing in that loop, it's hard to suggest what you could do to offload that work into a separate thread.
I'm not entirely sure what you're aiming for in a use case for this - I'm guessing you have something happening in a loop that's slowing down your UIScrollView scrolling and making it stutter a bit more than you'd like.
I'm going to guess that the answer is make the background task that you're working with asynchronous so that it's not taking up so much CPU resource in general. If you really want to bind into reacting if the scroll view is moving, then you want the UIScrollView Delegate methods to be your primary trigger points. The ones that stand out as potential uses:
– scrollViewWillBeginDragging:
– scrollViewDidEndDragging:willDecelerate:
– scrollViewDidEndScrollingAnimation:
...
Don't invoke the looping in viewDidLoad or you'll block the main UI interaction thread. Instead trigger off a background process using classic threading or better yet NSOperationQueue to do whatever looping/background thing you want done. If you have that queue reference in the view controller, you could also hook into that to pause or cancel those operations when a person decides to scroll using the delegate methods above.