I have an ivar that is a 'plain' C array of CFURLRef structs. I call this sourceURLArray. I initialize it to hold six elements.
Later on, in a function, I create (alloc/init) an NSURL* object. I call it fileURL and I want to save a copy of that object into the first element of the aforementioned array. I thought all I needed to do was this:
sourceURLArray[0] = (__bridge CFURLRef)([fileURL copy]);
However when I execute the code I get message sent to deallocated instance messages the second time through the function. Upon inspection of the variables, after the line above executes, sourceURLArray[0] holds the same address as fileURL. Since fileURL goes out of scope when the function completes the address in sourceURLArray[0] is deallocated.
It seems I'm misunderstanding something fundamental about either copying, nuances with toll-free bridging, or both.
Try:
sourceURLArray[0] = (__bridge_retained CFURLRef)([fileURL copy]);
or:
sourceURLArray[0] = (CFURLRef)CFBridgingRetain([fileURL copy]);
This tells ARC that you are transferring ownership to the other array. You must now properly call CFRelease on the CFURLRef at some point.
Related
I have a CFMutableArray that I created using CFArrayCreateMutable.
I just need to know whether I need to deallocate this array by myself, or is it already taken care by the ARC? If I need to deallocate this, how can I, since I didn't find any function like CFArrayRelease?
All Core Foundation objects that were allocated/copied/retained by user should be released by the user. To release the CFMutableArray, you use CFRelease() function.
CFMutableArrayRef ar = CFArrayCreateMutable(kCFAllocatorDefault, capacity, NULL);
// some code
CFRelease(ar);
More information here:
https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Concepts/Ownership.html#//apple_ref/doc/uid/20001148-CJBEJBHH
https://developer.apple.com/library/ios/documentation/CoreFoundation/Conceptual/CFMemoryMgmt/Articles/lifecycle.html#//apple_ref/doc/uid/TP40002439-SW1
Yes, we need.
You have two options:
Transfer ownership to ARC while creating the item by casting the type to an Objective-C object.
NSMutableArray *array = (NSMutableArray *)CFBridgingRelease(CFArrayCreateMutable … )
Or release the object later
CFRelease(cfMutableArray)
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).
I am a newbie to Objective-C. XCode highlights the following code as an issue.
_myCookies is a private variable of my class where I store the received cookies.
#implementation MessageSender {
NSArray *_myCookies;
}
...
// Socket open callback
- (void) gotData:(MySocket *) socket {
NSDictionary *responseHeaders = (__bridge NSDictionary*)CFHTTPMessageCopyAllHeaderFields(socket.HTTPHeaders);
_myCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:responseHeaders
forURL:[NSURL URLWithString:#""]];
}
The highlighted issues are:
Call to function 'CFHTTPMessageCopyAllHeaderFields' returns a Core Foundation object with a +1 retain count
Object leaked: object allocated and stored into 'responseHeaders' is not referenced later in this execution path and has a retain count of +1
How do I resolve this one?
I am using ARC. I want to store the cookies in my class so I can later use them while sending the request, but I want to let the socket take care of its responseHeaders.
You need to transfer ownership of the CoreFoundation object to ARC:
NSDictionary *responseHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(socket.HTTPHeaders));
CF objects are not managed by ARC, and must be released manually. When you use a __bridge cast, you're simply casting the object directly with no change in ownership. This is what causes your memory leak (you need to manually release CF objects with CFRelease when you're done with them).
You can avoid all this manual memory management trouble by simply using CFBridgingRelease to cast the object (as in the code example above). This transfers ownership of the CF object to ARC, so ARC will automatically handle releasing that object for you, and everything will work just fine with no extra work on your part.
Instead of __bridge, use __bridge_transfer which transfers ownership of the object to ARC. Ex:
NSDictionary *responseHeaders = (__bridge_transfer NSDictionary*)CFHTTPMessageCopyAllHeaderFields(socket.HTTPHeaders);
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!
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.