NSString to CFStringRef and CFStringRef to NSString in ARC? - objective-c

I am trying to understand the correct way of getting an NSString from a CFStringRef in ARC?
Same for going the opposite direction, CFStringRef to NSString in ARC?
What is the correct way to do this without creating memory leaks?

Typically
NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;
and
CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;
Now, if you want to know why the __bridge keyword is there, you can refer to the Apple documentation. There you will find:
__bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.
__bridge_retained or CFBridgingRetain casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you.
You are responsible for calling CFRelease or a related function to relinquish ownership of the object.
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC.
ARC is responsible for relinquishing ownership of the object.
Which means that in the above cases you are casting the object without changing the ownership.
This implies that in neither case you will be in charge of handling the memory of the strings.
There may also be the case in which you want to transfer the ownership for some reason.
For instance consider the following snippet
- (void)sayHi {
CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);
NSString * aNSString = (__bridge NSString *)str;
NSLog(#"%#", aNSString);
CFRelease(str); //you have to release the string because you created it with a 'Create' CF function
}
in such a case you may want to save a CFRelease by transferring the ownership when casting.
- (void)sayHi {
CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);
NSString * aNSString = (__bridge_transfer NSString *)str;
// or alternatively
NSString * aNSString = (NSString *)CFBridgingRelease(str);
NSLog(#"%#", aNSString);
}
The ownership of str has been transferred, so now ARC will kick in and release the memory for you.
On the other way around you can cast a NSString * to a CFString using a __bridge_retained cast, so that you will own the object and you'll have to explicitly release it by using CFRelease.
To wrap it up you can have
NSString → CFString
// Don't transfer ownership. You won't have to call `CFRelease`
CFStringRef str = (__bridge CFStringRef)string;
// Transfer ownership (i.e. get ARC out of the way). The object is now yours and you must call `CFRelease` when you're done with it
CFStringRef str = (__bridge_retained CFStringRef)string // you will have to call `CFRelease`
CFString → NSString
// Don't transfer ownership. ARC stays out of the way, and you must call `CFRelease` on `str` if appropriate (depending on how the `CFString` was created)
NSString *string = (__bridge NSString *)str;
// Transfer ownership to ARC. ARC kicks in and it's now in charge of releasing the string object. You won't have to explicitly call `CFRelease` on `str`
NSString *string = (__bridge_transfer NSString *)str;

Related

Using alloc, init in ARC enabled projects

