What is the difference between the two code snippets below:
1.
__block __weak NSMutableArray *arrBlock = self.arr ;
[[AsyncRequest initRequest:url onCompletedBlock:^(NSMutableArray *arr) {
arrBlock = arr;
}]ExecuteRequest];
2.
id __weak weakself = self;
[[AsyncRequest initRequest:url onCompletedBlock:^(NSMutableArray *arr) {
weakself.arr = arr;
}]ExecuteRequest];
Neither of them cause retain cycles, but Apple suggests using the first one. Is there a problem with the second one?
They have different effects. The first updates the local variable and the second updates the instance variable (property).
Which one you want to use depends on what you want to happen, however I suspect you want the second as the first looks like a no-op if that block is executed asynchronously.
Related
I have a class, there's a block proper:
#property(nonatomic, strong) void (^hehe)();
In the init method, I do the following work:
__weak test *weakSelf = self;
self.hehe = ^{
test *self = weakSelf;
NSLog(#"%zd", self.a);
NSLog(#"%zd", self->_a);
NSLog(#"%zd", _a);
};
What is the difference between the last two line in the block.
I thought self->_a is equals to _a.
But the Xcode shows warning on the last line:
Caputuring self strongly in this block is likely to lead a retain cycle
Edit:
I know the local self and the global self is not the same. How the os distinguish the difference. I used clang to rewrite the code, and get the following:
static void __ViewController__init_block_func_0(struct __ViewController__init_block_impl_0 *__cself) {
__Block_byref_weakSelf_0 *weakSelf = __cself->weakSelf; // bound by ref
ViewController *self = (weakSelf->__forwarding->weakSelf);
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gp_6ztdfl3n5919c3y4pb03gd340000gn_T_ViewController_ad5b98_mi_0, ((NSInteger (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("a")));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gp_6ztdfl3n5919c3y4pb03gd340000gn_T_ViewController_ad5b98_mi_1, (*(NSInteger *)((char *)self + OBJC_IVAR_$_ViewController$_a)));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_gp_6ztdfl3n5919c3y4pb03gd340000gn_T_ViewController_ad5b98_mi_2, (*(NSInteger *)((char *)self + OBJC_IVAR_$_ViewController$_a)));
}
The last two line is used the same self...
Because it means a different self. A quick rename will make everything clear :
__weak test *weakSelf = self;
self.hehe = ^{
test *strongSelf = weakSelf;
NSLog(#"%zd", strongSelf.a);
NSLog(#"%zd", strongSelf->_a);
NSLog(#"%zd", _a);
};
Now it is clear, that the last line captures self from outside the block. The way you had it named, made it harder to differentiate between the self that was a local variable declared inside a block, and the self that was captured from outside its scope.
Referring to _a is a direct reference to an instance variable from the enclosing scope. That implicitly captures self. It doesn't invoke the property's getter/setter. It points directly to the instance variable.
Don't do that from inside a block that persists. (An "escaping" block, as Apple has started calling it.) Use the weakSelf/strongSelf syntax #Losiowaty showed in his answer.
I'm trying to get variables and properties in self in a block for actions to complete, but, if I reference self or a global variable in self when self is the object running the block, it warns me of a retain loop. Here's what I'm doing:
I'm adding actions to an NSMutableArray that are of type (void(^)() (in other words, a block returning void with no parameters).
I call it using this syntax later on, where i is an int determined by code (that is in the bounds of the array:
void (^someBlock)() = arrayOfActions[i];
someBlock();
The code works and runs fine, but, because I use properties of self within the block, Xcode warns me of a retain loop. Should I ignore it because it's simply a warning and everything works fine in code (it only executes the block once), or should I do something different?
You should definitely not ignore the warning, but use __weak instead to define a weak reference and eliminate retain cycles as described in the documentation:
__weak SelfType *weakSelf = self;
void (^aBlock)() = ^(){
SelfType *strongSelf = weakSelf;
//User strongSelf
};
Alternatively you can use libextobjc (https://github.com/jspahrsummers/libextobjc) with its convenient #strongify and #weakify annotations.
I am new to blocks in iOS and had a quick question regarding their use. Say I have the following setup:
viewController.rowLabels = #[#"Hello", #"World"];
viewController.testBlock = ^(NSInteger itemIndex) {
// here i want to access another property of the viewController called foo
};
So, as seen above, I want to access another property of the view controller within the block itself. Do i need to do a *__weak -> strong assignment to achieve this or can i simply access it like NSLog(viewController.foo)?
The simple, but possibly problematic answer, is just to access it as you do the other properties:
viewController.rowLabels = #[#"Hello", #"World"];
viewController.testBlock = ^(NSInteger itemIndex) {
... viewController.foo ...
};
From your fragment we cannot know what viewController is - e.g. it could be a local variable from the method this fragment is in or a global variable etc. If you are just reading the value in viewController, as you are here, this does not matter[1].
The above works but there might be a problem: you probably have a strong reference cycle. The viewController instance references the block through it's testBlock property, and the block references the viewController instance. If both these references are strong (likely) then you have a circular dependency and the viewController instance and the block can never be freed by the system. You can break this cycle using a weak reference:
viewController.rowLabels = #[#"Hello", #"World"];
__weak ViewController *weakViewController = viewController; // make a weak reference to the instance
viewController.testBlock = ^(NSInteger itemIndex)
{
// temporarily make a strong reference - will last just as long as the block
// is executing once the block finishes executing the strong reference is
// removed and no strong reference cycle is left.
ViewController *myController = weakViewController;
// only execute if the `ViewController still exists
if (myController != nil)
{
... myController.foo ...
}
};
HTH
[1] note that the value you are reading is a reference to a ViewController instance and you can modify properties of that instance, what you cannot do (and are not trying to do) is modify which instance the viewController references if viewController is a local variable.
Declare a __block variable containing the view controller object, like so:
__block __weak ViewController *blockVC = viewController;
viewController.testBlock = ^(NSInteger itemIndex) {
NSLog(#"%#", blockVC.foo);
};
I've used both __block and __weak since __block is implicitly strong, but adding __weak as a reference can help break the strong reference cycle while still using __block's strong reference to prevent deallocation.
As of iOS 5.0, it seems as if you can just create a __weak reference as opposed to using a __block variable to access a variable and its properties within a block:
__weak ViewController * weakVC = viewController;
viewController.testBlock = ^(NSInteger itemIndex) {
ViewController * strongVC = weakVC;
if (strongVC) {
NSLog(#"%#", strongVC.foo);
}
};
But note that unlike using __weak in combination with the __block storage type, __weak specifies a reference that might not keep the object alive, i.e. may deallocate, so even within the block, weakVC may be nil before you actually need it. (This is why the if (strongVC) conditional is required when just using a __weak variable alone.)
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;
});
});
I have a view controller that I want to lazily initialize, and once initialized, use the same copy when possible (I don't use a singleton since I do want to remove it from memory eventually), I use the getter to do so, my code look like this:
#property (retain) UIViewController *myController
...
#synthesize myController = _myController;
...
- (UIViewController *)myController
{
if (!_myController) { // Evaluation
_myController = [[MyViewController alloc] init]; // Object Creation
}
return _myController;
}
This works, but it's not thread safe, and if more than one thread evaluate to true before the object is created, I'll have a memory leak. One solution I've tried is to #synchronized the code, but I'm not sure the correct way to do it.
This appears to work, (lockForMyController is a simple NSString) but it makes this section of code a lot slower:
- (UIViewController *)myController
{
#synchronized(self.lockForMyController){
if (!_myController) {
_myController = [[MyViewController alloc] init];
}
}
return _myController;
}
I was wondering if there is some other way to achieve a lazy initialized, thread safe, property?
This solution works
Note that this solution only works if myController is accessed on a background thread the first time. It will deadlock if called on the main thread.
You want to use gcd. The key is serialize the creation of the object, so that regardless of the threads starting the block, it will always only be created exactly once.
- (UIViewController *)myController
if (_myController == nil) {
dispatch_sync(dispatch_get_main_queue(), ^ { if (_myController == nil) _myController = [[MyViewController alloc] init]; });
}
return _myController;
}
Here, even if multiple threads execute the block, the execution of the block is serialized onto the main thread and only one MyViewController can ever be created.
You won't see a performance hit here unless the object is nil.
Since the property is implicitly atomic, that means that in the setter the value will be autoreleased. This should make it suitable for mingling with your custom getting, since it will autorelease any value changes to _myController.
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW2
However, you still may get into a race condition where you are setting the value on one thread but accessing it on another. Any time you set the value, you probably want to make sure and do something like this:
dispatch_sync(dispatch_get_main_queue(), ^ { self.myController = {newValueOrNil} });
This will make sure to serialize your setter methods calls without having to reinvent the wheel for atomic setters, which is very hard to get right.
This solution does not work
You want to use gcd.
http://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_once
See this post about singletons. I know you don't want a singleton, but this demonstrates how to use the method. You can easily adapt it.
Create singleton using GCD's dispatch_once in Objective C