Objective-C: Potential leak of an object stored into NSDictionary - ios

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);

Related

When to release Core Foundation or core graphics object?

I'm using core graphics and core foundation object in iOS 10 and iOS 11. When should I release it? Or will it be handled by ARC automatically and I should not bother releasing it?
The reason is because the app crashes if I release a CGDataProviderRef
using CGDataProviderRelease(inputPDFDataProvider):
//file ref
CFURLRef pdfOutputURL = ( CFURLRef)CFBridgingRetain([NSURL fileURLWithPath:pdfOutputPath]);
CFDataRef inputPDFDataRef = (__bridge CFDataRef)inputFileData;
CGDataProviderRef inputPDFDataProvider = CGDataProviderCreateWithCFData(inputPDFDataRef);
CGPDFDocumentRef pdfRef = CGPDFDocumentCreateWithProvider(inputPDFDataProvider);
numberOfPages = CGPDFDocumentGetNumberOfPages(pdfRef);
// Release Core Graphics and Core Foundation Object
CGPDFDocumentRelease(pdfRef);
// CGDataProviderRelease(inputPDFDataProvider); **// CRASHES When releasing this CoreGraphics object**
CFRelease(inputPDFDataRef);
CFRelease(pdfOutputURL);
As with manual storage management, ownership is the decisive factor. From Apple docs:
If you create an object (either directly or by making a copy of another object—see The Create Rule), you own it.
If you get an object from somewhere else, you do not own it. If you want to prevent it being disposed of, you must add yourself as an owner (using CFRetain).
If you are an owner of an object, you must relinquish ownership when you have finished using it (using CFRelease).
You have to release an object if and only if you're an owner of the object.
But you may transfer the ownership to ARC with CFBridgingRelease. If you assign the result of this function to an Objective C variable, you doesn't own the object from the argument anymore.
For your case: You're an owner of inputPDFDataProvider because CGDataProviderCreateWithCFData matches the Create Rule:
Object-creation functions that have “Create” embedded in the name;
Object-duplication functions that have “Copy” embedded in the name.
Thus, CGDataProviderRelease is correct. However, there may be an error in the memory management of inputFileData.
'... will it be handled by ARC automatically and I should not bother releasing it?'
Answer is YES, you should always call CFRelease on Core Graphics objects manually to release allocated memory.
About you crash, it shouldn't crush, if you call CGDataProviderRelease
Apple Documentation (https://developer.apple.com/documentation/coregraphics/1408304-cgdataproviderrelease):
This function is equivalent to CFRelease, except that it does not cause an error if the provider parameter is NULL.
Your inputPDFDataRef has been assigned through __bridge from inputFileData. Therefore, there is no transfer of ownership, and you should not release inputPDFDataRef when you are ready with it. It will be released automatically when inputFileData is released.
See this reference for more information.

Want Autorelease lifetime with ARC

Transitioning to ARC on iOS.
I have an autoreleased NSString that I use to generate a UTF-8 representation, and rely on pool lifetime to keep the UTF-8 pointer alive:
char *GetStringBuffer(something)
{
NSString *ns = [NSString stringWithSomething:something];
return [ns UTF8String];
}
The nature of something is not important here.
Pre-ARC rules make sure the returned data pointer will stay valid for the lifetime of current autorelease pool. Crucially, I don't carry the NSString pointer around.
Now, under ARC, won't the string be released when the function returns? I don't think ARC will consider a char * to a structure deep inside an NSString a strong reference, especially seeing that it's not explicitly freed ever.
What's the best ARC idiom here?
If you want to guarantee that the return value of UTF8String is valid until the current autorelease pool is drained, you have two options:
Define GetStringBuffer in a file that is compiled with ARC disabled. If stringWithSomething: follows convention, it must return an autoreleased NSString to a non-ARC caller. If it doesn't (e.g. it acts like -[NSArray objectAtIndex:]), you can explicitly retain and autorelease it.
Use toll-free bridging and CFAutorelease:
char *GetStringBuffer(something) {
NSString *ns = [NSString stringWithSomething:something];
CFAutorelease(CFBridgingRetain(ns));
return [ns UTF8String];
}
(I can't delete this because it's accepted, but this answer is incorrect. See Rob Mayoff's answer, and the comments on that answer for an explanation. There is no promise that this pointer is valid past the return statement.)
Rewriting my whole answer. Had to dig and dig, but I believe this is surprisingly safe today (due to improvements in ARC since I had my crashes; I knew something like that was rolling around in the back of my head). Here's why:
#property (readonly) __strong const char *UTF8String NS_RETURNS_INNER_POINTER; // Convenience to return null-terminated UTF8 representation
UTF8String is marked NS_RETURNS_INNER_POINTER, which is really objc_returns_inner_pointer. Calling that method:
the object’s lifetime will be extended until at least the earliest of:
the last use of the returned pointer, or any pointer derived from it, in the calling function or
the autorelease pool is restored to a previous state.
Which is pretty much what you wanted it to do.

Do we need to deallocate CFArray?

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)

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.

How to copy a NSURL object to an array of CFURL structs

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.

Resources