Block in MRC why this code not crash - ios

File Person.h
#interface Person:NSObject
+ (void)callBlock:(void (^)())block;
#end
File Person.m
#imp:
+ (void)callBlock:(void (^)())block
{
[NSThread sleepForTimeInterval:2];
block();
}
#end
Code in ViewDidLoad:
Person *p = [[Person alloc] init];
void (^block)() = ^{
NSLog(#"%#",p);
[p release];
}
[Person callBlock:block];
finish!
MyQuestion:
in main function, block var is a stackblock,and this block assign to the function +callBlock:,and the block in Person.m is also a stackblock. Content of them are same.
In my opinion,the block in main will be free by system before called in Person.m, so I think this program will crash, but it run normal. why?
And i think my code is same as below.
...
void example_addBlockToArray(NSMutableArray *array) {
char b = 'B';
[array addObject:^{
printf("%cn", b);
}];
}
void example() {
NSMutableArray *array = [NSMutableArray array];
example_addBlockToArray(array);
void (^block)() = [array objectAtIndex:0];
block();
}
This programe crashed! which the difference between them?
Sorry! both program use mrc!!! i did not write clearly!

As it seems, you're using manual memory management.
Therefore is an explanation:
Person object case
You create the object
You create the block
You call the block
Block logs the object out
Block frees the object
That's why there is no crash
Char log case
Since you're not using ARC, it goes this way:
You add the block that logs char
Once you leave the function that adds the block to an array, the char you've just created is going to be released from memory.
In case if you use ARC for memory management, it will keep this char alive in the memory, until this block exists. But once you remove it from an array and block's reference count equals to 0, this char also being released.
You take a block from an array
Call it, it references to a memory address of char that already released, crash appears. As explained in your error:
EXC_BAD_ACCESS (code=1, address=0x0)
Means, that you point to zero address (null pointer exception in other words).
So, that's it.

As pointed out in the comments, the first example does not crash because the block is defined in a function scope which doesn't end until after the block is called.
The second example, on the other hand, defines the block in a secondary function, which ends before the block is called. Thus, at the time of the block invocation, the stack has already been modified and the block has become invalid.

After main function executed the block in main will be free by system ,not before called in Person.m. I tried the second code in viewcontroller, it works fine, not crash.

Related

where to release a __block variable?

I have following code snippet:
-(void) doSomething
{
__block NSMutableArray *objArray = [[NSMutableArray alloc] initWithCapacity:0];
[self performOperationWithBlock:^(void)
{
//adding objects to objArray
.
.
//operation with objArray finished
// 1. should objArray be released here?
}];
//2. should objArray be released here?
}
Should I autorelease the objArray?
If it's an asynchronous call, it would make sense to create the NSMutableArray inside the actual block:
[self performOperationWithBlock:^(void)
{
NSMutableArray *objArray = [[NSMutableArray alloc] initWithCapacity:0];
//adding objects to objArray
.
.
//operation with objArray finished
// 1. should objArray be released here?
}];
As you won't be needing it after the block (it only makes sense for the duration of the async operation), so in the end release it after you have used it. Or, you can simply:
NSMutableArray *objArray = [NSMutableArray array];
And in this case you don't need to release it.
If it's a sync call, you should release it after the block.
Note: I am assuming you are populating the NSMutableArray before being used on the block, which means it makes sense to be created before the block starts.
Async approach:
-(void) doSomething
{
// Remove the `__block` qualifier, you want the block to `retain` it so it
// can live after the `doSomething` method is destroyed
NSMutableArray *objArray = // created with something useful
[self performOperationWithBlock:^(void)
{
// You do something with the objArray, like adding new stuff to it (you are modyfing it).
// Since you have the __block qualifier (in non-ARC it has a different meaning, than in ARC)
// Finally, you need to be a good citizen and release it.
}];
// By the the time reaches this point, the block might haven been, or not executed (it's an async call).
// With this in mind, you cannot just release the array. So you release it inside the block
// when the work is done
}
Sync Approach:
It assumes that you need the result immediately, and it makes sense when you do further work with the Array, after the block has been executed, so:
-(void) doSomething
{
// Keep `__block` keyword, you don't want the block to `retain` as you
// will release it after
__block NSMutableArray *objArray = // created with something useful
[self performOperationWithBlock:^(void)
{
// You do something with the objArray, like adding new stuff to it (you are modyfing it).
}];
// Since it's a sync call, when you reach this point, the block has been executed and you are sure
// that at least you won't be doing anything else inside the block with Array, so it's safe to release it
// Do something else with the array
// Finally release it:
[objArray release];
}
You should release it after the performOperationWithBlock: method has finished, in my opinion, provided that method is synchronous (i.e. works on the same thread as the calling thread).
If that method is asynchronous then it should be released within the block.
If you're not using ARC, you should release the array when you no longer need it. According to the comments you added and assuming the doSomething method doesn't do anything with the array outside of the block, it should be at your 1. mark.
Option 2. Release it after [self performOperationWithBlock:...]. Block will retain and release yours objArray by himself. Releasing inside block is dangerous: block can be performed twice and then objArray will be released twice, but it's should de released once. So there is only one option left: 2.

Weird bad_access with dispatch_async

I'm getting a really weird bad access error while using dispatch async. I managed to reduce it down to this segment of code in my program.
-(void)buttonTapped:(id)sender {
__block NSArray*foo = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//Foo was initially declared here but then moved it outside.
foo = [self someMethod];
[foo retain]; // bad access here. Why ?
dispatch_async(dispatch_get_main_queue(),0) {
// doesnt matter what happens here
}); });
}
-(id)someMethod
{
return [self secondMethod];
}
-(id)secondMethod
{
// was initially returning an autoreleased object from here. Changed it
// to eliminate that as source of the error.
id newThing = [[NSObject alloc] init];
return newThing;
}
The code didnt initially look like this but this is how it is right now . Including allocating a dummy NSObject .
How is it possible for foo to get released in between calls inside a dispatch async ? I dont understand how this is possible. I know its difficult to suggest whats going from just this but any debugging suggestions would be helpful. I tried turning on NSZombies but I dont get any Zombies.
You ask:
How is it possible for foo to get released in between calls inside a dispatch_async?
It shouldn't, unless someMethod or secondMethod are, themselves, doing something asynchronously which might allow the autorelease pool to be drained in the interim.
I tried turning on NSZombies but I dont get any Zombies.
If you've got zombies turned on and you're not getting a zombie, then I suspect the problem rests elsewhere. Frankly, I suspect that the root of the problem was eliminated in your process of simplifying the sample code for the purposes of the question:
A few other observations/clarifications:
You declared foo to be a NSArray, but then you're returning NSObject. I'll assume you meant it to be NSObject throughout.
You have a line of code that says:
dispatch_async(dispatch_get_main_queue(),0) {
I'll just assume that was a typo and that you intended:
dispatch_async(dispatch_get_main_queue(), ^{
The foo variable should definitely be inside the dispatch_async block. It doesn't really make sense to have a __block variable for something (a) you don't reference outside of that block for a block; and (b) for a block you're dispatching asynchronously.
The secondMethod should return an autorelease object, as you apparently originally had it. (Or you'd probably want to change secondMethod and someMethod to start with new in their names to avoid confusion and make life easier for yourself when you eventually move to ARC.)
If you retain the foo object, you'll want to also add the appropriate release. In fact, your original code sample returns a +1 object, and then retain it again, bumping it to +2, so you'd need two release calls.
Anyway, correcting for these various issues, I end up with the following, which does not generate an exception:
- (IBAction)buttonTapped:(id)sender
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSObject *foo = [self someMethod];
[foo retain]; // no bad access here
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"foo = %#", foo);
[foo release];
});
});
}
- (NSObject *)someMethod
{
return [self secondMethod];
}
- (NSObject *)secondMethod
{
return [[[NSObject alloc] init] autorelease];
}
Furthermore, I would suggest, especially when using manual retain and release (MRR), that you run it through the static analyzer ("Analyze" on the Xcode "Product" menu) and make sure you have a clean bill of health. (It would have pointed out some of the issues I mentioned.) It's not perfect, but it's remarkably good at identifying issues.
But, in short, the above code is fine, and if you're still getting an exception, update your question with working code that reproduces the exception.

