I have a class derived from NSThread:
#interface FSEventMonitorThread : NSThread {
FSEventStreamRef m_fseStreamRef;
CFRunLoopRef m_runLoop;
}
- (id) initWithStream:
(FSEventStreamRef)fseStreamRef;
- (void) dealloc;
- (void) main;
#end
#implementation FSEventMonitorThread
- (id) initWithStream:
(FSEventStreamRef)fseStreamRef
{
if ( self = [super init] )
m_fseStreamRef = fseStreamRef;
return self;
}
- (void) dealloc
{
CFRunLoopStop( m_runLoop );
FSEventStreamStop( m_fseStreamRef );
[super dealloc];
}
- (void) main
{
m_runLoop = CFRunLoopGetCurrent();
FSEventStreamScheduleWithRunLoop(
m_fseStreamRef, m_runLoop, kCFRunLoopDefaultMode
);
FSEventStreamStart( m_fseStreamRef );
CFRunLoopRun();
}
#end
Elsewhere (inside a C++ function), I create an instance:
m_thread = [[FSEventMonitorThread alloc] initWithStream:m_fseStreamRef];
My understanding is that the retain-count should now be 1.
In another C++ function, I want to stop and deallocate the thread:
[m_thread release];
Yet the dealloc method is not called. If I instead do:
[m_thread release];
[m_thread release];
then dealloc is called which implies the retain-count was 2. But how did it get to be 2?
Note that the documentation for NSThread only mentions retaining when using detachNewThreadSelector:toTarget:withObject:.
The framework itself keeps ownership of the thread. This is necessary so that the thread object doesn't go away while the main method is executing. If you want to stop a thread, you are doing it the wrong way. You must provide some sort of inter-thread communication to signal the thread's main method that it should stop whatever it is doing, clean up, and exit. Once that happens, relinquishing your ownership of the thread will cause the thread to dealloc. You should never simply over-release something to get it to "go away". If you are doing that, you are almost certainly not using the provided objects the way they are meant to be used, as in this case.
A very simple example to cancel your thread might be:
- (void)finishThread
{
if( [NSThread currentThread] != self ) // dispatch this message to ourself
[self performSelector:#selector(finishThread) onThread:self withObject:nil waitUntilDone:NO];
else
CFRunLoopStop(CFRunLoopGetCurrent());
}
Related
I tried to subclass NSThread in order to operate a thread with some data. I want to simulate the join() in python, according to the doc:
join(): Wait until the thread terminates. This blocks the calling thread until
the thread whose join() method is called terminates
So I think using performSelector: onThread: withObject: waitUntilDone:YES would be fine, but it does not work. It just do nothing and would not exit, running like forever.
This is my code:
#interface MyClass : NSThread
#property (strong, nonatomic) NSMutableArray *msgQueue;
#property (assign, nonatomic) BOOL stop;
#end
#implementation MyClass
-(id)init
{
self = [super init];
if (self) {
self.msgQueue = [NSMutableArray array];
self.stop = NO;
[self start];
return self;
}
return nil;
}
-(void)myRun
{
while (!self.stop) {
NSLock *arrayLock = [[NSLock alloc] init];
[arrayLock lock];
NSArray *message = [self.msgQueue firstObject];
[self.msgQueue removeObjectAtIndex:0];
[arrayLock unlock];
NSLog(#"%#", message);
if ([message[0] isEqualToString:#"terminate"]) {
self.stop = YES;
}
}
}
-(void)join
{
[self performSelector:#selector(myRun) onThread:self withObject:nil waitUntilDone:YES];
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
MyClass *a = [[MyClass alloc] init];
[a.msgQueue addObject:#[#"terminate",#"hello world"]];
//[a myRun]; // this line works so the myRun method should be good,
[a join]; // but I want this line work, and I have no idea what the problem is.
}
return 0;
}
From Apple's documentation on performSelector:onThread:withObject:waitUntilDone::
This method queues the message on the run loop of the target thread using the default run loop modes—that is, the modes associated with the NSRunLoopCommonModes constant. As part of its normal run loop processing, the target thread dequeues the message (assuming it is running in one of the default run loop modes) and invokes the desired method.
You probably never started a run loop on the thread, so it will never execute your myRun method, since it has no run loop to execute on.
As for Merlevede's answer, myRun is not enqueued on the same thread as join. join was called on your main thread, whereas you're trying to enqueue myRun on your secondary thread. So his theory is incorrect. Also from Apple's documentation regarding the wait parameter:
If the current thread and target thread are the same, and you specify YES for this parameter, the selector is performed immediately on the current thread. If you specify NO, this method queues the message on the thread’s run loop and returns, just like it does for other threads. The current thread must then dequeue and process the message when it has an opportunity to do so.
So even if it was on the same thread, it wouldn't be stuck waiting, it would just execute it right away as if you had directly called the method instead of using performSelector: in the first place.
You're basically in a deadlock condition.
-(void)join
{
[self performSelector:#selector(myRun) onThread:self withObject:nil waitUntilDone:YES];
}
join is waiting for myRun to finish (waitUntilDone flag), but myRun is enqueued on the same thread as join, so it's also waiting for join to finish.
For performSelector:onThread:withObject:waitUntilDone: you would never pass the current thread as the thread parameter.
I have a certain object that perform a "Refresh" every X seconds. ("The Updater")
The way I'm doing this repetitive update is by calling performSelector:withObject:afterDelay and in my selector I'm re-scheduling as necessary.
Of course I have a method to stop these invokations by calling cancelPreviousPerformRequests.
The problem is that this "Updater" is never being deallocated.
There is only one other object that retaining the Updater (AFAIK), and the retaining object is being deallocated and calls [self setUpdater:nil];
I'm suspecting that this is have something to do with the performSelector:withObject:afterDelay method, but I couldn't find any reference to that question in the documentation.
Can anyone confirm or dismiss it?
Thanks!
APPENDIX
This are the scheduling methods:
-(void) scheduleProgressUpdate
{
[self stopProgressUpdates]; // To prevent double scheduling
[self performSelector:#selector(updateProgress)
withObject:nil
afterDelay:1.0];
}
-(void) updateProgress
{
// Perform update..
[self scheduleProgressUpdate];
}
-(void) stopProgressUpdates
{
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:#selector(updateProgress)
object:nil];
}
As far as I know the performSelector method retain its receiver and arguments.
I have an object called MadsAdViewController that requests ads asynchronously, and is called back on the method didReceiveResponse. In an app with a lot of memory usage the dealloc method is called really fast, and sometimes even when the didReceiveResponse method is still running. This causes crashes, as the result of what I would call a race condition. As the output shows, both didReceiveResponse and dealloc are called on the main thread.
Why isn't the dealloc waiting for the method to finish? And why does the #synchronized block not work? And how can I fix this?
-(void)didReceiveResponse:(MadsAdResponse*) inAdResponse {
NSLog(#"didReceiveResponse: main thread? = %i, address = %p", [NSThread isMainThread], self);
#synchronized (self) {
//... (lots of stuff that takes a while)
[self logEvent:logAction eventName:EVENT_INIT action:ACTION_VIEW extra:nil];
}
NSLog(#"done with didReceiveResponse response")
}
- (void)dealloc {
#synchronized (self) {
NSLog(#"in sync block in dealloc of object %p", self);
//lots of releases
}
[super dealloc]
}
and this is the output:
didReceiveResponse: main thread? = 1, address = 0x139d50b0
in sync block in dealloc of object 0x139d50b0
and then the app crashes:
*** -[[MadsAdViewController logEvent:eventName:action:extra:]: message sent to deallocated instance 0x139d50b0
OK, turned to be a nice interaction between blocks and this piece of code listed above.
For context, our library was used by an external party in a way that we would not ahem recommend.
This is what happened around it:
XXXMadsAdViewController *adViewController = [[[XXXMadsAdViewController alloc]init]autorelease];
self.adViewController = adViewController;
[self.adViewController loadAdWithCompletionHandler:^(BOOL success) {
//stuff
}];
XXXMadsAdViewController both extended MadsAdViewController as that it was the delegate to receive the method call didReceivePartialAd. [self.delegate didReceivePartialAd] is called in the method didReceiveResponse that I didn't include in the original question and that was called before [self logEvent];
Now, sometimes self.adViewController was already released, but this block was still waiting for the callback. On callback on didReceivePartialAd, the block was processed, self.adViewController released again and the app crashed.
I fixed the problem by making didReceivePartialAd the last statement of the method didReceiveResponse.
Thanks guys, without your pointers I would still think it was a race condition!
I've had a look around but have been unable to find a definitive answer to this question.
If I have a class that performs an async operation, when and how do I release it?
-(void)main
{
AsyncObject *async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
}
When do I release *async?
You could keep a private property to save the value, or, if you have control over the AsyncObject, pass the instance in the didSomething: selector.
I think the first option is better since you know the object will be retained until you get your delegate call.
Option 1:
ClassName.m
#interface ClassName ()
#property (nonatomic, retain) AsyncObject* async;
#end
#interface
//...
-(void)main
{
async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
[async release];
async = nil;
}
Option 2:
-(void)aysncObject:(AsyncObject*)async didSomething:(Result*)result {
[async release];
}
If your object runs its asynchronous task on a background thread, or is the target of a timer, or uses GCD and is referenced within the scope of the dispatched block (the ^ {} kerjigger) then it will be retained for you for the lifetime of that background operation.
So the normal use case would be:
AsyncObject *async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
[async release];
Now, it's possible to work in the background with an object that is not retained (e.g. by using a __block-scoped reference to the object with GCD, or by detaching your worker thread with pthreads instead of NSThread/NSOperation) but there are no typical use cases I can think of offhand where that would happen. In such a case, you should ensure that -goDoSomething internally retains and releases self for the duration of the operation.
(If somebody can think of a case where the object is not retained for you, please post in the comments and I'll update my answer.)
Thanks for the help guys, I did a bit of experimenting with NSURLConnection to see how it handled it (As you autorelease that and it will continue on with it's async operations).
Turns out at the beginning of every async step it internally bumps its retain count and at the end of every async step it internally releases itself.
This means that it can be sent autorelease/release and it won't actually be release until it has completed it's current operation.
// MAIN.M
-(void)main
{
AsyncObject *async = [[[AsyncObject alloc] initWithDelegate:self] autorelease];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
}
// ASYNCOBJECT.M
-(void) goDoSomething
{
[self retain];
}
-(void) finishedDoingSomething
{
[delegate didSomething:result];
[self release]
}
I've just run into blocks and I think they are just what I'm looking for, except for one thing: is it possible to call a method [self methodName] from within a block?
This is what I'm trying to do:
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
void (^tempFunction)(void) = ^ {
[self changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
}
I've been searching for a couple of days and I can't find any evidence that this is possible.
Is this at all possible, or am I trying to use blocks for something they aren't meant for?
The reason I'm using blocks is that I've created a Fader class, and I want to store a block for it to execute when it finishes fading out.
Thank you
EDIT:
Okay, I added in the suggestion, but I'm still getting an EXC_BAD_ACCESS error...
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
__block MyScreen* me = self;
void (^tempFunction)(void) = ^ {
[me changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
[fader release];
}
Maybe I'm not allowed to give fader the function...?
Yes, you can do this.
Note, however, that the block will retain self. If you end up storing this block in an ivar, you could easily create a retain cycle, which means neither would ever get deallocated.
To get around this, you can do:
- (void) someMethodWithAParameter:(id)aParameter {
__block MySelfType *blocksafeSelf = self;
void (^tempFunction)(void) = ^ {
[blocksafeSelf changeWindow:game];
};
[self doSomethingWithBlock:tempFunction];
}
The __block keyword means (among other things) that the referenced object will not be retained.
The accepted answer is outdated. Using __block in that case can cause errors!
To avoid this problem, it’s best practice to capture a weak reference to self, like this:
- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
[weakSelf doSomething]; // capture the weak reference
// to avoid the reference cycle
}
}
Please, look at Apple Documentation - Avoid Strong Reference Cycles when Capturing self
for more details.
__block CURRENTViewController *blocksafeSelf = self;
[homeHelper setRestAsCheckIn:strRestId :^(NSObject *temp) {
[blocksafeSelf YOURMETHOD:params];
}];
Is it possible to call a method [self methodName] from within a block?
Yes, why not. If your tempFunction is an instance method, you can do it. The called method should be accessible is the only restriction.
Consider this (which I think is the best practice)
#implementaion ViewController
- (void) viewDidLoad {
__weak typeof(self) wself = self;
[xxx doSomethingUsingBlock: ^{
__strong typeof(wself) self = wself;
[self anotherMessage];
}];
}
#end
Moreover, You can define wrapper macros.
#define MakeWeakSelf __weak typeof(self) wself = self
#define MakeStrongSelf __strong typeof(wself) self = wself
I wonder whether you [fader setFunction:tempFunction]; then is synchronous or asynchronous.
blocks push onto stack.so in MRR,if you don't retain it,it will pop off.
-(void)someFunction{
Fader* fader = [[Fader alloc]init];
void (^tempFunction)(void) = ^ {
[self changeWindow:game];
//changeWindow function is located in superclass
};
[fader setFunction:tempFunction];
//if the tempFunction execute there will be right.
}//there the tempFunction pop off
//....some thing go on
//execute the tempFunction will go wrong.