ios stop 2 threads from using a method at the same time - objective-c

We had a bug, and it destroys the looks of our UI, some of the UI elements overlap, or has been added to the subview twice. the bug is hardly reproduced so its hard to fix it. Now I thought of the reason, and probably the method that changes the UI are being called twice at the same time. And I was correct, I tried to create the bug programatically.
We have a bug which is caused by a method being accessed by different threads at the same time. To emulate this problem, and better understand it. see codes posted below.
When I do this, updatePresence Method call, my program works perfectly
ViewController.m
-(void)loadConversationScreen{
[conversationController updatePresence];
}
But when I do this, something goes wrong with my program
ViewController.m
-(void)loadConversationScreen{
[conversationController performSelectorInBackground:#selector(updatePresence) withObject:nil];
[conversationController updatePresence];
}
This is because the method is being accessed at the same time and and the instance of my UIView is being accessed/changed also at the same time.
How do I PROPERLY stop 2 threads from using a method at the same time?
How do I properly handle it in IOS(if there is no proper way, what are the work arounds), are there built in locks or somekind?
My app should support ios 4.0 and up
Advance thanks to all for your help.

The best thread lock for you is #sycnhronized(object) {}. This means only one thread can enter the code at a time. The object passed in is used to perform the lock; only one thread can enter a block protected by a particular object's synchronized at a time. The others will wait. This can be any Objective-C object, even a NSString.
Typically, you'd use whatever object you're trying to protect from multiple threads. You probably want #synchronized(self) {}:
-(void)updateVariables {
#synchronized(self) {
_foo = 1;
_bar = 2;
}
}
#sycnhronized is re-entrant in the sense that the same thread can call #sycnhronized as deeply as it wants, for instance:
- (void)a {
#synchronized(self) {
// entered "immediately" if called from b, where the #synchronized has
// already been called
_foo = _foo + 1;
}
}
- (void)b {
#synchronized(self) {
[self a];
}
}
For posterity and because I already typed it before reading your clarification, if you really cared only about updating the UI, you'd want to force your call over to the main thread instead like this:
- (void)someTask {
dispatch_async( dispatch_get_main_queue(), ^{
[self updateUI];
});
}
- (void)updateUI {
NSAssert( [NSThread isMainThread], #"called from non-main thread" );
// do UI updates here
}

As warrenm said you shouldn't update your UIView from a different thread than the Main thread (UI thread). Still, you asked if there is any workaround for what's going on. To be honest, you should try to, instead of blocking the access of the second thread to your method, understand why the methods is called twice. This is more a logical problem than anything else and you should try to fix that, instead of trying a shortcut.

Related

Run C function in background in Objective-C

I want to call a C function in a Objective-C app. The function contains an endless loop. So I need to run this C function in background.
Here's my C function:
int go(){
for(;;){
//...
}
return 0;
}
And the call:
[self performSelectorInBackground:go() withObject:nil];
The function go() is called but it's not running in background (and the app stop working...).
Even in the background you probably should run something in an endless loop. However it is possible.
[self performSelectorInBackground:<selector> withObject:<Object>];
That is a nice convenience method to just throw a method to the background thread. But you also have access to Grand Central Dispatch that would let you put blocks of code into a background thread as well. You could even give it a private queue so it wouldn't block your background queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// Your code
go();
});
Hmm, there may be an easier way, but...
- (int)doGo {
return go();
}
Then...
[self performSelectorInBackground:#selector(doGo) withObject:nil];
So, this answer really just highlights what I believe is the most fundamental problem with your provided code, but you should certainly see Ryan's answer and use GCD. performSelectorInBackground: really isn't all that great.

dispatch_get_main_queue() in main thread

I have method which makes UI changes in some cases.
For example:
-(void) myMethod {
if(someExpressionIsTrue) {
// make some UI changes
// ...
// show actionSheet for example
}
}
Sometimes myMethod is called from the mainThread sometimes from some other thread.
Thats is why I want these UI changes to be performed surely in the mainThread.
I changed needed part of myMethod this way:
if(someExpressionIsTrue) {
dispatch_async(dispatch_get_main_queue(), ^{
// make some UI changes
// ...
// show actionSheet for example
});
}
So the questions:
Is it safe and good solution to call dispatch_async(dispatch_get_main_queue() in main thread? Does it influence on performance?
Can this problem be solved in the other better way? I know that I can check if it is a main thread using [NSThread isMainThread] method and call dispatch_async only in case of other thread, but it will make me create one more method or block with these UI updates.
There isn't a problem with adding an asynchronous block on the main queue from within the main queue, all it does is run the method later on in the run loop.
What you definitely don't want to do is to call dispatch_sync adding a block to the main queue from within the main queue as you'll end up locking yourself.
Don't worry if you are calling dispatch_async in main thread or not. iOS will put the block in a queue and execute the block in main thread.

App stops inconsistently at a call to dispatch_sync() [duplicate]

Im using XMPPFramework and in it's code there's a method like this:
- (NSDictionary *)occupants
{
if (dispatch_get_current_queue() == moduleQueue)
{
return occupants;
}
else
{
__block NSDictionary *result;
dispatch_sync(moduleQueue, ^{//IT BLOCKS HERE, WITHOUT MESSAGE
result = [occupants copy];
});
return [result autorelease];
}
}
[EDIT]
It blocks inconsistently, not always, since the app is not doing anything I pause it and I see the thread has stopped there, and it never continues to execute.
What is wrong? Any ideas?
Thanks
The behavior you explain perfectly matches with the one that appears when you try to send perform an operation on main thread via GCD while being on the main thread. So you should check if moduleQueue is the main queue, then this is it. Try checking if it is the main queue if it is, skip the dispatch_sync block.
Blocks sometimes need to retain variables to ensure they are available when they execute. If you use a local variable inside a block, you should initialise it to zero where you declare it outside the block.

App blocks while dipatching a queue

Im using XMPPFramework and in it's code there's a method like this:
- (NSDictionary *)occupants
{
if (dispatch_get_current_queue() == moduleQueue)
{
return occupants;
}
else
{
__block NSDictionary *result;
dispatch_sync(moduleQueue, ^{//IT BLOCKS HERE, WITHOUT MESSAGE
result = [occupants copy];
});
return [result autorelease];
}
}
[EDIT]
It blocks inconsistently, not always, since the app is not doing anything I pause it and I see the thread has stopped there, and it never continues to execute.
What is wrong? Any ideas?
Thanks
The behavior you explain perfectly matches with the one that appears when you try to send perform an operation on main thread via GCD while being on the main thread. So you should check if moduleQueue is the main queue, then this is it. Try checking if it is the main queue if it is, skip the dispatch_sync block.
Blocks sometimes need to retain variables to ensure they are available when they execute. If you use a local variable inside a block, you should initialise it to zero where you declare it outside the block.

Why can't my singleton class return a value that will stay in scope

Stick with me. I'm visually impaired, have never used this site before, and will probably not post this in precisely the format that you are all used to. I apologize for any unintentional faux pas's herein.
Using Objective-C in an iOS project…
I have a singleton class, set up in what appears to be the usual way for Objective-C. It is, in the main, a series of methods which accept NSString values, interprets them, and return something else. In the code below, I'm simplifying things to the barest minimum, to emphasize the problem I am having.
From the singleton class:
- (NSUInteger) assignControlState:(NSString *)state {
// excerpted for clarity...
return UIControlStateNormal; // an example of what might be returned
}
Now, an instance of another class tries to use this method like so:
- (void) buttonSetup:(UIButton*)button {
[button setTitle:#"something" forState:[[SingletonClass accessToInstance] assignControlState:#"normal"]];
}
This code actually works. HOwever, when the system goes to draw the UI which includes the button whose title was set in this way, an EXC_BAD_ACCESS error occurs.
If the assignControlState method is moved into the same class as the buttonSetup method, no error is generated.
I'm guessing this is something about Apple's memory management that I'm not fully understanding, and how things go in and out of scope, but for the life of me, I can't figure out where I'm going wrong.
HOpe someone can help. Thanks.
The problem is in your accessToInstance method. I'll bet you are under-retaining. The implementation should be more like this:
static SingletonClass *sSingletonClass = nil;
#implementation
+ (id)accessToInstance {
if (sSingletonClass == nil) {
sSingletonClass = [[[self class] alloc] init];
}
return sSingletonClass;
}
#end
Now, if your program is following normal memory management rules, the singleton will stay around. You can check by writing:
- (void)dealloc {
[super dealloc]; // <-- set a breakpoint here.
}
If the debugger ever stops at this breakpoint, you know something in your program has over-released the singleton.
You know that bit you excerpted for clarity? I think you need to show us what it is because there's probably an over release in it somewhere.
Specifically, I think you release an autoreleased object. If you do that and don't use the object again, everything will carry on normally until the autorelease pool gets drained. The autorelease pool gets drained automatically at the end of the event at about the same time as the drawing normally occurs.
That would also explain the delayed crash following the NSLogs.