ARC and releasing object created in method

I have stumbled upon an issue for which I can't find answer elsewhere. When I am calling a method which returns pointer to an object which is later used and at the end set to nil, it is still allocated in memory (according to Instruments). I'm using XCode 4.6.3 and iOS 6.1. ARC is turned on.
Here is sample code:
ClassA.h
#interface ClassA : NSObject
-(void)runSomething;
#end
ClassA.m
#import "ClassA.h"
#import "ClassB.h"
#implementation ClassA
-(void)runSomething {
int counter = 0;
while (true) {
ClassB *instance = [self makeClassBWithNumber:counter];
NSLog(#"%d", [instance getNumber]);
[NSThread sleepForTimeInterval:0.01];
instance = nil;
counter++;
}
}
-(ClassB*) makeClassBWithNumber:(int)number {
return [[ClassB alloc] initWithNumber:number];
}
#end
ClassB.h
#interface ClassB : NSObject
#property int number;
-(id)initWithNumber:(int)number;
-(int)getNumber;
#end
ClassB.m
#import "ClassB.h"
#implementation ClassB
-(id)initWithNumber:(int)number {
self = [super init];
if(self) {
_number = number;
}
return self;
}
-(int)getNumber {
return [self number];
}
#end
ClassB is created in view controller and method runSomething is called. This sample code produces that created object (ClassB) is never released from memory. If I change code from
ClassB *instance = [self makeClassBWithNumber:counter];
to
ClassB *instance = [[ClassB alloc] initWithNumber:counter];
created object is properly released in each of loop cycle. What is the reason for such behaviour? I found some old answers here on stackoverflow that makeClassBWithNumber should return result invoking autorelease return [result autorelease], but this can't be done if ARC is enabled.
The difference is that +alloc returns an object with a +1 retain, which ARC will balance with a release at the end of its scope, and so immediately deallocate. +make… returns an object with a +1 retain and a matching autorelease. The autorelease pool will send a release message when it drains. Since you stay in loop "while true," the autorelease pool never drains and you accumulate memory.
The solution is to give your loop an autorelease pool:
while (true) {
#autoreleasepool { // <== Add an autorelease block here.
ClassB *instance = [self makeClassBWithNumber:counter];
//NSLog(#"%d", [instance getNumber]);
NSLog(#"%d", [instance number]); // Fix naming; do not prefix accessors with `get`
[NSThread sleepForTimeInterval:0.01];
// instance = nil; // Does nothing in this loop.
counter++;
}
}
This will cause the pool to drain on every iteration. In any case the instance=nil is unnecessary.
EDIT: Do read MartinR's answer. It gives some more details on the implementation details, and particularly why this may behave differently depending on the optimization level, and whether the called method is in the same compile unit (.m file) as the calling method. That is only an optimization detail; you still need to put this #autoreleasepool in the loop for correctness.
makeClassBWithNumber returns an autoreleased object, even with ARC.
(More precisely, it can return an autoreleased object, depending on the optimization.)
The difference to manual reference counting is that the ARC compiler inserts the autorelease call where required, not you.
From the Clang/ARC documentation:
3.2.3 Unretained return values
A method or function which returns a retainable object type but does
not return a retained value must ensure that the object is still valid
across the return boundary.
When returning from such a function or method, ARC retains the value
at the point of evaluation of the return statement, then leaves all
local scopes, and then balances out the retain while ensuring that the
value lives across the call boundary.
In the worst case, this may involve an autorelease, but callers must not assume that the value is
actually in the autorelease pool.
makeClassBWithNumber is not a alloc, copy, init, mutableCopy, or new
method and therefore returns an unretained return value.
The operative word in your question is "OLD". Old answers are no longer relevant.
This is what ARC is for.
You no longer need to worry about any memory management.
If ARC tells you not to do it... don't.
In this case, you don't need autorelease.
As others have said the difference you are seeing is down to whether a method returns and object the caller owns or an object the caller does not own.
In the former category are methods in the alloc, init, new, copy & mutableCopy categories. These all return an object owned by the caller and ARC will ensure it is released.
In the latter category are all the methods not in the first! These return an object which is not owned by the caller, ARC will ensure that this object is retained if needed and released if it was retained. Return values in this category may be in the auto-release pool, which means they will live at least as long as they are in the pool (maybe longer if they've been retained by ARC) and the standard pool is emptied at the end of each run loop cycle. This means that in loops which generate a lot of entries into the auto-release pool that a lot of no longer needed objects can accumulate in the pool - this is what you are seeing.
Under MRC the solution was to introduce a local auto-release pool, within such loops, to avoid accumulation of no longer needed objects. However under ARC this is probably not the best choice.
Under ARC the better solution is probably to follow the naming conventions, and in this case you want to use the new pattern - new is the standard pattern for alloc + init in one method. So rename your makeClassBWithNumber as newClassBWithNumber:
// *create* a new ClassB object
- (ClassB *) newClassBWithNumber:(int)number
{
return [[ClassB alloc] initWithNumber:number];
}
This indicates the method returns an object the caller owns, it is a "creation" method, and ARC will handle the rest without no longer objects accumulating.
(Adding a newWithNumber method to ClassB itself is often a good idea under ARC.)

How to force release on iOS

I'm new to ARC but understand how it works and I'm trying it out. I'm on iOS so memory is a severe concern.
I have a MyObject class which contains lots of big data. I want to release it, and load a new set of data.
MyObject *object;
object = [[MyObject alloc] initWithData:folder1]; // load data from folder1
// later...
object = [[MyObject alloc] initWithData:folder2]; // load data from folder2
This works fine without leaks, and I'm guessing the ARC inserts a [object release] before the new assignment. My problem is the data inside 'object' is released after the new set is allocated, and I run out of memory. What I really want to be able to do is:
object = nil;
<function to pop the pool, wait till everything is deallocated>
object = [MyObject alloc] initWithData:folder2]; // load data from folder2
but I'm not sure how to do that. I could run the new allocation on a performselector afterdelay, but it feels like I'm shooting in the dark and a bit of hack. There's probably a proper way to do this?
P.S I've tried searching for an answer, but all results are about memory leaks and how to make sure variables go out of scope and set variables to nil etc. My issue isn't about that, it's more of a timing thing.
UPDATE
Thanks for the answers, I'd already tried
object = nil;
object = [MyObject alloc] initWithData:folder2];
and it hadn't worked. I wasn't sure whether it was supposed to or not. Now I understand that it is supposed to work, but I must have something else holding on to it for that fraction of a second. I have NSLogs in all of my init/dealloc methods, and I can see first all the inits of the new instances of classes (of MyObject's ivars) being called, and then almost immediately after (within a few ms), the dealloc of MyObject, followed by the deallocs of its ivars.
I also tried the #autorelease but the same thing happens.
I've searched throughout the project and pasted all the code which I think may be relevant to this.
#interface AppDelegate : UIResponder <UIApplicationDelegate>;
#property PBSoundSession *soundSession;
#end
//--------------------------------------------------------------
#implementation AppDelegate
// onTimer fired at 60Hz
-(void)onTimer:(NSTimer *) theTimer {
[oscReceiver readIncoming]; // check incoming OSC messages
// then do a bunch of stuff with _soundSession;
}
#end
//--------------------------------------------------------------
#implementation OscReceiver
-(void)readIncoming {
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
// parse all incoming messages
if(bLoadNewSoundBank) {
NSString *newFolder = parseNewFolder();
appDelegate.soundSession = nil;
appDelegate.soundSession = [MyObject alloc] initWithData:newFolder];
}
}
#end
//--------------------------------------------------------------
#implementation GuiController
// onTimer fired at 10Hz
-(void)onTimer:(NSTimer *) theTimer {
PBSoundSession *soundSession = appDelegate.soundSession;
// update gui with received values
}
#end
I thought it might be the 'soundSession' local variable in the GuiController::onTimer holding onto the old appDelegate.soundSession for the duration of that method, but to my surprise commenting out all of the GUI code (in fact disabling the timer), made no difference.
Is there a way of finding out at that point who is still holding onto my appDelegate.soundSession? I placed a breakpoint where I set it to nil, but couldn't find any useful information. I tried Instruments in Allocation template, but couldn't find anything useful there either (probably because I don't know where to look).
This is what my allocations track looks like, you can see the memory is all deallocated a bit too late!
.
This might not be an an ARC problem. What you could be seeing is your autorelease pool not draining soon enough—your MyObject is getting released, but the data it loaded is getting held onto by the pool because of some internal -retain/-autorelease pair. Try wrapping your -initWithData: calls in an #autoreleasepool block, like this:
#autoreleasepool {
object = [[MyObject alloc] initWithData:folder1];
// do things
}
// later…
#autoreleasepool {
object = [[MyObject alloc] initWitData:folder2];
// do other things
}
Setting the object to nil immediately before setting it to something else as Gabriele suggests might cause the compiler to insert the appropriate release before the second -alloc/-initWithData:, but it might be smart enough to do that already—if that doesn’t work, it’s most likely the autorelease-pool thing.
There is no delay when draining an #autoreleasepool {...}; the objects in the pool have release invoked immediately. If an object survives that, it is because there is either a strong reference elsewhere or because the object was autoreleased into the next pool out.
If you do:
a = [[Foo alloc] initBigThing];
a = nil;
a = [[Foo alloc] initBigThing];
The first instance of Foo will be released prior to the allocation of the second
With one big caveat; if any of the code paths that a is invoked upon happen to retain/autorelease it, then it'll stick around until the pool is drained. Surrounding it in #autoreleasepool{ ... }; should do the trick.
Note that the compiler will sometimes emit retain/autorelease sequences in non-optimized builds that are eliminated in optimized builds.
A bit more general answer, I found how you can force release an object:
#import <objc/message.h>
// ---
while ([[object valueForKey:#"retainCount"] integerValue] > 1) {
objc_msgSend(object, NSSelectorFromString(#"release"));
}
objc_msgSend(object, NSSelectorFromString(#"release"));
But you shouldn't do this because ARC will probably release the object later and this will cause a crash. This method should be only used in debug!

Recursive block gets deallocated too early

I have written a recursive block following these guidelines:
NSMutableArray *groups = [NSMutableArray arrayWithArray:#[#"group1", #"group2", #"group3", #"group4"];
__block CommunicationCompletionHandler completion = [^{
[groups removeObjectAtIndex:0];
if ([groups count] > 0) {
// This will send some information to the network, and calls the completion handler when it receives a response
[mySocket saveGroup:groups[0] completion:completion];
}
} copy]; // Removing copy here doesn't work either
[mySocket saveGroup:groups[0] completion:completion];
In the saveGroup:completion: method, I add the completion handler to an array:
self.completionHandlers[SaveGroupCompletionHandlerKey] = [completion copy];
And when I receive a response, I call the following method (key is in this case SaveGroupCompletionHandlerKey):
- (void)performCompletionHandlerForKey:(NSString *)key {
if (self.completionHandlers[key]) {
((CommunicationCompletionHandler)self.completionHandlers[key])();
[self.completionHandlers removeObjectForKey:key];
}
}
The problem is that the completion handler only gets called once. The removeObjectForKey: line makes the block deallocate. If I uncomment that line, everything works fine. I'm not sure how the array has the last reference to this block, since I add a copy (which I believe is being optimized to a retain).
For clarity, the flow of the app is:
Send data for first group over network
Receive response
Call completion handler
In the completion handler, send data for next group (this is the recursive part).
Anybody here who can point out what I'm doing wrong?
In -performCompletionHandlerForKey: you remove the completion handler from your dictionary after executing the block, which means that the handler will always be removed from the dictionary after one run.
Instead, store the block in a temporary variable and remove it from the dictionary before executing the block.
By the way, the advice to remove the weak reference is wrong. As your code is written now, your block will never be deallocated. The typical block recursion pattern is this:
__weak __block MyBlock weakHandler;
MyBlock handler = ^ {
if (foo) {
MyBlock strongHandler = weakHandler;
[bar asyncOperationWithCompletion:strongHandler];
}
};
weakHandler = handler;
[bar asyncOperationWithCompletion:handler];
A popular way to avoid retain retain cycles is to create a weak reference to the object before defining the block, then create a strong reference inside the block and set it to that weak reference. This method is frequently used to avoid strongly capturing self inside of blocks:
- (void)someMethod {
__weak MyType *weakSelf = self;
[self someMethodWithABlockArg:^{
MyType *strongSelf = weakSelf;
[strongSelf someOtherMethod];
}];
}
The strong reference created inside the block prevents the object from being deallocated while the block is running. You can, of course, do the same with any object type.
Edit2: Looks like [someBlock copy] is indeed fine. Have you tried running Analyze on the code? It may be that completion is not yet initialized when it is referred to inside of the block.

Resources