MCSession takes a long time to dealloc - ios

I'm using Multipeer-Connectivity.
When the session ends, the app comes to the main menu and all network stuff is released then deallocated.
But my dealloc method is called in main thread and the MCSession object takes a very long time to release itself, I don't know why, and consequently the main menu screen freezes.
If somebody know why MCSession could be so long, I'm interested. But if it comes from the MCSession itself, is it a good solution to do this?
-(void) dealloc
{
//... other release
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[_session release];
_session = nil;
});
[super dealloc];
}
EDIT: nope, it's definitely not a good solution, because it makes my app crashing. Anyway, other ideas?

When you call [_session release] since _session is an Ivar, the compiler will replace this line by [self->_session release] and the block will retain self instead of the iVar _session.
Here you have 2 problems:
Trying to retain an object(self) which are deallocating.
When the queue will be executed, it'll call self which is already deallocated.
The following solution create a local variable which point to the same address as the iVar and release it inside the block, the block will not capture self.
-(void) dealloc
{
//... other release
MCSession* localSession = _session;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[localSession release];
});
[super dealloc];
}

bsarr007's solution will work for non-ARC projects. If you are using ARC, you can try this:
__block MCSession *localSession = _session;
_session = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
oldSession = nil;
});
It works for me. What I am doing here is increasing reference count of MCSession object by creating new local variable that points to that object, so it won't be deallocated immediately when setting _session = nil. After that I am running asynchronously the code that decreasing reference counter of my MCSession object using background queue.

Related

why this RACObserve block caused retain cycle?

