Cause NSThread can't be joinable I tried next method, it seems works ok, but is still very bad solution or good enough?
// init thread
NSThread *mythread = [[NSThread alloc] initWithTarget:self selector:#selector(runThread:) object: nil];
// start thread
mythread.start;
// JOIN NSThread custom implementation
// wait until thread will finish execution
if (mythread.isExecuting) {
while(mythread.isExecuting) {
sleep(0);
}
} else if (!mythread.isCancelled && !mythread.isFinished) {
while(!mythread.isExecuting) {
sleep(0);
}
while(mythread.isExecuting) {
sleep(0);
}
}
A live lock like this is a bad idea on an iPhone, because it eats battery and CPU without doing anything, even though calling sleep(0) might give it a little bit of rest.
You could use NSCondition to implement joining. The idea is that the parent thread will wait on the NSCondition, and the worker thread would signal on that condition when it finishes:
- (void)main1 {
// thread 1: start up
_joinCond = [NSCondition new];
[mythread start];
// thread 1: join, i.e. wait until thread 2 finishes
[_joinCond lock];
[_joinCond wait];
[_joinCond unlock];
}
- (void)main2 {
// thread 2 (mythread):
// ... work, work, work ...
// now we're done, notify:
[_joinCond lock];
[_joinCond signal];
[_joinCond unlock];
}
I read the Apple doc about the function of #autoreleasepool. It says in a new thread, the programmer should declare a new autorelease pool using the following code in ARC.
#autoreleasepool{
//etc
}
But as my test, I did not add the #autoreleasepool block in my code, it still run well.My code is like below.
[NSThread detachNewThreadSelector:#selector(threadTest) toTarget:self withObject:nil];
- (void)threadTest
{
// #autoreleasepool {
for (int i=0; i<1000000; i++) {
NSNumber *num = [NSNumber numberWithInt:i];
[NSString stringWithFormat:#"%#",num];
}
// }
}
I used the Xcode Leaks instruments to see whether it has any memory leaks, but I did not find any memory leaks. So the result is that "It seems it is not required to declare the #autoreleasepool block in a secondary thread", is my word correct, can someone clarify this?
In iOS, when the autoreleasepool create and be destroyed?
When a touch event created, the runloop create an autoreleasepool.
When the touch event ends, the autoreleasepool will be destroyed.
Is my understand of the autoreleasepool right?
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
how can I understand the autoreleasepool in main method?
In xcode 4 we have to create pool and we have release it by using this syntax with NSAutorealeasePool:
{
NSAutorealeasePool *pool=[[NSAutorealeasePool alloc] init];
[pool drain];
}
When ever use like this in Xcode 4 memory is initialized for your pool and control enter into your pool deallocate your pool objects by using drain ..if u use drain means u permanently destroy ypur pool objects..if you use release means its not completely destroyed..
In xcode 5 we are using #autoreleasepool syntax like this:
#autoreleasepool
{
}
Here we don't need to create pool and release the objects..every thing done by compiler..once control enters automatically create the pool and release the pool objects means which we want to deallocate
The NSAutoreleasePool class is used to support Cocoa’s reference-counted memory management system. An autorelease pool stores objects that are sent a release message when the pool itself is drained.
IMPORTANT
If you use Automatic Reference Counting (ARC), you cannot use autorelease pools directly. Instead, you use #autoreleasepool blocks. For example, in place of:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Code benefitting from a local autorelease pool.
[pool release];
you would write:
#autoreleasepool {
// Code benefitting from a local autorelease pool.
}
#autoreleasepool blocks are more efficient than using an instance of NSAutoreleasePool directly; you can also use them even if you do not use ARC.
Few things to keep in mind -
Case 1)
#autoreleasepool
{
MyObject *obj = [[MyObject alloc] init];
//No need to do anything once the obj variable is out of scope there are no strong pointers so the memory will free
}
case 2)
MyObject *obj //strong pointer from elsewhere in scope
#autoreleasepool
{
obj = [[MyObject alloc] init];
//Not freed still has a strong pointer
}
This gives me memory leak, even thought I call create and release pool in the selector function.
[read_qr performSelectorInBackground:#selector(newThreadWrapper) withObject:nil];
class read_qr:
- (void) newThreadWrapper {
reading = YES;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self another_function:arg];
[pool release];
reading = NO;
}
There is no leak if I call the same function in the main thread without performSelectorInBackground.
Any tips are appreciated.
Thank you.
Apple's Grand Central Dispatch (GCD) is great, but only works on iOS 4.0 or greater. Apple's documentation says, "[A] serialized operation queue does not offer quite the same behavior as a serial dispatch queue in Grand Central Dispatch does" (because the queue is not FIFO, but order is determined by dependencies and priorities).
What is the right way to achieve the same effect as GCD's serial dispatch queues while supporting OS versions before GCD was released? Or put another way, what is the recommended way to handle simple background processing (doing web service requests, etc.) in iOS apps that want to support versions less than 4.0?
How about this PseudoSerialQueue? It is a minimal implementation like the Dispatch Serial Queue.
#import <Foundation/Foundation.h>
#interface PseudoTask : NSObject
{
id target_;
SEL selector_;
id queue_;
}
#property (nonatomic, readonly) id target;
- (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue;
- (void)exec;
#end
#implementation PseudoTask
#synthesize target=target_;
- (id)initWithTarget:(id)target selector:(SEL)selector queue:(id)queue;
{
self = [super init];
if (self) {
target_ = [target retain];
selector_ = selector;
queue_ = [queue retain];
}
return self;
}
- (void)exec
{
[target_ performSelector:selector_];
}
- (void)dealloc
{
[target_ release];
[queue_ release];
}
#end
#interface PseudoSerialQueue : NSObject
{
NSCondition *condition_;
NSMutableArray *array_;
NSThread *thread_;
}
- (void)addTask:(id)target selector:(SEL)selector;
#end
#implementation PseudoSerialQueue
- (id)init
{
self = [super init];
if (self) {
array_ = [[NSMutableArray alloc] init];
condition_ = [[NSCondition alloc] init];
thread_ = [[NSThread alloc]
initWithTarget:self selector:#selector(execQueue) object:nil];
[thread_ start];
}
return self;
}
- (void)addTask:(id)target selector:(SEL)selector
{
[condition_ lock];
PseudoTask *task = [[PseudoTask alloc]
initWithTarget:target selector:selector queue:self];
[array_ addObject:task];
[condition_ signal];
[condition_ unlock];
}
- (void)quit
{
[self addTask:nil selector:nil];
}
- (void)execQueue
{
for (;;) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[condition_ lock];
while (array_.count == 0)
[condition_ wait];
PseudoTask *task = [array_ objectAtIndex:0];
[array_ removeObjectAtIndex:0];
[condition_ unlock];
if (!task.target) {
[pool drain];
break;
}
[task exec];
[task release];
[pool drain];
}
}
- (void)dealloc
{
[array_ release];
[condition_ release];
}
#end
How to use:
PseudoSerialQueue *q = [[[PseudoSerialQueue alloc] init] autorelease];
[q addTask:self selector:#selector(test0)];
[q addTask:self selector:#selector(test1)];
[q addTask:self selector:#selector(test2)];
[q quit];
Seems like people are going to a lot of effort to rewrite NSRunloop. Per the NSRunloop documentation:
Your application cannot either create
or explicitly manage NSRunLoop
objects. Each NSThread object,
including the application’s main
thread, has an NSRunLoop object
automatically created for it as
needed.
So surely the trivial answer would be, to create a usable queue:
- (void)startRunLoop:(id)someObject
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[NSRunLoop currentRunLoop] run];
[pool release];
}
...
NSThread *serialDispatchThread = [[NSThread alloc]
initWithTarget:self
selector:#selector(startRunLoop:)
object:nil];
[serialDispatchThread start];
To add a task to the queue:
[object
performSelector:#selector(whatever:)
onThread:serialDispatchThread
withObject:someArgument
waitUntilDone:NO];
Per the Threading Programming Guide section on Run Loops:
Cocoa defines a custom input source
that allows you to perform a selector
on any thread. ... perform selector requests are
serialized on the target thread,
alleviating many of the
synchronization problems that might
occur with multiple methods being run
on one thread.
So you've got an explicitly serial queue. Of course, mine isn't fantastically written because I've told the run loop to run forever, and you may prefer one you can terminate later, but those are easy modifications to make.
you can simulate it using NSOperationQueue, then just set the task count to one.
EDIT
-- oops, should have read more carefully. the fifo solution follows:
i can't think of a way that the majority of ios devs would use in your situation.
i'm not afraid of writing threaded programs, so here is one solution:
create a fifo worker queue that:
supports locking
holds one NSOperationQueue
holds an NSOperation subclass, designed to pull workers from the fifo queue in its implementation of main. only one may exist at a time.
holds an NSArray of workers to be run (defining a worker is up to you - is it an NSInvocation, class, operation, ...)
the NSOperation subclass pulls the workers from the fifo worker queue until the fifo worker queue is exhausted.
when the fifo work queue has workers and no active child operation, it creates a child operation, adds it to its operation queue.
there are a few pitfalls if you aren't comfortable writing threaded programs -- for this reason, this solution is not ideal for everybody, but this solution would not take very long to write if you are already comfortable using all the technologies required.
good luck
There are things NSOperationQueue documentation writer forgot to mention, making such implementation seem trivial when in fact it's not.
Setting the maximum concurrent operation count to 1 is guaranteed to be serial only
if NSOperations are added to the queue from same thread.
I'm using another option because it just works.
Add NSOperations from different threads but use NSCondition to manage queuing.
startOperations can (and should, you don't want to block main thread with locks) be called with performSelectorOnBackgroundThread...
startOperations method represents single job that consists of one or more NSOperations.
- (void)startOperations
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[AppDelegate condition] lock];
while (![[[AppDelegate queue] operations] count] <= 0)
{
[[AppDelegate condition] wait];
}
NSOperation *newOperation = [alloc, init]....;
[[AppDelegate queue] addOperation:newOperation];
[[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this!
NSOperation *newOperation1 = [alloc, init]....;
[[AppDelegate queue] addOperation:newOperation1];
[[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this!
NSOperation *newOperation2 = [alloc, init]....;
[[AppDelegate queue] addOperation:newOperation2];
[[AppDelegate queue] waitUntilAllOperationsAreFinished]; // Don't forget this!
// Add whatever number operations you need for this single job
[[AppDelegate queue] signal];
[[AppDelegate queue] unlock];
[NotifyDelegate orWhatever]
[pool drain];
}
That's it!
If the processing is in the background anyway, do you really need it to be strictly in-order? If you do, you can achieve the same effect simply by setting up your dependencies so 1 depends on 0, 2 on 1, 3 on 2, etc. The operation queue is then forced to handle them in order. Set the maximum concurrent operation count to 1, and the queue is also guaranteed to be serial.