Trouble with Cocoa Touch Threading - objective-c

I'm writing a multi threaded application for iOS.
I am new to Objective-C, so I haven't played around with threads in iPhone before.
Normally when using Java, I create a thread, and send "self" as object to thread. And from the thread I can therefor call the main thread.
How is this done in Objective C?
How can I call the main thread from a thread? I have been trying with NSNotificationCenter, but I get a sigbart error :/
This is how the thread is started:
NSArray *extraParams = [NSArray arrayWithObjects:savedUserName, serverInfo, nil]; // Parameters to pass to thread object
NSThread *myThread = [[NSThread alloc] initWithTarget:statusGetter // New thread with statusGetter
selector:#selector(getStatusFromServer:) // run method in statusGetter
object:extraParams]; // parameters passed as arraylist
[myThread start]; // Thread started
activityContainerView.hidden = NO;
[activityIndicator startAnimating];
Any help would be great!

you accomplish this by adding a message to the main thread's run loop.
Foundation provides some conveniences for this, notably -[NSObject performSelectorOnMainThread:withObject:waitUntilDone:] and NSInvocation.
using the former, you can simply write something like:
[self performSelectorOnMainThread:#selector(updateUI) withObject:nil waitUntilDone:NO]
a notification may be dispatched from a secondary thread (often the calling thread).

You can either use performSelectorOnMainThread:withObject:waitUntilDone: or, if you're targeting iOS 4 and later, Grand Central Dispatch, which doesn't require you to implement a method just to synchronize with the main thread:
dispatch_async(dispatch_get_main_queue(), ^ {
// Do stuff on the main thread here...
});
This often makes your code easier to read.

Though this is not a direct answer to your question I would highly recommend you take a look at Grand Central Dispatch. It generally gives better performance than trying to use threads directly.
As Justin pointed out, you can always perform a function in the main thread by calling performSelectorOnMainThread, if you really needed too.

Related

AFNetworking - Why does it spawn a network request thread?

I'm trying to understand Operations and Threads better, and looked to AFNetworking's AFURLConnectionOperation subclass for example, real-world, source code.
My current understanding is when instances of NSOperation are added to an operation queue, the queue, among other things, manages the thread responsible for executing the operation. In Apple's documentation of NSOperation it points out that even if subclasses return YES for -isConcurrent the operation will always be started on a separate thread (as of 10.6).
Based on Apple's strong language throughout the Thread Programming Guide and Concurrency Programming Guide, it seems like managing a thread is best left up to the internal implementation of NSOperationQueue.
However, AFNetworking's AFURLConnectionOperation subclass spawns a new NSThread, and the execution of the operation's -main method is pushed off onto this network request thread. Why? Why is this network request thread necessary? Is this a defensive programming technique because the library is designed to be used by a wide audience? Is it just less hassle for consumers of the library to debug? Is there a (subtle) performance benefit to having all networking activity on a dedicated thread?
(Added Jan 26th)
In a blog post by Dave Dribin, he illustrates how to move an operation back onto the main thread using the specific example of NSURLConnection.
My curiosity comes from the following section in Apple's Thread Programming Guide:
Keep Your Threads Reasonably Busy.
If you decide to create and
manage threads manually, remember that threads consume precious system
resources. You should do your best to make sure that any tasks you
assign to threads are reasonably long-lived and productive. At the
same time, you should not be afraid to terminate threads that are
spending most of their time idle. Threads use a nontrivial amount of
memory, some of it wired, so releasing an idle thread not only helps
reduce your application’s memory footprint, it also frees up more
physical memory for other system processes to use.
It seems to me that AFNetworking's network request thread isn't being "kept reasonably busy;" it's running an infinite while-loop for handling networking I/O. But, see, that's the point of this questions - I don't know and I am only guessing.
Any insight or deconstruction of AFURLConnectionOperation with specific regards to operations, threads (run loops?), and / or GCD would be highly beneficial to filling in the gaps of my understanding.
Its an interesting question and the answer is all about the semantics of how NSOperation and NSURLConnection interact and work together.
An NSURLConnection is itself an asynchronous task. It all happens in the background and calls its delegate periodically with the results. When you start an NSURLConnection it schedules the delegate callbacks using the runloop it is scheduled on, so a runloop must always be running on the thread you are executing an NSURLConnection on.
Therefore the method -start on our AFURLConnectionOperation will always have to return before the operation finishes so it can receive the callbacks. This requires that AFURLConnectionOperation be an asynchronous operation.
from: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/index.html
The value of property is YES for operations that run asynchronously with respect to the current thread or NO for operations that run synchronously on the current thread. The default value of this property is NO.
But AFURLConnectionOperation overrides this method and returns YES as we would expect. Then we see from the class description:
When you call the start method of an asynchronous operation, that method may return before the corresponding task is completed. An asynchronous operation object is responsible for scheduling its task on a separate thread. The operation could do that by starting a new thread directly, by calling an asynchronous method, or by submitting a block to a dispatch queue for execution. It does not actually matter if the operation is ongoing when control returns to the caller, only that it could be ongoing.
AFNetworking creates a single network thread using a class method that it schedules all the NSURLConnection objects (and their resulting delegate callbacks) on. Here is that code from AFURLConnectionOperation
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
#autoreleasepool {
[[NSThread currentThread] setName:#"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:#selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
Here is code from AFURLConnectionOperation showing them scheduling the NSURLConnection on the runloop of the AFNetwokring thread in all runloop modes
- (void)start {
[self.lock lock];
if ([self isCancelled]) {
[self performSelector:#selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
} else if ([self isReady]) {
self.state = AFOperationExecutingState;
[self performSelector:#selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
[self.lock unlock];
}
- (void)operationDidStart {
[self.lock lock];
if (![self isCancelled]) {
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
[self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
[self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
}
//...
}
[self.lock unlock];
}
here [NSRunloop currentRunloop] retrieves the runloop on the AFNetworking thread instead of the mainRunloop as the -operationDidStart method is called from that thread. As a bonus we get to run the outputStream on the background thread's runloop as well.
Now AFURLConnectionOperation waits for the NSURLConnection callbacks and updates its own NSOperation state variables (cancelled, finished, executing) itself as the network request progresses. The AFNetworking thread spins its runloop repeatedly so that as NSURLConnections from potentially many AFURLConnectionOperations schedule their callbacks they are called and the AFURLConnectionOperation objects can react to them.
If you always plan to use queues to execute your operations, it is simpler to define them as synchronous. If you execute operations manually, though, you might want to define your operation objects as asynchronous. Defining an asynchronous operation requires more work, because you have to monitor the ongoing state of your task and report changes in that state using KVO notifications. But defining asynchronous operations is useful in cases where you want to ensure that a manually executed operation does not block the calling thread.
Also note that you can also use an NSOperation without a NSOperationQueue by calling -start and observing it until -isFinished returns YES. If AFURLConnectionOperation was implemented as a synchronous operation and blocked the current thread waiting for NSURLConnection to finish it would never actually finish as NSURLConnection would schedule its callbacks on the current runloop, which wouldn't be running as we would be blocking it. Therefore to support this valid scenario of using NSOperation we have to make the AFURLConnectionOperation asynchronous.
Answers to Questions
Yes, AFNetworking creates one thread which it uses to schedule all connections. Thread creation is expensive. (this is partly why GCD was created. GCD keeps a pool of threads running for you and dispatches blocks on the different threads as needed without having to create, destroy and manage threads yourself)
The processing is not done on the background AFNetworking thread. AFNetworking uses the completionBlock property of NSOperation to do its processing which is executed when finished is set to YES.
The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore, you should not use this block to do any work that requires a very specific execution context. Instead, you should shunt that work to your application’s main thread or to the specific thread that is capable of doing it. For example, if you have a custom thread for coordinating the completion of the operation, you could use the completion block to ping that thread.
the post processing of HTTP connections is handled in AFHTTPRequestOperation. This class creates a dispatch queue specifically for transforming response objects in the background and shunts the work off onto that queue. see here
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
self.completionBlock = ^{
//...
dispatch_async(http_request_operation_processing_queue(), ^{
//...
I guess this begs the question could they have written AFURLConnectionOperation to not make a thread. I think the answer is yes as there is this API
- (void)setDelegateQueue:(NSOperationQueue*) queue NS_AVAILABLE(10_7, 5_0);
Which is meant to schedule your delegate callbacks on a specific operation queue as opposed to using the runloop. But as we're looking at the legacy part of AFNetworking and that API was only available in iOS 5 and OS X 10.7. Looking at the blame view on Github for AFURLRequestOperation we can see that mattt actually wrote the +networkRequestThread method coincidentally on the actual day the iPhone 4s and iOS 5 were announced back in 2011! As such we can reason that the thread exists because at the time it was written we can see that making a thread and scheduling your connections on it was the only way to receive callbacks from NSURLConnection in the background while running in an asynchronous NSOperation subclass.
the thread is created using the dispatch_once function. (see the extra code snipped i added as you suggested) This function ensures that the code enclosed in the block it runs will be run only once in the lifetime of the application. The AFNetworking thread is created when it is needed and then persists for the lifetime of the application
When i wrote NSURLConnectionOperation i meant AFURLConnectionOperation. I corrected that thanks for mentioning it :)

Leak reported by profiler when using NSThread. The project is compiled with ARC for Objective C and iOS

This is the way I am trying to manage my thread
-(void)ExecuteThread {
#autoreleasepool {
bInsideDifferentThread = YES;
//some code...
bInsideDifferentThread = NO;
}
[NSThread exit];
}
-(void)ThreadCallerEvent {
NSThread *myThread = [[NSThread alloc] initWithTarget:self selector:#selector(ExecuteThread) object:nil];
if (!bInsideThread)
[myThread start];
else
{
[myThread cancel];
}
}
I do it this way becuase I don't want the thread to be started until it has finished working. The problem is that this is generating leaks from a non released memory allocated at [NSThread init]
Any ideas of how to fix this problem?
I ran a fragment similar to yours and wasn't able to detect leaks; but the context is almost certainly different. I'm really not sure what ARC is doing with myThread in your example when it goes out of scope. A typical pattern for using NSThread would be:
[NSThread detachNewThreadSelector:#selector(executeThread)
toTarget:self
withObject:nil];
in which case you're not responsible for dealing directly with the thread you are detaching. (Note: I changed your method name to use camel case which is the preferred method and variable naming convention in Cocoa.)
All of the above said, managing threads are no longer the preferred way of achieving concurrent design. It's perfectly acceptable; but Apple is encouraging developers to migrate to GCD. Far better to think in terms of units of work that need to be performed concurrently.
Without understanding your needs more deeply in this case, it's hard to know what advantages, if any, working directly with threads might offer you; but I would consider looking at concurrent queues/GCD more closely. Perhaps you could simply use something like:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do your background work
});
and achieve both a clearer design for concurrency and avoid whatever memory management issues you are now seeing.

Block version of performSelectorOnMainThread:withObject:waitUntilDone:

Is there a way that I can execute a block rather than a selector corresponding to this and similar methods?
I have observers that may receive events that aren't generated on the main thread. I want the action to be performed on the main thread if it is primarily UI oriented. Right now, I need to write two methods to do this, where one is the event observer, and the second is the code that needs to be executed on the main thread.
I would like to encapsulate this all into one method, if I could.
GCD should do the trick:
dispatch_sync(dispatch_get_main_queue(), ^{
// Do stuff here
});
Or dispatch_async if you were planning on waitUntilDone:NO. The main queue is guaranteed to be running on the main thread, so it is safe for UI operations.
The preferable technology for block-supporting multhreading actions is called Grand Central Dispatch. You can find some sample code on Wikipedia and in the Grand Central Dispatch (GCD) Reference
dispatch_async(backgroundQueue, ^{
//background tasks
dispatch_async(dispatch_get_main_queue(), ^{
//tasks on main thread
});
});

sizeWithFont in MultiThread Crash!

sizeWithFont crashed in multithread,this is the debug info:
1 0x00a0df8e in icu::RuleBasedBreakIterator::handleNext
2 0x00a0daff in icu::RuleBasedBreakIterator::next
3 0x00a0d174 in icu::RuleBasedBreakIterator::following
4 0x35879719 in WebCore::nextBreakablePosition
5 0x3587842a in -[NSString(WebStringDrawing) _web_drawInRect:withFont:ellipsis:alignment:lineSpacing:includeEmoji:measureOnly:]
6 0x35877da3 in -[NSString(WebStringDrawing) _web_sizeInRect:withFont:ellipsis:lineSpacing:]
7 0x3090d238 in -[NSString(UIStringDrawing) sizeWithFont:constrainedToSize:lineBreakMode:lineSpacing:]
8 0x3090cee3 in -[NSString(UIStringDrawing) sizeWithFont:constrainedToSize:lineBreakMode:]
now I solve the error by using a NSLock object,before using this function I will lock this object,and after that unlock it
but I think there must be a more better solution!
and I found this error only appeared when the NSString object for this function on both two threads are multi-lines text
As a rule, you should not invoke UIKit methods [1] from a separate thread. It does not matter if you are taking locks, this is a non-starter.
When you are using multi-threaded applications, you need to make sure that any code that touches any UIKit objects executes on the main thread. This is achieved by using the performSelectorOnMainThread:withObject:waitUntilDone: method which invokes the given selector on the main thread:
http://developer.apple.com/iphone/library/documentation/cocoa/reference/foundation/Classes/NSObject_Class/Reference/Reference.html#//apple_ref/occ/instm/NSObject/performSelectorOnMainThread:withObject:waitUntilDone:
Or in MonoTouch: foo.InvokeOnMainThread (delegate { your_code_here });
[1] With iOS 4.0 the rule is relaxed for a handful of APIs.
Formatting, please.
"Solving" a multi-threaded problem by placing random locks around objects is never the right answer. Not ever. Multi-threading requires systemic design of your application.
If a lock does "fix" the problem, showing what you locked and how is critical to assessing the situation.
Some more symptoms would be helpful. Code, in particular. Code in your questions is very useful.
Given the lack of evidence, I'd wager that your are mutating a string on one thread while trying to grab the size on another. Or the object is being released on one thread while still using it another. Or you are manipulating an object from a secondary thread that isn't thread safe.
I think performSelectorOnMainThread:withObject:waitUntilDone: is correct,
Before, I use a operation to calculate text size,
And use waitUntilAllOperationsAreFinished in the main thread to wait for the operation's return,
But if I also use performSelectorOnMainThread:withObject:waitUntilDone in the operation, and set the waitUntilDone parameter to Yes(Because I need the result)
The main thread will be stucked
So now I remove waitUntilAllOperationsAreFinished ,and use a asynchronous object to ensure
the operation won't start until the previous one stopped
[md removeAllObjects];
[md setObject:subString forKey:#"text"];
[md setObject:[NSNumber numberWithInt:view_w ] forKey:#"width"];
[md setObject:[NSNumber numberWithInt:height_left + font_h ] forKey:#"height"];
[self performSelectorOnMainThread:
#selector(calculateTextRegion:)
withObject:md
waitUntilDone:YES];
CGSize stringSize = textRegion;

Threading in Objective-C

Are there threads in Objective C? If so, how are they declared and used?
If anybody knows about multithreading in Objective C, please share with me.
Thanks and regards.
An easy way to just spin off a method in a new thread is to use.
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument on NSThread. If you aren't running garbage collected you need to set up your own autorelease pool.
Another easy way if you just don't want to block the main thread is to use.
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg on NSObject
Depending on what type of concurrency you are after you should also take a look at NSOperation that can give you free locking so you can share it between several threads among other things.
If you're developing using Cocoa (ie for the mac or iphone), you have access to the NSThread class, which can be used for multithreading. Googling for NSThread will find you the API.
You can declare it like using:
NSThread *mythread = [[NSThread alloc] initWithTarget:target selector:selector object:argument];
Where target and selector is the object and selector you want to start a thread with, and argument is an argument to send to the selector.
Then use [mythread start] to start it.
Yes there are threading concepts in Objective C. and there are multiple way to achieve multi threading in objective C.
1> NSThread
[NSThread detachNewThreadSelector:#selector(startTheBackgroundJob) toTarget:self withObject:nil];
This will create a new thread in the background. from your main thread.
2> Using performSelector
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
will perform UI task on your main thread if you call this from background thread... You can also use
[self performSelectorInBackground:#selector(abc:) withObject:obj];
Which will create a background thread.
3> Using NSoperation
Follow this link
4> Using GCD
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self callWebService];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUI];
});
});
Will callWebService in background thread and once it's completed. It will updateUI in main thread.More about GCD
This is almost all way of multithreading that is used in iOS. hope this helps.
You could also look into NSOperation
To see an example of this, have a look at Drew McCormack's post on MacResearch.
Before going to far with stuff like detachNewThreadSelector: be sure to check out Apple's official documentation. For a high-level overview of options (including operation queues, dispatch queues, and such), there's the Concurrency Programming Guide. And, for a look at lower-level (and less recommended) threading, there's the Threading Programming Guide.
You definitely don't want to just start spinning up threads without reading what Apple has to say on the subject first. They've done a lot of work with stuff like GCD to make it easier and safer to write concurrent programs.