Block is preventing dealloc although the block was copied - ios

I believe I was following the rules but still a problem exists
My class init includes a block like this:
HTTPChunkReceiveBlock chunkBlock = ^(id connection, NSData *data) {
NSLog(#"Hi there!!");
};
and I am passing this block into an HttpConn obj which my class holds:
operation_ = [[HttpClient sharedClient] performChunkedRequest:url
chunkHandler:chunkBlock];
Now for the problem: my object is never deallocated!!
The problem seems to be caused because the HttpConn is keeping a pointer to the block, but I want to mention two points:
The block is not referring to self!
The HttpConn class is keeping a copy of the block, like this:
chunkBlock_ = [chunkBlock copy];
Any explanation would be greatly appreciated!
EDIT
Extra info:
I have verified that if I'm freeing operation_ then my object is deallocated fine:
reader.operation_ = nil;
reader = nil; //previous line allows 'dealloc' to be called
Now repeating the question: operation did not get a pointer of reader's self, it only holds a copy of the block which do not refer to self!

Ok, I will answer my own question so that others do not fall into the same problem. #DarkDust was actually correct. there was a tiny line which I was completely ignoring:
**retriesNumber++;**
It looks like an innocent sentence, but because retriesNumber is a member of the class, it is actually meaning
(INVISIBLE strong pointer to self)->retriesNumber
so the solution was to declare it as a property (versus a member ivar) so that we can use self to access it, and then write:
pSelf->retriesNumber++;
Thank you guys for your quick support, and I hope others will learn from it too!

Related

Best practice to declare Objective-C blocks as variable

I have a question regarding the best practice for declaring a block as a variable.
Initially I wrote my block variable like this:
id actionHandler = ^(UIAlertAction * action) {
// Handling code
};
To be later used like so:
UIAlertAction *action = [UIAlertAction actionWithTitle:#"Title"
style:UIAlertActionStyleDefault
handler:actionHandler];
But when I came across Apple's Working With Blocks guide, I saw I could rewrite it like so:
void (^actionHandler)(UIAlertAction * action) = ^(UIAlertAction * action) {
// Handling code
};
Is this the 'correct' way to declare it? That is in my opinion not as readable, but I don't have a lot of experience with Objective-C. So what is the best practice for declaring a block as a variable?
Edit: Alright, thanks all for the clarification! Defining a typedef as shown by amin-negm-awad and others seems like a good alternative approach as well.
There is no one-fits-all answer here: when you declare your block variable as id you no longer have compile-time information associated with your block, so calling it manually becomes problematic:
id myHandler = ^(NSString *str) {
NSLog(#"%#", str);
};
// Error: Called object type id is not a function or function pointer
myHandler(#"Hello");
if you want to make a direct call to the block from your code, you need to cast it back to a block.
On the other hand, if you declare a block variable only so that you could pass it to a function that takes a block as a parameter, using id provides a more readable approach.
Additional to the problem mentioned by dasblinkenlicht I want to ask a rhetoric question:
Likely you know that you can substitute this code …:
NSString *string = #"All about types";
… with this code:
id string = #"All about types";
Would you do? I'm sure, you don't.
So why should one change the "typed" version of the var into an id version? The only reason is, that the syntax of block types is unhandy and not easy to read (and not easy to write). I always define a concrete type to get rid of the unhandy syntax:
typedef void (^ActionHandlerType)(UIAlertAction * action);
And then:
ActionHandlerType actionHandler = ^(UIAlertAction * action) {
// Handling code
};
To make that clear: id is great to use the dynamic nature of Objective-C's message passing. But block execution is neither late bound. Nor the parameters of the block can change its number or type, so there is nothing to dynamically bind. It is a simple call with fixed numbers of arguments, fixed typed. Therefore the usage of id is possible as a side-effect of the block's object nature. But it is not an usage, which is intended.
BTW: If you use a concrete type in a parameter list, Xcode can autocomplete the syntax of the argument. With id this is not possible. Obviously.
If you use id in this context the compiler will not check that the type of the block you declare matches the type of the block the method expects. If you accidentally get the block wrong nasty, hard to debug, things will probably happen when the method tries to use the block...
So if you never make mistakes go with id, but if like me you do provide the correct type so the compiler can help you out when you do.
To make it easier, and consequently less error prone, use a typedef, e.g.:
typedef void (^AlertActionHandler)(UIAlertAction * action);
...
AlertActionHandler actionHandler = ^(UIAlertAction * action) { ...

NSError object already populated on first method call

I am following the book Test-Driven iOS development by G. Lee and came across this unit test, which I don't understand. First of all, if you need more code, please let me know right away.
-(void)testDelegateNotifiedOfErrorWhenNewsBuilderFails
{
MockNewsBuilder *builder = [MockNewsBuilder new];
builder.arrayToReturn = nil;
builder.errorToSet = underlyingError;
newsManager.newsBuilder = builder;
[newsManager receivedNewsJSON:#"Fake Json"];
...
}
-(void)receivedNewsJSON:(NSString *)objectNotation
{
NSError *error = nil;
// As you see error is nil and I am passing in a nil error.
NSArray *news = [_newsBuilder newsFromJSON:objectNotation error:&error];
...
}
#implementation MockNewsBuilder
-(NSArray *)newsFromJSON:(NSString *)objectNotation error:(NSError **)error
{
// But once I arrive here, error is no longer nil.
// (NSError **) error = 0x00007fff5cb887f0 domain: #"Fake Json" - code: 0
...
}
How is error auto-magically set?
UPDATE:
Thanks everyone for active discussion and advice. The answers explain how the caller side gets the error instance because of &, I understand that clearly. My question remains though why the callee side is pointing to a populated NSError instance, even though it had to be nil. I didn't set the error instance within newsFromJSON:error: so how is it already populated there?
I just changed [newsManager receivedNewsJSON:#"Fake Json1"]; and the error instance within newsFromJSON:error: reflects right away
(NSError **) error = 0x00007fff5b9b27f0 domain: #"Fake Json1" - code: 0. Its very confusing...
This is just pointer to pointer concept. You are passing the reference to the reference error object &error to the method -(NSArray *)newsFromJSON:(NSString *)objectNotation error:(NSError **)error;
And this will update the error object at the memory pointer you have passed.
See this is the concept of pointer to pointer.
Update:
Your error object is nil, yes its right. But you are not passing that error object to the newsFromJSON method, but the memory address of the error object( &error). That is the memory address of the error object.
This why you are getting non null value there inside your newsFromJSON method.
And one more thing, you can access the original object in your newsFromJSON method using the content of operator(* operator)
like **error = something;
This will update your original object ( NSError *error ) you declared in your caller method.
In C or CPP or Objective-C, & is the Address of operator and * is the content of operator.
&obj -> give the memory address of the obj
*obj -> give the content of the memory address in the obj.
** is a pointer to a pointer.
It means you need to pass a pointer address to a function or method.
Objective-C is a strict superset of C.
That means as in C functions and methods can only return one value.
There are two ways about it.
One is to wrap all your returns in structs or NSDictionaries or other collections.
This way is called an outParameter
It's passing a pointer address in.
C is a by copy language. But pointers are portable black holes that allow you to do wild things in C.
Objective-C and C++ give you the same wildness.
The error is set by Apple's framework code.
The Cocoa pattern is usually to return a BOOL and pass in an NSError pointer address.
If BOOL is NO check the NSError.
Apple framework will have put some presents in your NSError pointer address box.
Sometimes they don't use BOOL and instead return an object or nil.
Core Foundation C frameworks work very similarly and use in and out parameters a lot.
error is a variable of type NSError*, that is "pointer to NSError" (in objective-C, all objects are handled as references, as opposed to e.g. C++).
What this means is that error is a (local) variable that stores the address of the actual NSError object, initially nil.
The method you call creates an (autoreleased) NSError instance. In order to get a reference to that instance back, you need to pass the method the address of the pointer, or &error, which is, in turn, of type "pointer to pointer to NSError" (note the two-level indirection).
You do this because arguments to functions in C and methods in Objective-C are passed by value: if you just passed error, the value stored there (nil) alone is copied, and no matter what the called method does, the contents of the variable error on your side (the caller) can't be modified. To achieve this, you need to pass the address of error, or &error.
This way, the called method can "change" the contents of error (the address held there) so that it points to the newly created, NSError instance.
Does it make sense?
ADDENDUM: This is a very common pattern very often seen in Cocoa: The method being called could potentially fail, and instead of just using the return value to signal success/failure, and additional 'in/out' parameter is passed to retrieve detailed error information in case of failure. On failure, the method can return false (NO, 0, etc.), but in addition in can provide a more detailed error report (e.g. the reason for failure) inside the NSError instance.
EDITED: As #Droppy said, and seeing that all code involved is your own (i.e., not some first or third party framework), it is impossible that error is set to anything other than nil unless you explicitly allocate it somewhere. Perhaps you should "watch" it in the debugger to see when/where it is set. since the message seems to be set to #"Fake JSON", the first thing you could do is search that string in your project (all files).

What is Apple warning against in ARC documentation caveat about pass by reference?

In Apple's documentation about ARC, they make a point of spelling out a problematic scenario in which ARC will generate a boilerplate temporary variable behind the scenes. Search on "The compiler therefore rewrites":
https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
The gist of the warning seems to be that because the stack-based variable is "strong" and the by-reference parameter to the called method (performOperationWithError:) is autoreleasing, ARC will generate a temporary local variable to serve the memory management needs of the autoreleasing variable. But because the temporary variable is assigned to the strong variable in the boilerplate example, it seems as though from a client's point of view there is no risk.
What exactly is the documentation taking pains to warn us about here? What is the risk as either a client or as an implementor of a method that may be called in this way (with an autoreleased, return-by-value parameter)?
It's only a warning about less than ideal performance. In the rewritten code, the NSError pointed to by "tmp" comes back autoreleased, is retained when assigned to "error", and then is released again when "error" goes out of scope.
If you change the declaration in the original code to:
NSError __autoreleasing *error;
If you do this, there is no assignment to a temp, and that implicit retain and then release no longer occurs. (The NSError object itself is still valid for exactly as long as it was before, since it is still in the autorelease pool.) So the documentation is warning you that if you use the "wrong" variable qualifier that it can cause extra retain count munging that wouldn't otherwise be required.
Also note that with either version of the code: Because the variable in question is passed by reference and isn't the return value from -performOperationWithError:, there isn't the opportunity to do the magic stack walking trick that ARC can do to save the object from going into the autorelease pool in the first place.
I think it’s to prevent confusion if you start looking at the values passed into the method. In their example, if I set a breakpoint on the line that calls [myObject performOperationWithError:&tmp]; and type p error, I’ll see the address of it. But if I step into -performOperationWithError: and type p error, I’ll get a different value—inside the method, error points to that temporary value.
I can see a situation where some poor sap is trying to debug something tricky with ARC where the pointer changing as it gets passed into the method would be an extremely confusing red herring.
My guess: If you made assumptions about the memory referenced by the output parameter, e.g indexing off the pointer, you might be surprised.
I don't think it has anything to do with the client. It looks like a reference to the same issue addressed in the WWDC 2013 video on memory issues: If you yourself implement a method that takes an autoreleasing indirection parameter (such as an NSError**), and if you create an autorelease pool block inside that method, do not assign to the NSError from inside the autorelease pool block. Instead, assign to a local variable, and then assign from the local to the NSError outside the autorelease pool block.
Seems to me that it's less of a warning about this behavior than a description of what the compiler does in this case and why you can pass the address of a strong local error reference to a method that is declared as wanting an __autoreleasing reference and not trigger a complaint.
You generally want an API to use __autoreleasing on such a parameter in case it is being used by either ARC or non-ARC code, as in non-ARC code it would be unusual to have to release such an output parameter.
The Apple documentation is referring to a compiler misfeature that will synthesize a temporary variable for you to deal with the conversion between __block and __autoreleasing. Sadly, this doesn't solve very many problems and it produces potentially disasterous unexpected results.
For example:
int main(int argc, char *argv[])
{
__block id value = #"initial value";
void (^block)(id *outValue) = ^(id *outValue){
value = #"hello";
};
block(&value);
NSLog(#"value = %#", value);
return 0;
}
With ARC, this reports:
2013-04-24 13:55:35.814 block-local-address[28013:707] value = initial value
but with MRR:
2013-04-24 13:57:26.058 block-local-address[28046:707] value = hello
This very often comes up when using NSFileCoordinator, causing you to lose the resulting NSError!
#import <Foundation/Foundation.h>
int main(int argc, char *argv[])
{
NSURL *fileURL = [NSURL fileURLWithPath:#"/tmp/foo"];
NSFileCoordinator *coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
__block NSError *error;
[coordinator coordinateWritingItemAtURL:fileURL options:0 error:&error byAccessor:^(NSURL *newURL){
NSDictionary *userInfo = #{
NSLocalizedDescriptionKey : #"Testing bubbling an error out from a file coordination block."
};
error = [NSError errorWithDomain:NSPOSIXErrorDomain code:ENOSYS userInfo:userInfo];
}];
NSLog(#"error = %#", error);
}
When compiled with ARC, this results in a nil error!
This has been written up as a bug at llvm.org for a while, though I just changed the title to make it more clear that I'm suggesting the feature be ripped out. Also attached to that bug is a patch to add a new flag -fno-objc-arc-writeback to disable the feature).

Copying a block

Could some one tell me why the memory address of the localComplete block and the self.block are the same? self.complete's property is set to copy, and just to be sure i also call copy on localComplete when assigning it to self.complete.
- (void) test {
CompletionBlock localComplete = ^{
};
NSLog(#"localComplete - %p", localComplete);
self.block = [localComplete copy];
NSLog(#"self.complete - %p", self.block);
self.block();
}
Here is the output:
2013-10-05 08:39:18.549 TestApp[90703:a0b] localComplete - 0x60b8
2013-10-05 08:39:18.550 TestApp[90703:a0b] self.complete - 0x60b8
As another example I create strings:
// creating string
self.carType = [[NSString alloc] initWithFormat: #"Good%#", #"year"];
NSLog(#"self.carType - %p", self.carType);
// same memory address???
NSString *carInitString = [[NSString alloc] initWithString: self.carType];
NSLog(#"carInitString - %p", carInitString);
// same memory address???
NSString *carCopy = [self.carType copy];
NSLog(#"carCopy - %p", carCopy);
// different memory address
NSString *carInitWithFormat = [[NSString alloc] initWithFormat: #"%#", self.carType];
NSLog(#"carInitWithFormat - %p", carInitWithFormat);
And the output:
2013-10-05 09:45:01.667 TestApp[91103:a0b] self.carType - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitString - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carCopy - 0xa084910
2013-10-05 09:45:01.668 TestApp[91103:a0b] carInitWithFormat - 0xa336b70
Why isn't carInitString and carCopy different memory addresses? Optimizations are turned off in the projects build settings.
Concerning your original question, blocks are normally allocated on the stack. Copying a block (either with the Block_Copy function or the -copy method) will move the block on the stack (further calls will just increase the block's retain count)
Block_copy [...], given a block pointer, either copies the underlying block object to the heap, setting its reference count to 1 and returning the new block pointer, or (if the block object is already on the heap) increases its reference count by 1
(source)
So in your example, you may expect different addresses, since the first block is local, whereas the second one is on the heap, BUT since that specific block doesn't make any reference to the surrounding scope, the compiler will mark it as a global block. Global blocks are not allocated on the stack, and are instead at a fixed location in memory.
Copying a global block won't move the block anywhere. It will just increase its retain count, since the object is already on the heap. That's why you don't get two different addresses.
Try to make a block with a reference to the surrounding context and you will have two different addresses (stack and heap).
Now, let's address your question about NSString.
Copying an immutable object can result in a retain as an optimization (I mean, a framework design optimization, the compiler has nothing to do with it), depending on how the class implements the NSCopying protocol.
This is true for many Foundation classes like NSString, NSArray, NSSet...
This is perfectly compliant with the NSCopying protocol specification, as you can read in the documentation:
Your options for implementing this protocol are as follows:
...
Implement NSCopying by retaining the original instead of creating a new copy when the class and its contents are immutable.
As noted by Greg Parker in the comments, -[NSString initWithString:] performs the same kind of optimization. If you pass an immutable string as argument, it just retains and return the same string.
This is a useful behavior in a few situations, here's an example: you declare a property
#property (nonatomic, copy) NSArray *anArray;
and you expose it in the interface.
Declaring it as copy is a good practice in order to ensure that the object you are working on doesn't get changed by the client later on. If you just retain it and the client passes in a NSMutableArray you cannot prevent her to manipulate the object.
So copying is good, but it looks like it comes with a price: you are going to copy the object even when you don't need to (i.e. it's immutable).
Thanks to the behavior discussed above, however, you don't pay such price. Sending copy to an NSArray will just retain it, whereas sending it to a NSMutableArray will actually copy it, so in this case is a big win.
it could be because the copy isn't necessary. you don't capture any variables or anything like that. so perhaps the block is constant. try having it refer to a local or __block variable.

Using output parameters with ARC

So I have read this question, which seems to be exactly the kind of problem I am having, but the answer in that post does not solve my problem. I am attempting to write a data serialization subclass of NSMutableData. The problematic function header looks like this:
-(void)readString:(__autoreleasing NSString **)str
I do some data manipulation in the function to get the particular bytes the correspond to the next string in the data stream, and then I call this line:
*str = [[NSString alloc] initWithData:strData encoding:NSUTF8StringEncoding];
No errors in this code. But when I try to call the function like so:
+(id) deserialize:(SerializableData *)data
{
Program *newProgram = [[Program alloc] init];
[data readString:&(newProgram->programName)];
On the line where I actually call the function, I get the following error:
Passing address of non-local object to __autoreleasing parameter for write-back
I have tried placing the __autoreleasing in front of the NSString declaration, in front of the first *, and between the two *'s, but all configurations generate the error.
Did I just miss something when reading the other question, or has something in the ARC compiler changed since the time of that post?
EDIT:
It seems that the problem is coming from the way I am trying to access the string. I can work around it by doing something like this:
NSString* temp;
[data readString&(temp)];
newProgram.programName = temp;
but I would rather have direct access to the ivar
You can't. You might gain insight from LLVM's document Automatic Reference Counting, specifically section 4.3.4. "Passing to an out parameter by writeback". However, there really isn't that much extra detail other than you can't do that (specifically, this isn't listed in the "legal forms"), which you've already figured out. Though maybe you'll find the rationale interesting.

Resources