Block recursion and breaking retain cycle - ios

To better illustrate the question, consider the following simplified form of block recursion:
__block void (^next)(int) = ^(int index) {
if (index == 3) {
return;
}
int i = index;
next(++i);
};
next(0);
XCode (ARC-enabled) warns that "Capturing 'next' strongly in this block is likely to lead to a retain cycle".
Agreed.
Question 1: Would the retain cycle be successfully broken by setting the block itself to nil, in this fashion:
__block void (^next)(int) = ^(int index) {
if (index == 3) {
next = nil; // break the retain cycle
return;
}
int i = index;
next(++i);
};
next(0);
(Note: you'd still get the same warning, but perhaps it is unwarranted)
Question 2: What would be a better implementation of block recursion?
Thanks.

To accomplish the retain-cycle-free recursive block execution, you need to use two block references - one weak and one strong. So for your case, this is what the code could look like:
__block __weak void (^weak_next)(int);
void (^next)(int);
weak_next = next = ^(int index) {
if (index == 3) {
return;
}
int i = index;
weak_next(++i);
};
next(0);
Note that the block captures the weak block reference (weak_next), and the external context captures the strong reference (next) to keep the block around. Both references point to the same block.
See https://stackoverflow.com/a/19905407/1956124 for another example of this pattern, which also uses block recursion. In addition, the discussion in the comments section of the following article is relevant here as well: http://ddeville.me/2011/10/recursive-blocks-objc/

I think #newacct is correct about #Matt Wilding's solution; it does seem that nothing will have a strong ref to the next block in that case and will result in a run time exception when run (at least it did for me).
I don't know how common it is to find recursively called blocks in the wild in objc. However, in a real world implementation (if actually required) on say, a view controller, one might define the block and then set up an internal interface property with a strong reference to said block:
typedef void(^PushButtonBlock)();
#interface ViewController ()
#property (strong, nonatomic) PushButtonBlock pushButton;
#end
#implementation ViewController
...
// (in viewDidLoad or some such)
__weak ViewController *weakSelf = self;
self.pushButton = ^() {
[weakSelf.button pushIt];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), weakSelf.pushButton);
};
self.pushButton();
...
#end
This runs fine for me and has no compiler warnings about retain cycles (and no leaks in instruments). But, I think I would probably steer clear of doing this (recursive block calls) in most cases in objc - it's smelly. But interesting in any case.

Related

how to create an autorelease object