Actually I am working on a project with ARC enabled. I know using alloc and init is taking ownership of the object. I know, If I create a string like this
NSString *myString = [[NSString alloc]initWithFormat:#"Something"];
then I need to release the myString on myself. What If I am using ARC enabled? I cannot release on myself. So will it create a leak? Or should I don't create object like this?
I can create a string like below code too.
NSString *myString = [NSString stringWithFormat:#"Something"];
But which type I need to use exactly for ARC enabled project ? What will happen if I use first type?
If you use ARC, all the necessary release calls will be added for you when you compile. It will not leak.
The difference between
NSString *myString = [[NSString alloc]initWithFormat:#"Something"];
and
NSString *myString = [NSString stringWithFormat:#"Something"];
is that the first one will automatically released after the last reference to myString in that block, while the second one is an autoreleased instance that will only be released at the end of the run loop. It's not a big difference, but if you're using a lot of objects, try to avoid autoreleased ones to keep memory usage low.
ARC takes care of the memory management, so no you don't need to worry about calling release on your myString variable, ARC will do that for you. Also as a suggestion I would recommend using convenience methods to create your object such as
[NSString stringWithFormat:#"Something"];
It's enough to set the string pointer to nil to release it.
You can also do the same things that you would be able to do without ARC, but with the advantage that if you don't explicitly do anything, the ARC will manage (almost) everything for you.
So to release it you set it to nil, let's see what else you could do:
NSString* str= [[NSString alloc]initWithUTF8String: "Hello"];
// here the retain count of str is 1
__unsafe_unretained NSString* string= str;
// again 1 because string is __unsafe_unretained
void* data= (__bridge_retained void*) string;
// data retains the string, so the retain count is to 2
// This is useful in the case that you have to pass an objective-c object
// through a void pointer.You could also say NSString* data= string;
str=nil;
// Here the retain count of str is 1
NSLog(#"%#",(__bridge NSString*)data);
UPDATE
Here's why sometimes you don't notice that an object is released:
NSString* str= [[NSString alloc]initWithString: #"hey"];
__unsafe_unretained NSString* str2=str;
str=nil;
NSLog(#"%#",str2);
In this case str=[[NSString alloc]initWithString: #"hey"] is equal to str=#"hey", with the difference that str is autoreleased and not released.But the compiler optimizes the code in str=#"hello", so if you are inside an autorelease block you won't have any problem, str2 will be printed correctly.
That's why I used initWithUTF8String, to avoid that compiler optimization.

potential memory leak encode url

Why am I getting memory leaking while analyzing using XCode?
NSString *email = [defaults objectForKey:#"email"];
NSString *encodeEmail = (__bridge NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)email, NULL, CFSTR(":/?#[]#!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
NSString *urlp1=#"/xyz/xx/";
NSString *fullUrl=[urlp1 stringByAppendingString: [NSString stringWithFormat:#"%#/following", encodeEmail]];
From transitioning to ARC release notes
__bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.
It means encodeEmail doesn't have the ownership of the allocated memory, and so it won't be released by ARC.
I think you should use __bridge_transfer
__bridge_transfer or CFBridgingRelease moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC. ARC is responsible
for relinquishing ownership of the object.
NSString *encodeEmail = (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)email, NULL, CFSTR(":/?#[]#!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
You are using CFURLCreateStringByAddingPercentEscapes which you have to release since you own it(Check the 'create' in the name)
You can try it as,
CFStringRef stringRef = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)email, NULL, CFSTR(":/?#[]#!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
encodeEmail = [NSString stringWithFormat:#"%#",(NSString *)stringRef];
CFRelease(stringRef);
Update:
If you are using ARC, you can also use __bridge_transfer for transferring ownership from created CFObjects to NSObjects. You just have to use it as NSString *encodeEmail = (__bridge_transfer NSString *)...
Because you will leak an object. To be specific the the CFString returned by the method CFURLCreateStringByAddingPercentEscapes that method, which includes the keyword "create", returns a retained item. You must either manually release it, or tell ARC to handle it for you using:
NSString *encodeEmail = (__bridge_transfer NSString*)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)email, NULL, CFSTR(":/?#[]#!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
Note the __bridge_transfer that lets ARC handle the memory management for you, and it will eliminate your warning.

Weak NSString variable is not nil after setting the only strong reference to nil

I have a problem with this code :
__strong NSString *yourString = #"Your String";
__weak NSString *myString = yourString;
yourString = nil;
__unsafe_unretained NSString *theirString = myString;
NSLog(#"%p %#", yourString, yourString);
NSLog(#"%p %#", myString, myString);
NSLog(#"%p %#", theirString, theirString);
I'm expecting all pointers to be nil at this time, but they are not and I don't understand why.
The first (strong) pointer is nil but the other two are not. Why is that?
tl; dr: The problem is that the string literal never gets released so your weak pointer still points to it.
Theory
Strong variables will retain the value they point to.
Weak variables won't retain their value and when the value is deallocated they will set their pointer to nil (to be safe).
Unsafe unretained values (as you probably can read by the name) won't retain the value and if it gets deallocated they do nothing about it, potentially pointing to a bad piece of memory
Literals and constants
When you create a string using #"literal string" it becomes a string literal that never will change. If you use the same string in many places in your application, it is always the same object. String literals doesn't go away. Using [[NSString alloc] initWithString:#"literal string"] won't make a difference. Since it becomes a pointer to the literal string. It is however worth noting that [[NSString alloc] initWithFormat:#"literal string"]; works differently and will the release its string object.
Line by line:
__strong NSString *yourString = #"Your String";
You are creating a strong pointer to a string. This will ensure that the value does not go away. In your case it's a little bit special since the string is a string literal that technically won't be released.
__weak NSString *myString = yourString;
You create a weak pointer to the same thing as your strong pointer. If at this time the strong pointer would point to something else, the value it is pointing to would get deallocated, then the weak pointer would change its value so that it points to nil. Now it still points to the same as the strong pointer.
yourString = nil;
Your strong pointer points to nil. Nothing points to the old string so it should get released if it wasn't for the fact that is was a literal string. If you tried the exact same thing with other objects that you created yourself, the weak variable would change so that it points to nil. But, since the string literal is literal and doesn't go away. The weak variable will still point to it.
__unsafe_unretained NSString *theirString = myString;
A new unretained pointer is created, pointing to your weak pointer which is pointing to the string literal.
NSLog(#"%p %#", yourString, yourString);
NSLog(#"%p %#", myString, myString);
NSLog(#"%p %#", theirString, theirString);
You print all your strings and get confused why the first value is nil but the other two aren't.
Related reading:
What's the difference between a string constant and a string literal?
David is 100% correct in his answer. I just added four explicit examples using GHUnit.
The lifetime qualifier behavior for object references.
Using NSObject as a proxy for all objects, the behavior of the lifetime qualifiers is as expected.
- (void) test_usingNSObjects
{
NSObject *value1 = [[NSObject alloc] init];
NSObject *value2 = [[NSObject alloc] init];
NSObject *value3 = [[NSObject alloc] init];
__strong NSObject *sRefToValue = value1;
__weak NSObject *wRefToValue = value2;
__unsafe_unretained NSObject *uRefToValue = value3;
value1 = value2 = value3 = nil;
GHAssertNotNil(sRefToValue,
#"Strong reference to the object that was originally \
assigned to value1. Even though value1 was set to nil, the \
strong reference to the object keeps the object from being \
destroyed.");
GHAssertNil(wRefToValue,
#"Weak reference to the object that was originally assigned to \
value2. When value2 was set to nil, the weak reference does \
not prevent the object from being destroyed. The weak \
reference is also set to nil.");
// Removing the #ifdef and #endif lines will result in a EXC_BAD_ACCESS
// signal. Receiving a EXC_BAD_ACCESS signal is the expected behavior for
// that code.
#ifdef RECIEVE_EXC_BAD_ACCESS
GHAssertNotNil(uRefToValue,
#"Unsafe unretained reference to the object that was \
originally assigned to value3. When value3 was set to nil, \
the unsafe unretained reference does not prevent the object \
from being destroyed. The unsafe unretained reference is \
unaltered and the reference is invalid. Accessing the \
reference will result in EXC_BAD_ACCESS signal.");
#endif
// To avoid future EXC_BAD_ACCESS signals.
uRefToValue = nil;
}
The lifetime qualifier behavior for literal NSStrings (#"something").
This is basically the same as test_usingNSObjects, but instead of using a NSObject, a NSString that is assigned a literal string is used. Since literal strings are not destroyed like other objects, different behaviors for __weak and __unsafe_unretained variables are observed.
- (void) test_usingLiteralNSStrings
{
NSString *value1 = #"string 1";
NSString *value2 = #"string 2";
NSString *value3 = #"string 3";
__strong NSString *sRefToValue = value1;
__weak NSString *wRefToValue = value2;
__unsafe_unretained NSString *uRefToValue = value3;
value1 = value2 = value3 = nil;
GHAssertNotNil(sRefToValue,
#"Strong reference to the object that was originally \
assigned to value1. Even though value1 was set to nil, \
literal strings are not destroyed.");
GHAssertNotNil(wRefToValue,
#"Weak reference to the object that was originally assigned \
to value2. Even though value2 was set to nil, \
literal strings are not destroyed so the weak reference is \
still valid.");
GHAssertNotNil(uRefToValue,
#"Unsafe unretained reference to the object that was \
originally assigned to value3. Even though value3 was set \
to nil, literal strings are not destroyed so the unsafe \
unretained reference is still valid.");
}
The lifetime qualifier behavior for nonliteral NSStrings.
This is basically the same as test_usingNSObjects, but instead of using a NSObject, a NSString that is assigned a nonliteral string is used. Since the nonliteral strings are destroyed like other objects, the behaviors are the same as observed in test_usingNSObjects.
- (void) test_usingNonliteralNSStrings
{
NSString *value1 = [[NSString alloc] initWithFormat:#"string 1"];
NSString *value2 = [[NSString alloc] initWithFormat:#"string 2"];
NSString *value3 = [[NSString alloc] initWithFormat:#"string 3"];
__strong NSString *sRefToValue = value1;
__weak NSString *wRefToValue = value2;
__unsafe_unretained NSString *uRefToValue = value3;
value1 = value2 = value3 = nil;
GHAssertNotNil(sRefToValue,
#"Strong reference to the object that was originally \
assigned to value1. Even though value1 was set to nil, the \
strong reference to the object keeps the object from being \
destroyed.");
GHAssertNil(wRefToValue,
#"Weak reference to the object that was originally assigned to \
value2. When value2 was set to nil, the weak reference does \
not prevent the object from being destroyed. The weak \
reference is also set to nil.");
// Removing the #ifdef and #endif lines will result in a EXC_BAD_ACCESS
// signal. Receiving a EXC_BAD_ACCESS signal is the expected behavior for
// that code.
#ifdef RECIEVE_EXC_BAD_ACCESS
GHAssertNotNil(uRefToValue,
#"Unsafe unretained reference to the object that was \
originally assigned to value3. When value3 was set to nil, \
the unsafe unretained reference does not prevent the object \
from being destroyed. The unsafe unretained reference is \
unaltered and the reference is invalid. Accessing the \
reference will result in EXC_BAD_ACCESS signal.");
#endif
// To avoid future EXC_BAD_ACCESS signals.
uRefToValue = nil;
}
NSString creation - literal vs nonliteral.
Shows strings created in various ways if they are literal nor nonliteral.
- (void) test_stringCreation
{
NSString *literalString = #"literalString";
NSString *referenced = literalString;
NSString *copy = [literalString copy];
NSString *initWithString = [[NSString alloc] initWithString:literalString];
NSString *initWithFormat = [[NSString alloc] initWithFormat:#"%#", literalString];
// Testing that the memory addresses of referenced objects are the same.
GHAssertEquals(literalString, #"literalString", #"literal");
GHAssertEquals(referenced, #"literalString", #"literal");
GHAssertEquals(copy, #"literalString", #"literal");
GHAssertEquals(initWithString, #"literalString", #"literal");
GHAssertNotEquals(initWithFormat, #"literalString",
#"nonliteral - referenced objects' memory addresses are \
different.");
// Testing that the objects referenced are equal, i.e. isEqual: .
GHAssertEqualObjects(literalString, #"literalString", nil);
GHAssertEqualObjects(referenced, #"literalString", nil);
GHAssertEqualObjects(copy, #"literalString", nil);
GHAssertEqualObjects(initWithString, #"literalString", nil);
GHAssertEqualObjects(initWithFormat, #"literalString", nil);
// Testing that the strings referenced are the same, i.e. isEqualToString: .
GHAssertEqualStrings(literalString, #"literalString", nil);
GHAssertEqualStrings(referenced, #"literalString", nil);
GHAssertEqualStrings(copy, #"literalString", nil);
GHAssertEqualStrings(initWithString, #"literalString", nil);
GHAssertEqualStrings(initWithFormat, #"literalString", nil);
}
the weak property will only be set to nil after the autorelease pool was drained.
try:
#autoreleasepool {
_strong NSString *yourString = #"Your String";
__weak NSString *myString = yourString;
yourString = nil;
__unsafe_unretained NSString *theirString = myString;
}
NSLog(#"%p %#", yourString, yourString);
NSLog(#"%p %#", myString, myString);
NSLog(#"%p %#", theirString, theirString);

Removing objects in obj-c

How I must remove objects?
For example, I have NSDictionary and some NSStrings from it:
NSDictionary *dict = [NSDictionary dictionaryWithObjects....];
NSString *str = [dict objectForKey:#"key"];
[str release]; or [str dealloc]; or str = nil or it's autorelease object?
If I will remove not autorelease dict, will all child removed too?
Memory management in objective c is based on object ownership. If you own the object you must release that object.
Cocoa sets the following policy:
You own any object you create
You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy).
You can take ownership of an object using retain.
When you no longer need it, you must relinquish ownership of an object you own
You relinquish ownership of an object by sending it a release message or an autorelease message.
You must not relinquish ownership of an object you do not own
This is just corollary of the previous policy rules, stated explicitly.
In your case
NSDictionary *dict = [NSDictionary dictionaryWithObjects....];
NSString *str = [dict objectForKey:#"key"];
you are not owner of str, so you should not release that object.
to remove specific objects you will have to make a mutable Object.
Most of the objective-c dat types are mutable such as
NSMutableDictionary,NSMutableArray..etc
then just call ..[yourObject removeObjectatIndex:someInteger] or [yourObject RemoveAllObjects] to remove objects.
Releasing or auto releasing an object is totally different thing..it will free up the memory that whole object(Dict..array..etc) is taking..
If the call does not end in retain, copy or mutableCopy, alloc or new you must not use release or autorelease. The object is already autoreleased.
NSString *str = [[NSString alloc] initWithString:#"123"]; <- needs release
NSString *str = [aString copy]; <- release
NSString *str = [aString mutableCopy]; <- release
NSString *str = [aString retain]; <- release
NSString *str = [NSString new]; <- release
everything else <- don't release.
there is exactly one valid use of dealloc. That is in [super dealloc]; in your - (void)dealloc method.
If the dictionary gets deallocated all the objects and keys it contains get released. If they are not retained somewhere else they get deallocated too.
There is plenty of documentation about memory management available. For example Apples Advanced Memory Management Programming Guide
what do you mean "remove"? assume you mean dealloc or free
str is retained by dict and if you didn't call retain on it than you should not call release on it.
and you should never call dealloc to any object
NSDictionary *dict = [NSDictionary dictionaryWithObjects....];
dict is an autoreleased object with means it will be deallocated on next run loop if you did not retain it anywhere
everything in dict is retained by it so they will not be deallocated until dict is deallocated

Correct bridging for ARC?

I have a category class for NSString.
#implementation NSString (URLEncode)
- (NSString *)URLEncodedString
{
__autoreleasing NSString *encodedString;
NSString *originalString = (NSString *)self;
encodedString = (__bridge_transfer NSString * )
CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFStringRef)originalString,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
return encodedString;
}
Am I using the correct bridge transfers for ARC and the new LLVM?
The original code:
- (NSString *)URLEncodedString
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
return [encodedString autorelease];
}
As mentioned in the comments, I think it's fine to talk about ARC and the contents of Automatic Reference Counting here.
__autoreleasing is not meant to be used like that. It's used for passing indirect object references (NSError**, etc). See 4.3.4 Passing to an out parameter by writeback.
According to 3.2.4 Bridged casts, the __bridge_transfer is correct as the CFURLCreateStringByAddingPercentEscapes function returns a retained object (it has "create" in its name). You want ARC to take ownership of the returned object and insert a release (or autorelease in this case) to balance this out.
The __bridge cast for originalstring is correct too, you don't want ARC to do anything special about it.
This is a correct, not leaking version.
As you say in the comments: __bridge_transfer transfer the ownership to NSObject (NSString) and assume that the object is retained by CF Framework (the method CFURLCreateStringByAddingPercentEscapes return a retained object so this is what we need)
than on the self object we don't want to perform any memory management. Hope it helps
Fra
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge CFStringRef)self,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
CFStringConvertNSStringEncodingToEncoding(encoding));
}
-(NSString *) urlEncoded
{
CFStringRef encodedCfStringRef = CFURLCreateStringByAddingPercentEscapes(NULL,(CFStringRef)self,NULL,(CFStringRef)#"!*'\"();#+$,%#[]% ",kCFStringEncodingUTF8 );
NSString *endcodedString = (NSString *)CFBridgingRelease(encodedCfStringRef);
return endcodedString;
}
No __autoreleasing necessary. The correct ARC syntax is simply:
- (NSString *)URLEncodedString
{
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8));
}