I have a Cocoa/Objective-C class with a method that looks something like this:
- (void)doWork:(void (^)(void))handler
{
[self->someObject doActualWork:kWorkID handler:^(Result *result) {
if (handler)
handler();
}];
}
However, when the inner block is called handler have been dealloced and the program crashes when it is called. From what I understand this is because the block is stored on the stack and thus removed soon after doWork: finishes. I'm using ARC. What should I do to fix this?
First, self-> for iVar access is an odd, and discouraged, pattern, generally.
Did you copy the blocks prior to storing 'em away for use later? If this is intended to be asynchronous code, then your actualWork:handler: method should be copying the block prior to enqueueing it.
Even under ARC; while ARC handles the return of blocks from methods automatically, it can't handle blocks as arguments automatically and you do still need to copy 'em.
If this is purely synchronous code, then something else is going wrong. You'll need to provide more clues.
Related
I have an Objective-C class whose instances can detect when they are no longer needed and destroy themselves, but I am looking for a safe way to trigger an object's self-destruction from within the object itself, without somehow "destroying the method that is calling the destruction"... My code looks roughly like this (some removed for brevity):
+ (oneway void)destroyInstance:(id)obj {
printf("Destroying.\n");
if (obj != nil) {
free(obj);
obj = nil;
}
}
- (oneway void)release {
_noLongerRequired = [self determineIfNeeded]; // BOOL retVal
if (_noLongerRequired) {
[self deallocateMemory]; // Free ivars etc (NOT oneway)
[MyClass destroyInstance:self]; // Oneway
}
}
If I call -release, it should return instantly to the main thread (due to the oneway).
Meanwhile, if the instance finds it is no longer needed, it should then call the oneway class method destroyInstance: and remove itself from the runtime. My question is, is this safe?? And have I used oneway correctly? It seems to me there is the possibility of destroying the instance's -release function before it returns, which could be... rather bad..?
(PS: Obviously not looking for anything to do with NSObject, etc :))
This is without a doubt a terrible idea if you want working and maintainable software and unsafe in just about any context. But sometimes terrible, unsafe ideas can be fun on the weekend, so I'll answer the components of the question I can discern.
A method will not get "destroyed" because an instance is deallocated. What can happen is that self can end up pointing to deallocated memory during the execution of a method, which means that accessing self or any instance variables during this time can crash.
As to the rest of your code, there is no reason at all to set obj equal to nil in +destroyInstance, so if you were trying accomplish something in particular (nil'ing out pointers to the object perhaps) that way is not the right way to go about it.
Thinking about the use of oneway, what the language says is that sending this message won't block the calling thread. In the context of releasing objects I think it makes some sense, as presumably the target of the message won't ever be referenced by that thread again. By that logic I'd think your declaration of +destroyInstance is maybe OK. I do wonder if you'd need to provide some sort of synchronization so that there's no retain/release race conditions but thinking about it, taking ownership of an object should probably never be asynchronous.
My personal opinion is that anyone who puts this code into production should probably be fired or sued =P. But if it's only for educational purposes, have fun, and hope this helps.
I was looking at some code in this thread How do you trigger a block after a delay, like -performSelector:withObject:afterDelay:?. I was wondering, if the block does something asynchronously, when should the block be released?
Let's say I have code that looks like this:
- (void)testMethod:(id)parameter
{
dispatch_block_t block = ^{
SomeAsyncTask *t = [SomeAsyncTask withCompletionBlock:^{
[parameter doAction];
}];
};
[self performSelector:#selector(executeBlock:)
onThread:backgroundThread
withObject:block
waitUntilDone:NO];
dispatch_release(block); //I can release the block here because performSelector retains the block
}
- (void)executeBlock:(id)block
{
block();
}
Is the key then, that the completion block in SomeASyncTask will retain the parameter so it's safe to release the block?
Ken Thomases's answer is correct. I want to give a more detailed response to your comments.
First, it is not clear whether you meant performSelector:withObject: or performSelector:withObject:afterDelay:, since performSelector:withObject: is a direct synchronous call, so [self performSelector:#selector(runBlock:) withObject:block_]; is identical to [self runBlock:block_]. I'll assume it's performSelector:withObject:afterDelay:, since performSelector:withObject: is less interesting.
Look at it step by step. performSelector:withObject:afterDelay: retains its argument, so you can release it after giving the block to it. And performSelector:... retains it through the performance of its selector. So during the runBlock, the block is valid because it is still retained by performSelector:.... During the execution of the block, it is still valid (since it is still inside the execution of runBlock). doSomethingAsynchronouslyWithCompletionBlock must retain its argument if it is asynchronous. And so on.
But you don't need to look at it that way. Once you think through it, you will realize that the memory management rules are made so that you don't need to worry about what other code does, only what you need locally.
The memory management rules boil down to the following conditions: Every function / method expects its arguments to be valid when it is called (which usually means through the duration of the function call, since the calling function does not run during this time, so how can it become invalid, unless this function does something which indirectly removes it (like removing from a dictionary)?); and does not have any expectations about how long it will remain valid after the function call. That's it. Everything follows from this.
For example, in your doWork, you only care about how long you need to use the block. Since you don't need it after performSelector:..., you can safely release it. It doesn't matter that performSelector:... might do something with it asynchronously; you may not even know that it is asynchronous (e.g. you could be choosing an unknown method to call dynamically). The point is, what it does doesn't matter. Why? Because the performSelector:... does not assume the argument to be valid any longer than when you called it. So if it needs to keep it longer (and it does), it must retain it (but you don't need to know this). And it will retain it for as long as it needs it.
Similarly, runBlock can assume that the argument it was given is valid for the duration of its call. Since it does not need to keep it around for longer (all it does is call the block), it does not need to retain it. The block does not change this. Why? Again, because the block does not assume its arguments (including the block itself) is valid after its call, so runBlock doesn't need to guarantee it. If the block calls doSomethingAsynchronouslyWithCompletionBlock, that's fine. doSomethingAsynchronouslyWithCompletionBlock does not assume anything is valid beyond its call, so if it is truly asynchronous, it must retain it somewhere. etc.
You can release it immediately after invoking -performSelector:withObject:afterDelay:. (I assume you meant to use the after-delay variant.) As usual, you are responsible for your memory management and other code is responsible for its memory management. Which is another way of saying that -performSelector:withObject:afterDelay: has to retain the receiver and the object that's passed in until after the selector has been performed.
Edited to add: By the way, why wouldn't you use dispatch_after() as illustrated in the answer to the question to which you linked?
I might just try passing an array with the arguments.
I'm working on an iOS project that has to work from iOS4. I have an NSOperationQueue and I add an operation. The main method of the operation looks something like this:
-(void)main
{
[self.client getStuffSuccess:^(Stuff *s) {
//Do something on success
} failure:^(NSError *error) {
//Do something on failure
}
}
The code inside the block will only be called when getStuff calls success or failure. I thought that in the meanwhile, my operation would be removed from the NSOperationQueue and the block wouldn't be called. However, I tested it and the block was in fact called. It's called no matter if the client calls the success block on the dispatch_get_main_queue or on the thread that called it - in this case the operation above.
Before the block is called, the method isFinished is actually returning true (I overrode the isFinished method and checked the value), so can someone explain me how is it possible that the block is being called?
I'm asking all this because although this works fine for one call, when I add it in a cycle of a few hundred iterations, I get an EXC_BAD_ACCESS and understanding the above might help me on the debugging.
The code inside the block will only be called when getStuff calls success or failure. I thought that in the meanwhile, my operation would be removed from the NSOperationQueue and the block wouldn't be called.
What leads you to believe this. A block is a closure, a self-contained block of code. It does not rely on the existence of some other object (the NSOperation in this case) in order to exist. You might want it to rely on that other object, but that's up to you to enforce. Ideally, I'd make getStufSuccess:failure: synchronous. If you can't you can use an NSCondition or call NSRunLoop methods to block the thread cheaply until it's done.
You also need to consider thread safety here. Your problem might not have to do with the operation going away, but your block doing something that isn't thread-safe.
Since getStuffSuccess:failure is asynchronous, you need to use a concurrent operation. Here is a helpful blog post:
http://www.dribin.org/dave/blog/archives/2009/05/05/concurrent_operations/
If your -getStuffSuccess:failure doesn't block the thread (i.e. the method is asynchronous), then your -main will complete and your operationQueue may deallocate your operation before the success or failure blocks are called. You can block the thread by adding a:
while(notProcessed){
sleep(0.1);
//Make sure your success and failure functions update notProcessed BOOL
}
so that main never completes before you've had a chance to call the closures. Or just use a synchronous method. This is generally fine because you won't be on the UI thread anyways.
Accidentally I have been using a #synchronized block with the semaphore self in a class method.
+(void)someFunction {
#synchronized(self) {
/* some code */
}
}
It seems to be valid code, at least the compiler does not give me any bad feedback. My question is: what is self here? As far as I can tell the #synchronized block didn't work, but it didn't crash either.
I'm just asking out of curiousity.
self in this instance refers to the class, instead of an instance. In ObjC, classes are themselves objects.
self in this context is the class itself, it's perfectly fine to use #synchronized in a class function since they are also Objective-C objects.
The #synchronized syntax is a compiler extension for mutex implementation. I assume you understood what it does. The compiler will translate it into something else, supposedly something similar to critical section because it's less CPU intensive. Locks need to be tracked. The implementation will use an object to record the state of the lock, to keep its integrity (i.e. a lock shouldn't be acquired twice, or unlocked twice).
In #synchronized(self), the object doesn't have to be self. It could be any objective-c object. Note that a single #synchronized block usually does nothing (when you mentioned it's not working, it's actually behaving correctly). But when you have two #synchronized blocks on the same object, only one block will be executed at the same time, the other block would have to wait for the lock to be unlocked (i.e. the first block finishes). This helps to keep things synchronized as in a multithreaded environment.
In a class method self is the class that the method is being called on. For example you can call other class methods of the same class using self. [MyClass someFunction] and [self someFunction] would be the equivalent to recursively calling someFunction. The #synchronized block I am sure worked as it was supposed to.
I am wondering if I am using blocks as shown in the code below
__block Loader *loader = [[Loader alloc]initWithResourcePath:self.resourcePath];
[loader setCompletionHandler:^(NSArray *anArray){
self.answerArray=anArray;
[self reloadData];
}];
[loader getObjects];
My question is with regards to memory management. The analyzer tells me that there is a potential leak (since I did an alloc/init for my loader). How can I stop the leak here? I tried to release the loader at the end but that causes my app to stop functioning. Any advise is appreciated here
Several issues:
there is no reason for loader to be declared __block; you aren't re-assigning in the block and, thus, the __block is pointless.
the leak is because you alloc/init the loader, but never release it
do not name methods getSomething; the get prefix is reserved for methods that return stuff by reference. Just call it objects. If it is supposed to trigger the load, then call it load or performLoad.
If it is asynchronous, then getObjects is pointless. If synchronous, then the completion block is pointless.
If loader is to be used synchronously, release it at the end of the method. If it is asynchronous, then the completion block could release it. Note that the use of __block in this case is still pointless; while referring to loader in the completion block will create a retain cycle, it will be broken when you explicitly Block_release() the block in your loader (because you must have done a Block_copy() when setting the completion handler if it is to be used asynchronously in the first place).
If you plan to use loader outside of the function calling your block, it is highly possible that you need to store it in a ivar of your controller (I guess, it is a controller, but I don't know what kind of class owns the code you shows). Once you do that, you can release it in your dealloc.
The reasoning is that loader should live across several methods and runloop cycles, so a local variable will not do.
Otherwise, just release it at the end of the block, once you have done with it.
If this does not seem right to you, then possibly more code is needed.
I'm going to make some assumptions: 1) The completion handler (block) is used by method getObjects. 2) getObjects is asynchronous (it returns to the caller right away though it continues to process).
With these assumptions you can't send release after sending getObjects because getObjects is still using the completion handler.
Try sending a release or autorelease at the end of the completion handler. That should free loader provided reloadData is not also asynchronous.