Is this method create an autorelease object?
- (instancetype)autoreleasePerson {
return [[Person alloc] init];
}
I created an Command Line Tool Project to test this:
int main(int argc, const char * argv[]) {
#autoreleasepool {
{
[Person autoreleasePerson];
}
NSLog(#"did out scope");
NSLog(#"will out autoreleasepool");
}
NSLog(#"did out autoreleasepool");
return 0;
}
And the output is:
2022-02-04 23:22:23.224298+0800 MyTest[8921:4007144] did out scope
2022-02-04 23:22:23.224771+0800 MyTest[8921:4007144] will out autoreleasepool
2022-02-04 23:22:23.224876+0800 MyTest[8921:4007144] -[Person dealloc]
2022-02-04 23:22:23.224948+0800 MyTest[8921:4007144] did out autoreleasepool
The person instance will dealloc when the autoreleasepool drains!
But when I use the same Person class in my iOS APP project:
- (void)viewDidLoad {
[super viewDidLoad];
{
[Person autoreleasePerson];
}
NSLog(#"out scope");
}
The output is:
2022-02-04 23:28:13.992969+0800 MyAppTest[9023:4011490] -[Person dealloc] <Person: 0x600001fe8ff0>
2022-02-04 23:28:13.993075+0800 MyAppTest[9023:4011490] out scope
The person instance released once out of scope!
Why is this so?
It looks like on macOS the default behaviour is to autorelease return values, except for cases where the method name starts with "new", "init" or "copy":
+ (Person *)createPerson {
return [Person new]; // autorelease & return
}
+ (Person *)newPerson {
return [Person new]; // direct return
}
To control this behaviour apply a compiler attribute:
+ (Person *)createPerson __attribute__((ns_returns_retained)) {
return [Person new]; // direct return
}
+ (Person *)newPerson __attribute__((ns_returns_not_retained)) {
return [Person new]; // autorelease & return
}
To check whether a call to objc_autoreleaseReturnValue was added by the compiler, enable Debug -> Debug Workflow -> Always Show Disassembly,
and put a breakpoint inside these methods on return lines. A call to objc_autoreleaseReturnValue should be visible then:
See ARC reference - Retained return values
Both of the results are valid. You should never assume that there is an autorelease in ARC. See the section "Unretained return values" in the ARC specification:
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.
So maybe it's autoreleased, and maybe not (i.e. maybe ARC optimizes it out).
Here, ARC will call objc_autoreleaseReturnValue() when returning from autoreleasePerson, because +alloc returns a retained reference, but autoreleasePerson returns a non-retained reference. What objc_autoreleaseReturnValue() does is check to see if the result of the return will be passed to objc_retainAutoreleasedReturnValue() in the calling function frame. If so, it can skip both the autorelease in the called function, and the retain in the calling function (since they "cancel out"), and hand off ownership directly into a retained reference in the calling function.
objc_retainAutoreleasedReturnValue() is called when ARC will retain the result of a function call. Now, I don't know why in this case calling [Person autoreleasePerson]; will involve a retain of the result, since the result is unused. Perhaps the compiler is treating it as Person temp = [Person autoreleasePerson];, and thus retains and then releases it. This may seem unnecessary, but it is valid for ARC to do it this way. And if ARC does happen to treat it this way internally, then the optimization described above can skip both the autorelease and retain, and it will be simply released in the calling function. Maybe it's doing this in one of your cases and not the other. Who knows why? But my point is that both are valid.
See this article for a more detailed explanation.

Objective c block in a block

Lot of blocks here!
I am trying to use blocks to perform an operation on each record present in a dictionary.
I created a weak reference of the strongRecordBlock and used that to call itself in the strongRecordBlock. It all worked fine until I introduced my actual operation (DataManager addRecord) that I need to perform which in turn is a block.
So there is an exception now, the weakRecordBlock is null after first iteration of the recursive loop. Can anybody please guide!
__weak __block void (^weakRecordBlock)(int i);
void (^strongRecordBlock)(int) = ^(int i) {
NSString *key = weakSelf.recordDictionary.allKeys[i];
CSVRecord *record = [weakSelf.recordDictionary objectForKey:key];
NSLog(#"%d %#", i, record.recordFullname);
[[DataManager sharedInstance] addRecord:record onSuccess:^(NSString *objectId) {
if (i < weakSelf.recordDictionary.allKeys.count-1) {
weakRecordBlock(i+1);//Crashes here
}
else {
completedBlock();
}
} onError:^(NSError *error) {
onError(error);
}];
};
weakRecordBlock = strongRecordBlock;
strongRecordBlock(0);
The problems is that you are trying to use weak pointer inside of block. And it lead to realising weak point after first run loop.
So you need to create strong reference to the weakRecordBlock inside of strongRecordBlock. So just add this line of code on top of your strongRecordBlock
void (^strongPointerToWeakRecordBlock)(int i) = weakRecordBlock;
and replace weakRecordBlock(i+1) with strongPointerToWeakRecordBlock(i+1)
RomanSalabay's answer is right. The problem is -[DataManager addRecord:record onSuccess:] executes its argument block asynchronously. Therefore, that block (the argument to -[DataManager addRecord:record onSuccess:]) needs to keep a strong reference to the objects and blocks used within, to keep them alive until the block runs; otherwise they can be deallocated by the time that block runs. But it captures a weak reference (weakRecordBlock). It needs to copy a strong reference instead. So you should assign the weak variable to a strong variable in the body of the outer block to let the inner block capture.

EXC_BREAKPOINT: Message sent to deallocated instance

I get the above message in XCode 4.6. I've done a pretty thorough search and but nothing seems to match the exact circumstances surrounding my issue. Admittedly, I'm relatively new to iOS dev, and memory-management has never been my strong suit, but this just has me completely miffed.
I have an instance variable theLink which is defined in the class Game as follows:
#interface Game : NSObject
// Class objects
#property(nonatomic,retain) NSMutableArray *queryItems;
#property(nonatomic,retain) NSMutableArray *theArray;
#property(nonatomic,retain) NSString *theLink;
#property(nonatomic,retain) NSString *thePath;
theLink is set in the makeGame method which is called in the method initialiseGame in my view controller:
- (void) initialiseGame
{
bool gameCreated = FALSE;
while (!gameCreated)
{
gameCreated = [theGame makeGame:#"ptl"];
}
[loadingIndicator stopAnimating];
[loading setText:#"Tap to Start"];
[self performSelector:#selector(setLabels) withObject:nil afterDelay:0.0];
}
(Note: the performSelector afterDelay is used to allow the view to update before continuing. Bit of a hack but I couldn't work out a better way!)
The app then loads the game, and when the user taps the screen to start, the next method which is called from the view controller is:
- (void) setupLink
{
...
for(int i=0; i<[theGame.theLink length]; i++) {
...
}
}
It is on this reference to theGame.theLink where I'm am getting the crash.
What has me most confused is that if I call theGame.theLink from inside the initialiseGame method, it is displays correctly, and also calling any other variable from the Game class (such as thePath or theArray works perfectly, so theGame object has not been deallocated in it's entirety, only the variable theLink.
It seems to me that the variable is being deallocated somewhere as the view controller is being updated. I haven't released the variable, and can't work out why only this variable is being deallocated. As I said at the start, memory-management is not my strength!
Any help/ideas would be hugely appreciated. Let me know if you require any more details.
Thanks heaps,
Andrew
EDIT: Setting of theLink within makeGame
- (bool) makeGame:(NSString*)gameType
{
...
[self getLink];
}
- (void) getLink
{
...
if (... && ((arc4random() % 10) > 8))
{
theLink = #"Animals";
}
}
There are many different ways theLink may be set, depending on random numbers and other factors. This is the most basic form which simply sets it to a static string. It doesn't matter how theLink is set or what it is set to, the program always crashes at the same point.
If theLink is being set to the parameter being passed to it ,#"ptl" or some similar temporary string, it will give you a problem, because it is just a pointer pointing at the current location that is holding #"ptl". After the makeGame method is completed, your system will assume that it is all done with #"ptl" and just free it up.
When you make an #"stringwhatever" in your code, it is supposed to be the equivalent of making an NSObject that is an immutable literal instance of #"stringwhataver". It should, in theory handle all the reference counting in a nice way, but when you are doing your own memory management, there are so many ways to lose count of your references.
There's a pretty simple rule to follow. If you've declared properties, access them via the property. To do otherwise (as you are doing above, with theLink = ...) bypasses all of the memory management built into the property accessors.
self.theLink = ...
Would have solved this problem under MRC. Switching to ARC has "solved" your problem without you understanding the root cause.

Please help me with block-based callbacks

I have an ill-understanding of block-based callbacks. There seems to be two approaches that I'm aware of and I don't know when I should be using one over the other so could someone please explain to me the differences between the two, correct me and give me some tips if I need any.
Some code I found off stackoverflow as well as a library from elsewhere so thanks to those who wrote this code.
typedef void (^MyClickedIndexBlock)(NSInteger index);
#interface YourInterface : YourSuperClass
#property (nonatomic, strong) MyClickedIndexBlock clickedIndexBlock
.m
//where you have to call the block
if (self.clickedIndexBlock != nil) {self.clickedIndexBlock(buttonIndex)};
// where you want to receive the callback
alert.clickedIndexBlock = ^(NSInteger index){NSLog(#"%d", index);};
my understanding with the above is that:
MyClickedIndexBlock is typedef to a NSInteger. Property created with the name "clickedIndexBlock" which is of type MyClickedIndexBlock (meaning that clickedIndexBlock can be a number).
Blocks can also be used as methods which is why I can call self.clickedIndexBlock(buttonIndex);
BUT something tells me that this approach as a #property only really supports one parameter
eg. NSInteger.
WHEREAS the following approach allows for more than one parameter.
bluetoothMe.h
typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
- (void)hardwareResponse:(hardwareStatusBlock)block;
bluetoothMe.m
- (void)hardwareResponse:(hardwareStatusBlock)block {
privateBlock = [block copy];
}
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
NSLog(#"Did connect to peripheral: %#", peripheral);
privateBlock(peripheral, BLUETOOTH_STATUS_CONNECTED, nil);
NSLog(#"Connected");
[peripheral setDelegate:self];
[peripheral discoverServices:nil];
}
My understanding that creating a property which is strong and doing a [block copy] will retain the block around until the app terminates. So [block copy] and strong both retain. [block copy] is applied to the block to retain otherwise the block would have vanished when the method goes out of scope.
ViewController.m
[instance hardwareResponse:^(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error) {
if (status == BLUETOOTH_STATUS_CONNECTED)
{
NSLog(#"connected!");
}
else if (status == BLUETOOTH_STATUS_FAIL_TO_CONNECT)
{
NSLog(#"fail to connect!");
}
else
{
NSLog(#"disconnected!");
}
NSLog(#"CBUUID: %#, ERROR: %#", (NSString *)peripheral.UUID, error.localizedDescription);
}];
So lets see what my questions were:
1) When would I choose the first approach over the second approach and vice versa?
2) First example, the block was a typedef to a property. Second example, the block was declared a method. Why couldn't the first example be declared a method and why couldn'tt the second example be typedef to a property?
3) Would I need to create a typedef for every type of delegate method that I want a block-based callback for?
4) At of date, ive only seen one delegate method supported. Could you show me an example on how one would implement each approach if I was to create block-based callbacks on multiple delegate methods which are not similar.
Appreciate your feedback. This is hard at times. Need as much help as I can get.
Thanks,
Ben
The questions
Whether to typedef a block or not,
whether to use a property for a block or not,
whether a block has a single or multiple arguments,
are completely independent (or orthogonal). All combinations are
possible and allowed.
void (^myClickedIndexBlock)(NSInteger index);
declares a block variable myClickedIndexBlock taking an integer argument
and returning void. You can use typedef if the same block type occurs
repeatedly in your program:
// Define MyClickedIndexBlock as *type* of a block taking an integer argument and returning void:
typedef void (^MyClickedIndexBlock)(NSInteger index);
// Declare myClickedIndexBlock as a *variable* of that type:
MyClickedIndexBlock myClickedIndexBlock;
With multiple arguments:
void (^privateBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
or
typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
hardwareStatusBlock privateBlock;
Instead of (instance) variables, you can use properties. In the first example:
#property (nonatomic, copy) void (^myClickedIndexBlock)(NSInteger index);
declares myClickedIndexBlock as a block property, and is equivalent to
typedef void (^MyClickedIndexBlock)(NSInteger index);
#property (nonatomic, copy) MyClickedIndexBlock clickedIndexBlock;
Contrary to your assumption, block properties are not restricted to blocks
with a single argument. You can use a property also in the second example,
with or without typedef:
#property (nonatomic, copy) void (^privateBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
or
typedef void (^hardwareStatusBlock)(CBPeripheral *peripheral, BLUETOOTH_STATUS status, NSError *error);
#property (nonatomic, copy) privateBlock;
It is your choice whether to use instance variables or properties for blocks.
I would use properties (with the "copy" attribute).
Whether to typedef or not is purely a matter of taste. It helps to avoid
errors if the same block type occurs repeatedly in your program. On the other
hand, the Xcode autocompletion seems to work better without typedef (in my
experience).
I strongly suggest you read the Blocks Programming Guide.
Blocks are not methods. I'm not going to paraphrase what's said in the Conceptual Overview, but just quote some parts:
Blocks represent typically small, self-contained pieces of code. [...]
They allow you to write code at the point of invocation that is executed later in the context of the method implementation.
It seems you're confused by the syntax.
typedef void (^MyClickedIndexBlock)(NSInteger index);
It's basically just defining a type named MyClickedIndexBlock representing a block that takes a single parameter of type NSInteger and returns nothing (void).
It's not a typedef to a NSInteger.
#property (nonatomic, strong) MyClickedIndexBlock clickedIndexBlock
is a declaration of a property that will contain a MyClickedIndexBlock.
It's not required to typedef blocks, it would be perfectly valid to write
#property (nonatomic, strong) void(^clickedIndexBlock)(NSInteger index);
But for the sake of clarity (or reuse), you may choose to typedef them. Notice that the property name is what follows the ^.
You're stating that blocks can be used as methods because it's possible to call self.clickedIndexBlock(buttonIndex) in your example. But in fact, it's because you've declared a property named clickedIndexBlock that you can call it like that.
There's a lot in your question, but a large part is due to confusion and misunderstanding. The 2 approaches you mention aren't really different. Blocks are objects and can be manipulated as parameters, local variables or ivars / properties just as you would do with NSString or other kinds of objects.
1) The block isn't typedef'd to an integer. It's typedef'd to return void and has an integer parameter. There is no advantage to ethos 1 or method 2; they both can have multiple parameters if declared.
2) No reason why that format has been chosen for either case. They both achieve the same result, but the first one is arguably better semantically.
3) No. You can declare blocks inline to a method. Look at the header for [NSArray enumerateObjectsUsingBlock:] for an example of inline block declaration.
4) You can just create multiple properties and call each distinct block when necessary.

iOS: why can't I access a #property from a global Block (outside of method)

I'm trying to create a global block that can be used from any method. I want this block to access #properties of the class. But when I try to do this I get "use of undeclared identifier self" accessing the backing variables _myVar also doesn't work.
Why doesn't this work? And what work around would give me a block that I can access from any method? Thanks.
An example:
#interface myClass()
#property (nonatomic,assign) BOOL subjectSex;
#end
#implementation
// these returns will get: use of undeclared identifier
int (^myBlock) = ^{
if(self.subjectSex) return 1;
return (!_subjectSex);
}
#end
You must define the block inside an instance method. You can then have a static block pointer that all your methods can access. When you assign the block to the pointer you must copy it:
s_blockPtr = [block copy];
Alternatively, you can send the this pointer as argument to the block. It's simpler to understand but may be more typing.
It doesn't so much have to do with property access as that you are using self. (You can use properties of other objects that you have access to without problem.) self does not exist in that scope. self is an implicit parameter in methods. Since your block definition is not inside a method, there is no variable named self (unless you define a global variable named self, but that would probably be a bad idea).
Blocks are nothing it's just a function pointer.If you want to access property in block you have to explicitly set __block in the property i.e.
you have to tell the compiler this is a block type property.
Let's take a closure look on blocks:
suppose there are two threads T1 and T2
//T1 Thread
void fun(int (*funptr)(int a,int b))
{
funptr(2,3);
}
//T2 Thread
int add(int a,int b)
{
return a+b;
}
//Main Thread
fun(&add);
printf("Hello");
From the above code ,assume main thread address is 20004 and executing fun having address 20006 and that fun taking function pointer as an argument which pointing to another function of thread T2 at an address of 20064 which means context switching from Thread T1 and T2, while executing T2 thread,function don't know about the global variables which are in code segment thats why they can't access because they are in different thread and this is the reason blocks are running on different thread.
that's solve.
You can access any object in a block by declaring it block type
#property(nonatomic,retain) __block NSString *strName;
dispatch_async(dispatch_get_current_queue(), ^(void)
{
self.strName= #"XYZ";
});

Resources