TestObj class is a simple class that has a method doSomethingInBackground in which I send it performSelectorInBackground method to make itself sleep 5 seconds in background thread.
#implementation TestObj
- (void)dealloc
{
NSLog(#"%#, is main thread %u", NSStringFromSelector(_cmd), [NSThread isMainThread]) ;
}
- (void)doSomethingInBackground
{
[self performSelectorInBackground:#selector(backgroundWork) withObject:nil] ;
}
- (void)backgroundWork
{
sleep(5) ;
}
#end
I alloc and init the instance and send it doSomethingInBackground message and assign nil to it in order to release it as soon as possible.
TestObj *obj = [[TestObj alloc] init] ;
[obj doSomethingInBackground] ;
obj = nil ;
I find that the dealloc will run after about 5 seconds obj = nil;, it seems that system retains self when send it the method [self performSelectorInBackground:#selector(backgroundWork) withObject:nil] ; and after backgroundWork returned, the instance will be deallocated.
Can anyone tell me the works that system do behind this. Thanks.
-[NSObject performSelectorInBackground:withObject:] under the hood calls -[NSThread initWithTarget:selector:object:] which does retain the original receiver (here passed as target parameter)
NSThread documentation: "The objects target and argument are retained during the execution of the detached thread. They are released when the thread finally exits."
From the Docs,
The performSelectorInBackground:withObject: method creates a new detached thread and uses the specified method as the entry point for the new thread. For example, if you have some object (represented by the variable myObj) and that object has a method called doSomething that you want to run in a background thread, you could use the following code to do that:
[myObj performSelectorInBackground:#selector(doSomething) withObject:nil];
The effect of calling this method is the same as if you called the detachNewThreadSelector:toTarget:withObject: method of NSThread with the current object, selector, and parameter object as parameters. The new thread is spawned immediately using the default configuration and begins running.
In the detachNewThreadSelector:toTarget:withObject: documentation,
The objects aTarget and anArgument are retained during the execution
of the detached thread, then released. The detached thread is exited
(using the exit class method) as soon as aTarget has completed
executing the aSelector method.
Regarding the performSelector:AfterDelay: ,
This method sets up a timer to perform the aSelector message on the
current thread’s run loop. The timer is configured to run in the
default mode (NSDefaultRunLoopMode). When the timer fires, the thread
attempts to dequeue the message from the run loop and perform the
selector. It succeeds if the run loop is running and in the default
mode; otherwise, the timer waits until the run loop is in the default
mode
And
The timer maintains a strong reference to this object until it (the
timer) is invalidated.
If you do not want your Obj to be retained, you can use a weak referenced object,
TestObj *obj = [[TestObj alloc] init] ;
__weak typeof(obj) weakObj = obj;
[weakObj doSomethingInBackground] ;
obj = nil ;
While special cases like performSelector: have been discussed in other answers I think it's helpful to add the answer to the general case:
Will self be retained when send message to it
No. In both manual retain count and ARC self is never implicitly retained. You must take care that the receiver of a message is not deallocated during method execution.
While under ARC self's type is strong the object is not actually retained. See the ARC documentation.
Related
I have a viewcontroller class and another class of NSObject. I call from the viewcontroller class with the following method the NSObject class.
SubmitContentViewController class
#implementation SubmitContentViewController
-(void)viewDidLoad{
[self callUploadQueueClass];
}
-(void)callUploadQueueClass{
UploadQueueClass *queue = [UploadQueueClass new];
[self generateIDforImage];
}
#end
UploadQueueClass
#implementation UploadQueueClass
-(void)generateIDforImage{
#weakify(self)
[[[ApiServicesProvider shared] userService] getCreatorsContentID:^(NSDictionary * _Nullable result, NSError * _Nullable error) {
#strongify(self)
if(nil==error){
NSString* ccID = result.creatorsContentId;
self.creatorsContentID = ccID;
NSLog(#"creatorsContentID %#",self.creatorsContentID);
[self getImageUploadURL:ccID withNumberOfAttempts:10];
}
else{
self.isUploading = NO;
}
}];
}
#end
at this line
NSLog(#"creatorsContentID %#",self.creatorsContentID);
creatorsContentID is null although at this line
self.creatorsContentID = ccID;
ccID is not null so self.creatorsContentID should not be null.
Moreover at this line
[self getImageUploadURL:ccID withNumberOfAttempts:10];
is never get called.
What am i missing?
You are creating your UploadQueueClass instance as a local variable *queue in callUploadQueueClass.
This local variable holds a strong reference to the UploadQueueClass instance.
As soon as the function returns, that local variable is released and it no longer holds the strong reference.
This happens before getCreatorsContentID has completed its work. Before the completion handler block is called.
You have used #weakify so that the self captured by the block does not hold a strong reference to the UploadQueueClass instance. The local variable has been released and the block self doesn't hold a strong reference to the instance. Nothing does, so it is released.
The self in the block is now nil. Using #Strongify won't help you here; the object has already gone away;
In this case you don't need to use #weakify; There is no danger of a circular reference causing a memory leak; The blocks capture of self only lasts until the completion handler has done its work.
However, removing #weakify doesn't seem like it would really help since there doesn't seem to be any way for the UploadQueueClass instance to communicate its results back to the calling view controller.
It would be more typical for the view controller to provide the completion handler block to the function it is calling, or at least provide some block to be executed. This is where you could use #weakify since the view controller instance would be self, but the block doesn't need to hold a strong reference to it to keep it around; The view controller hierarchy is doing that.
Since you don't want this object to report back to the view controller, simply remove the #weakify/#strongify. Then the block itself will hold a strong reference to the UploadQueueClass instance until it returns and then the object will be released by ARC.
I call a heartBeats method per 10ms in a specific thread(not main thread), how to call another method at any time in this same thread?
I subclass NSThread like this
#implementation MyThread
{
NSTimeInterval _lastTimeInterval;
}
- (void)main
{
while (true) {
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970]*1000;
if (timeInterval - _lastTimeInterval > 10)
{
[self heartBeats];
_lastTimeInterval = timeInterval;
}
}
}
- (void)heartBeats
{
NSLog(#"heart beats thread: %#", [NSThread currentThread].description);
}
#end
and run it like this
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"main thread: %#", [NSThread currentThread].description);
MyThread *myThread = [[MyThread alloc]init];
[myThread start];
}
- (void)someMethod
{
// do somthing
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Now,here is the question, how to run - (void)someMethod in myThread?
The main method of your NSThread subclass is everything that runs on that thread. You cannot interrupt it to run other code without the main method's cooperation.
What you really should do is throw out that entire loop and replace it with NSRunLoop and NSTimer.
NSRunLoop keeps the thread alive as long as there's something it will need to do, but also sleeps the thread until it needs to do something.
NSTimer does something on a repeating interval as long as it's scheduled on a run loop.
You need your thread to do two things:
send the MyThread object a heartBeats message (you're doing this)
send the view controller a someMethod message (this is what you asked about)
For the latter, you need one additional thing: A run loop source.
So, clear out your main method and replace it with the following:
Get the current NSRunLoop and store it in a local variable.
Create an NSTimer with a 10-second interval, whose target is self and selector is heartBeats. (Slightly cleaner version: Have another method that takes an NSTimer *but ignores it, so your timer calls that method and that method calls heartBeats. The proper way to set up a timer is to give it a method that expects to be called with a timer, but, in practice, giving it a method that takes no arguments works, too.)
If you didn't create the timer using scheduledTimerWith…, add it to the run loop. (The scheduledTimerWith… methods do this for you.)
Create a run loop source and add it to the run loop.
Call [myRunLoop run].
Step 4 bears explaining:
Core Foundation (but not Foundation; I don't know why) has something called “run loop sources”, which are custom objects that can be added to a run loop and will call something once signaled.
Sounds like what you want, to call your view controller method!
First, in the view controller, change myThread from a local variable in viewDidLoad to an instance variable. Rename it _myThread to make that clear.
Next, add a delegate property to MyThread. This should be weak and have type id <MyThreadDelegate>. You'll also need to define a MyThreadDelegate protocol, which should have one method taking no arguments and returning nothing (void).
You should now be able to set _myThread.delegate = self from the view controller, and implement in the view controller the method that you declared in the protocol. The view controller is now the delegate of its MyThread.
In -[MyThread main], create a version-0 CFRunLoopSource. The Create function takes a “context” structure, containing, among other things, the version (0), an “info” pointer (set this to self, i.e., the MyThread) and a Perform callback (a function, which will be called with the info pointer as its only argument).
In your perform callback, you'll need to do something like this:
MyThread *self = (__bridge MyThread *)info;
[self fireDelegateMessage];
In MyThread, implement that fireDelegateMessage method. In there, send self.delegate the message you declared in your protocol.
Next, add a public method to MyThread (i.e., declare it in MyThread.h as well as implementing it in MyThread.m) named something like “requestDelegateMessage”. In this method, call CFRunLoopSourceSignal on the run loop source. (The documentation for that function suggests that you also need to call CFRunLoopWakeUp on the thread's CFRunLoop. Try it without first.)
Lastly, when the view controller wants someMethod to be called on that thread, call [_myThread requestDelegateMessage].
So:
the view controller calls requestDelegateMessage
requestDelegateMessage signals the run loop source (and wakes up the run loop, if that is needed)
the run loop source calls the perform callback on the MyThread's thread
the perform callback calls fireDelegateMessage on the MyThread's thread
fireDelegateMessage calls the view controller's implementation of the delegate method on the MyThread's thread
the view controller calls someMethod on the MyThread's thread
I have a block retain cycle question,
suppose I have the following 3 methods, all in one class.
- (void)foo1WithBlock:(void (^)(BOOL success))completion
// do something...
completion(YES)
}
- (void)foo2 {
// do something...
}
- (void)foo3 {
[self foo1WithBlock:^(BOOL success) {
[self foo2];
}];
}
Will foo3 create a retain cycle?
No, there is no retain cycle.
However, self will be captured. This means, self will be imported into the lexical scope of the compound statement (the statements executed by the block). This involves making a copy of the "outside" variable self which creates the block's variable self.
A block can be copied and released. A block_copy operation will "move" the captured variables onto the heap. They exists there until the block gets destroyed via block_release operation. The compiler/runtime provides internal functions to copy and release a block and performs them when required. For example, if the block is executed asynchronously via dispatch_async() the block will have to be copied first, and later when the block is finished, released again. These block_copy and block_release operations are inserted by the compiler and executed by the runtime, so don't worry.
If the block will be copied, as an effect self will be retained, and released again when the block gets released - which happens when the block has been finished.
In effect, this guarantees that self within the block and during the life-time of the block is valid (that is, it won't get deallocated), whether it is called synchronously or asynchronously. When the block has been executed asynchronously, the block has been copied, and thus self has been retained. And self will be only released again until after the block finishes. This also means, that the block "will" extend the life time of self until after the block finishes.
No, there will no retain cycle..as you are not calling each other method here.
- (void)foo3 {
[self foo1WithBlock:^(BOOL success) {
[self foo2];
}];
}
In this case, if you don't understand the lifetime of the block you are passing to foo1WithBlock: it is probably a good idea to use this idiom to prevent a the block from inappropriately extending the lifetime of self.
- (void)foo3 {
__weak ParentType *wself = self; //create a weak reference (weak automatically gets set to nil on dealloc)
[self foo1WithBlock:^(BOOL success) {
ParentType *self = wself; //create a local strong reference for the life of the block.
[self foo2];
}];
}
if you are using cocoapods libextobjc has a EXTScope which provides helper macros for this:
- (void)foo3 {
#weakify(self);
[self foo1WithBlock:^(BOOL success) {
#strongify(self);
[self foo2];
}];
}
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.
Mike Ash has written this introduction to ARC where he introduces something like:
__weak Foo *_weakFoo = [object foo];
Why would I want to do that for a local, temporary variable? __weak is a zeroing reference which will set the _weakFoo pointer automatically to nil as soon as the referenced object gets deallocated. Also, __weak is only available in iOS >= 5.
When would I run into trouble when I simply do this?:
Foo *_weakFoo = [object foo];
This is always expected to return an object or nil. My guess is this:
Foo *_weakFoo = [object foo];
[self doSomethingStupid]; // does something bad so foo gets deallocated
[_weakFoo doIt]; // CRASH! msg sent to deallocated instance 0x123456
One thing that still bugs me with ARC is: When does it know that I don't need an object anymore? I'd argue that when I set a pointer to nil or to something else it figures out that the previously referenced object isn't needed by this owner anymore and therefore maybe can go away. But the point is: I set it to nil. So it's nil anyways!
So when would __weak for a local variable make sense, and what kind of crazy thing must I do somewhere else so that I really need that?
I use __weak local variables if I have to manipulate self inside of a block to avoid a retain cycle. Consider this example where I'm using GCD and blocks to perform a network request for a string, and then setting it on a label declared by the class, in this case, TurtlesViewController.
__weak TurtlesViewController *weakSelf = self;
dispatch_queue_t networkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(networkQueue, ^{
// Kick off a network task for some data that is going to populate a label declared on our class
NSString *returnString = [networkDataSource retrieveTurtleTime];
// Dispatch back to the main thread to populate the UILabel
dispatch_async(dispatch_get_main_queue(), ^{
// Using self.label here creates a retain cycle. Self owns the block and the block has captured self
self.label.text = returnString;
// Instead, we use weakSelf for our reference to the label as it will be torn down by ARC at the end of the loop.
weakSelf.label.text = returnString;
});
});