Consider I in my view controller, I added RACObserve of property of Singleton, and inside subscribNext I have a self reference in it.
The code is as below:
[RACObserve([Singleton shared], singletonFlag) subscribeNext:^(NSNumber *singletonFlag) {
self.flag = [singletonFlag boolValue];
}];
Based on my understanding, self don't hold a strong reference of the block(while block hold a strong reference of self), this shouldn't cause retain cycle.
I have read memory management of reactive cocoa as well https://github.com/ReactiveCocoa/ReactiveCocoa/blob/master/Documentation/Legacy/MemoryManagement.md
In which they provide an example as
[RACObserve(self, username) subscribeNext:^(NSString *username) {
[self validateUsername];
}];
I totally understand why it caused the retain cycle in above case and we need a weak self inside the block.
I am confused why in the first case, it will cause a retain cycle. To confirm this, just paste that code snippet after viewDidLoad and see whether the view controller was dealloc-ed when it should be.
If you need see more implementations of the singleton, this is the code,
#interface Singleton : NSObject
#property (readwrite,nonatomic) BOOL singletonFlag;
#end
#implementation Singleton
+ (Singleton *)shared {
static dispatch_once_t pred = 0;
__strong static id _sharedObject = nil;
dispatch_once(&pred, ^{
_sharedObject = [[self alloc] init];
});
return _sharedObject;
}
- (id)init {
if (self = [super init]) {
NSLog(#"init of %#",NSStringFromClass(self.class));
}
return self;
}
#end
Anyone enlighten me about this?
The internal implementation is quite complicated, It's not important whether there is a real retain cycle.
Here the reason why memory leaks is just the same in your two examples:
self is retained by the block
The block is retained by an internal subscriber object
The subscriber is retained by some internal thing of the RACObserve signal until the signal terminates.
The RACObserve signal terminates when either the target (the singleton instance) or self (the RACObserve micro is implicitly using self) is deallocated.
But now the singleton instance won't dealloc, and self won't dealloc neither since it's already retained. So the signal never terminates, then memory leaks.
Anyway, you shouldn't write such things as
[RACObserve([Singleton shared], singletonFlag) subscribeNext:^(NSNumber *singletonFlag) {
self.flag = [singletonFlag boolValue];
}];
Instead, write
RAC(self, flag) = RACObserve([Singleton shared], singletonFlag);
The problem is that RACObserve() will return you a RACDisposable object, that you have to dispose your self. If you use it the way RAC()=RACObserve(), then the RAC() part will take care of killing the RACDisposable object that is returned by RACObserve() method.
One quick fix that you can make when using the RACObserver like this:
[RACObserve(self, username) subscribeNext:^(NSString *username) {
[self validateUsername];
}];
Is to turn it into this:
(RACDisposable *disposableSignal; declared in .h for example)
disposableSignal=[RACObserve(self, username) subscribeNext:^(NSString *username) {
[self validateUsername];
}];
And use [disposableSignal dispose] to deallocate the signal. For example in viewWillDisappear method. Basically you have to kill it with dispose method to get rid of it.

captured self gets released inside a dispatch_async

I am experiencing an EXC_BAD_ACCESS error inside my app within a block that, as of my understanding, should actually capture everything involved in this, making it impossible that it is released inside the block. (ARC is enabled)
Here is my code:
- (void)_perform_async_onqueue:(void (^)(void))task {
dispatch_async(self.workerQueue, task);
}
- (void)cancel {
[self _perform_async_onqueue:^{
// operation is strongly retained by self.
// operation is also retained by an operation queue.
// within `cancel` the operation is released from the operation queue
[self.operation cancel];
}
}];
This crashes inside [self.operation cancel]. self.operation is a subclass of NSOperation. The operation's cancel method in detail:
- (void)cancel {
[self willChangeValueForKey:#"isCancelled"];
_cancelled = YES;
[self didChangeValueForKey:#"isCancelled"];
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_finished = YES;
_executing = NO;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"]; // CRASH (debugger lists `self` [= the operation] as `nil` in this line
}
As of my understanding, the first self should be retained inside the dispatched block. As self has a strong reference to operation, this should also be in memory until the end of the block execution. How can this lead to a EXC_BAD_ACCESS crash?
EDIT :
Don't implement cancel method in your NSOperation subclass. Just call :
[self.operation cancel];
A good tuto here
Methods don't have strong references to self. If self is deallocated while a method is being called, you are on your own. (That's why you get a warning if you call a method on a weak object, because the object might go away while the method is running).
You can assign SomeClass* myself = self; and that will keep self alive until the end of the method.
You can also implement your own dealloc (which just calls [super dealloc] automatically) and set a breakpoint to find out when exactly self is deallocated, to understand things better.
I've found the issue:
It turns out that the described behaviour is working totally fine. The issue is that the NSOperation that is used here is a custom, asynchronous operation that has implemented cancel in the wrong way: If you cancel an operation before it has been started by the NSOperationQueue the operation queue then overreleases the operation. This is the reason for the operation being deallocated even if there is still a strong reference that should hold it.
I'll go file a rdar for that.

ios using release in an async block

I have an IOS project (ARC disabled) which has several view controllers. One particular controller initialises a member object of type MyClass, however when the view controller is dismissed, I'm calling a cleanup method for the object which uses a thread (using dispatch-async) to make some time consuming operations and then when these operations are done im executing a [self release] on the main queue for the object. Is this a good practise, will it cause any errors? Below is a similar example to what im doing:
#implementation ViewController
- (void)viewDidLoad
{
myObj = [[MyClass alloc] init];
}
-(void)viewWillDisappear
{
[myObj cleanup];
}
#end
//myClass
#implementation MyClass
- (void)cleanup()
{
dispatch_queue_t myQueue = dispatch_queue_create ("MyClassDeallocQueue", NULL);
dispatch_async(myQueue, ^{
//time consuming operations
dispatch_async(dispatch_get_main_queue(), ^{
[self release];
});
});
}
#end
Is this a good practise, will it cause any errors?
Currently, your code has an unbalanced retain/release. That is definitely an error (over release).
"Is it good practice?" - well, I don't know what you are trying to accomplish. But if your goal is to keep self alive, until after the block is executed, it is already accomplished purely through the fact that self will be captured. So, strictly a release is not needed.
However, if you NOT explicitly release self on the main thread, you introduce a subtle bug: it might happen that the block has the last reference to self, and since it may execute on some arbitrary thread, it will release self on this non-main thread. And this is forbidden: UIKit methods (including dealloc) MUST be called on the main thread!
Thus, it might make sense:
[self retain];
dispatch_async(myQueue, ^{
// time consuming operation, which captures `self`
[self doSomething];
...
// ensure that `dealloc` will be executed on the main thread, if
// last reference is held by the block:
dispatch_async(dispatch_get_main_queue(), ^{
[self release];
});
});
or shorter:
dispatch_async(myQueue, ^{
// time consuming operation, which captures `self`
[self doSomething];
...
// ensure that `dealloc` will be executed on the main thread, if
// last reference is held by the block:
dispatch_async(dispatch_get_main_queue(), ^{
[self self];
});
});
Edit:
It's an interesting question, whether the "short" version is actually tread-safe or has a race:
Suppose, self will be released in the block executed on myQueue, as the effect of capturing self before it will be retained in the same bock as an effect of capturing self for the block executed on the main queue. Then, we have an issue. Comments appreciated.

Memory management with blocks when class object is released

Assuming an example block as shown below executed.
[testBlock testPerformWithBlock:^(BOOL finished) {
if (finished) {
self.textField.text = #"Finished";
NSLog(#"Edited to add an textfield update inside block");
}
}];
What will happen if I pop the view controller that contains the object testBlock before the block returns the value of BOOL. Will the objects get deallocated properly?
Everything inside a block is retained until the block is released from memory. If the object testBlock is still executing testPerformWithBlock and the block is still alive, then everything inside the block is retained.
You are only doing an NSLog in there, so nothing will change.
However, if you do this:
if (finished) {
[self doSomething];
}
self is being used, and it will be retained, so take some caution if you are storing the blocks in some ivar somewhere
I don't understand what you are asking. There is no problem with memory management in your example. If you did not explicitly retain something, you do not need to explicitly release it.
You will get warning that strongly capturing self inside block will lead to retain cycle it will not crash but its not proper you need to do as they say strong weak dance.You can do this.
__weak typeof(self)ref=self;
^(<your bock>){
__strong typeof(ref)strongSelf=ref;
if(strongSelf)//or if(!strongSelf)return;
{
[strongSelf-><variable> methodCall];
}
};
There will be no deallocated error.
Though the retainCount of "testBlock" will not change after the invocation, the block will not be released before it runs to the end.
The result is that program will run perfectly no matters "testBlock" dealloc or not.
The sample codes following:
- (void)lazyFetchingImage:(void (^)(void))finishBlock {
[[NSOperationQueue mainQueue] addOperationWithBlock:finishBlock];
}
MainVCAppDelegate *dd = [MainVCAppDelegate new];
NSLog(#"count==%i",[dd retainCount]);
[dd lazyFetchingImage:^{
NSLog(#"22");
}];
NSLog(#"count==%i",[dd retainCount]);
[dd release];
The out put should be :
count==1
count==1
22

How to set up proper object teardown when using GCD and calling back to main thread?

Consider this setup:
Object A creates object B for doing some work, and sets itself as B's delegate to be informed of work progress.
B does some work with GCD blocks, and signals back to A with the delegate method about work completion. A wants to tear down (release) B upon work completion.
In code terms:
Object A:
B *b = [[B alloc] init];
b.delegate = self;
[b doSomeWork];
- (void) didSomeWorkFromB:(B *)b {
[b release];
b = nil;
}
Object B:
- (void) doSomeWork {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
doSomeWork();
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Work is complete.");
[self.delegate didSomeWorkFromB:self];
});
});
}
PROBLEM: calling [b release] inside object A causes a crash. I think it's because the dispatch queue/background code is still running when A tries to release B.
QUESTION: how do I properly set up the objects and signaling in this case, to make sure that A only destroys B when all the background work has been completed?
Bogus question. It actually works as expected and the code above does not crash. The crash was caused by some unrelated code.
You are correct, that the code works as is. But it is unnecessarily complicated.
You can just have B's doSomeWork retain itself (either by explicitly calling [self retain] and [self release] in doSomeWork or just by referencing self in the dispatch_async block, which will retain it for us), and let A clean up immediately after the invocation of doSomeWork, and therefore no further cleanup is required in didSomeWorkFromB.
This pattern is very common in iOS. For example, if you look at many common implementations of NSURLConnection, since it retains itself while the connection is downloading, and releases itself once the connection is done, we often don't both keeping a reference to the connection and cleaning it up in connectionDidFinishLoading. Just let the magic of reference counting memory management take care of everything for you.
In A:
- (void) test
{
B *b = [[B alloc] init];
b.delegate = self;
[b doSomeWork];
[b release]; // you could also autorelease above, but I just wanted to make it more explicit for the purposes of the demonstration
}
- (void) didSomeWorkFromB:(B *)b
{
// [b release]; // don't need to release it ... we already did
// b = nil; // certainly don't need to nil local reference ... this does nothing useful in any scenario
}
In B:
- (void) dealloc
{
// let's log this so we can see when it's deallocated
NSLog(#"%s", __FUNCTION__);
[super dealloc];
}
- (void) doSomeWork
{
// [self retain]; // you could manually retain if you want
NSLog(#"%s", __FUNCTION__);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(10);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Work is complete.");
[self.delegate didSomeWorkFromB:self];
// [self release]; // and if you manually retained, you'd manually release, too
});
});
}
In my opinion, this approach (of having A release B immediately after calling doSomeWork) is more robust, more closely coordinating the balancing cleanup of the object. I also think this puts you in better stead as you contemplate an eventual shift to ARC.

Resources