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)
Related
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.
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);
Was testing some code and found an error with the following lines:
NSString *stringA = #"C99";
NSString *stringB = (__bridge id)malloc(sizeof (stringA));
It is not necessary to alloc a NSString this way, of course, and I am not required to do that. Again I was just testing on something else and I happened to stumble upon this.
The error reads:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x20)
In the console:
(lldb)
To generalize, perhaps I should ask:
Could we alloc Objective-C objects through the use of malloc?
Has someone encountered this before (which I doubt, because I don't think anyone who uses Objective-C would alloc a NSString this way), but rather than shoving it aside and call it a day, I thought I would ask and see if someone knows what the exact cause of this is and why.
It is possible to use custom allocators for Objective-C objects. The problems with your code include:
NSString is a class cluster superclass (similar to an "abstract class") and cannot be instantiated on its own. You would need to use some concrete subclass of NSString. Note that the OS API does not provide any such class.
sizeof(stringA) is the size of the pointer variable, 4 or 8 bytes, which is too small to hold an NSString instance. You would need to use class_getInstanceSize() to compute the size.
+alloc performs work other than the allocation itself which is not present here. You would need to erase the memory and call objc_constructInstance().
ARC forbids the use of the low-level runtime functions that are needed to accomplish the above tasks.
well as far as I found the closest example of allocating NSSTring Clike is like this:
NSString* s4 = (NSString*)
CFStringCreateWithFormat(kCFAllocatorDefault, 0,
(CFStringRef) __builtin___CFStringMakeConstantString("%# %# (%#)"), s1, s2, s3);
ofcourse if you want to go lower and lower levels of this allocations , you should watch the CFStringRef class for its lower allocation .
but I hope this answer will satisfy you
found here, also there is more interesting things
http://www.opensource.apple.com/source/clang/clang-318.0.45/src/tools/clang/test/Analysis/NSString.m
I think the question you should be asking is what purpose that code serves.
Note that sizeof doesn't return the number of bytes in stringA, it simply returns the size of the pointer that is stringA. Who knows what lives in that little block of memory that has been allocated to stringB. Maybe it's a string, maybe not. Life is full of mystery.
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.
I have a piece of code that the ARC converter turned into this...
// firstRange is a NSRange obviously
// test is an NSString * passed in as parameter to the method
NSRange range = NSMakeRange(firstRange.location, (lastRange.location - firstRange.location) + lastRange.length);
NSString *sentence = [text substringWithRange:range];
// OK, now chop it up with the better parser
CFRange allTextRange = CFRangeMake(0, [sentence length]);
CFLocaleRef locale = CFLocaleCopyCurrent();
CFStringTokenizerRef tokenizer = CFStringTokenizerCreate(kCFAllocatorDefault,
(__bridge CFStringRef) sentence,
allTextRange,
kCFStringTokenizerUnitWord,
locale);
I call this A LOT and I suspect that it leaks somehow. Is that CFStringTokenizerCreate call kosher? I am especially suspicious of the __bridge call. Do I create an intermediate that I have to manually release or some such evil?
You need to CFRelease the tokenizer and locale or else they will leak.
This falls under Core Foundation Ownership Policy and has nothing to do with ARC.
The __bridge cast tells ARC that no ownership transfer is done for sentence in CFStringTokenizerCreate call. So that is Ok.
You can test for memory leaks with Xcode's static analyser and profiler.
You need to call CFRelease(tokenizer); when you are done using the tokenizer. See Ownership Policy. You should call CFRelease(locale); too.
Your __bridge sentence syntax is correct. I must say that Xcode is correct about __bridge and __bridge_transfer most of the time. In your case, you are passing a reference of NSObject for use with CF. You have no intention to transfer the ownership to CF because you think ARC is great at managing NSObjects. So when CFStringTokenizerCreate is done using sentence, it won't do anything to free it up. ARC will then free up sentence.
On the other hand, if you changed it to __bridge_transfer, you are telling ARC that you are transferring the ownership to CF. Therefore, when you are done, ARC won't free up sentence. You must call CFRelease(sentence); to free it up, which is not a desired behavior.
My gut tells me that it should be __bridge_transfer instead of bridge since you are calling create (unless there is a CFRelease call later). I also think the locale needs to be released since it is a copy.
EDIT Oops ignore me, I read it wrong (was using a phone)
For any Swift users reading this thread: the CFRelease() function does not seem to have been carried on into the Swift language, as Core Foundation objects are automatically memory managed (according to a compiler warning I'm seeing in Swift 3.0.2), so that's one less thing to think about.