I am trying to convert a CFUUIDRef to a NSString *.
Before, I used the following code, and worked fine.
CFStringRef str = CFUUIDCreateString(NULL, _uuid); # _uuid is of type CFUUIDRef
return (__bridge NSString *) str;
However, after a recent update on Xcode (or other thing that I didn't notice?), the above code gives me the error:
Use of undeclared identifier '__bridge'
So have I did something wrong? How could I solve it?
=== UPDATED ===
The full code:
+ (NSString *)uuidToString:(CFUUIDRef)_uuid {
CFStringRef str = CFUUIDCreateString(NULL, _uuid); # _uuid is of type CFUUIDRef
return (__bridge NSString *) str;
}
The uuid is generated by:
uuid = CFUUIDCreate(NULL);
__bridge is only defined with ARC (Automatic Reference Counting) enabled. It is used to "transfer objects in and out of ARC control". (Source)
To turn on ARC, go to your build settings and set Objective-C Automatic Reference Counting to Yes.
Or, if you do not want to use ARC, simply remove __bridge and it should work fine.
Related
I've been experimenting with type safety in objective c for a while now. I think I got some of it, but I am wondering if the following is possible.
NSMutableArray <NSNumber *> *x = [NSMutableArray new];
[x addObject:#14];
[x addObject:#"s"]; // <--- Gives warning, good!
for (NSUInteger i = 0; i < x.count; i++) {
NSString *s = [x objectAtIndex:i]; // <-- Gives warning, good!
}
NSString *d = x[0]; // <-- Gives warning, good!
//but
for (NSString *s in x) // <-- expected warning but didn't get it
NSLog(#"%#", [s stringByAppendingString:#"s"]; // <-- no warning just run time error
So my question is can a for in loop give a warning when an incorrect object is used. I want to use the for in since it is fast and hides details of implementation.
Here's the issue.
Most of the NSArray/NSMutableArray methods such as addObject: and objectAtIndexedSubscript: (which allows for the modern [index] syntax) take or return ObjectType values. ObjectType is a special indicator that means "use the generic type" specified for the array.
The fast enumeration comes from the NSFastEnumeration protocol and its countByEnumeratingWithState:objects:count: method. Unfortunately, the objects parameter is a C-array of id. It doesn't use ObjectType. Since the objects are type id, the compiler can't do any type checking like it can for the other methods of NSArray.
its a bug. implementation details like NSFastEnumeration don't matter. they should at least check it in an analyzer pass if they don't manage to emit a warning. please file bug reports at Apple and LLVM
I want to create a wrapper around the NSURLSession and I found some nice code but was written in Swift.https://github.com/daltoniam/SwiftHTTP.But since I still write production code in Objective-C I started borrowing the idea of the above code, though I have hard time to understand the following code and translate to Objective-C (if needed).
I know I could use AFNetworking but this is not feasible due to architecture decisions when building a distributable framework.
The code:
/// encoding for the request.
public var stringEncoding: UInt = NSUTF8StringEncoding
// Somewhere in a method
var charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding));
if request.valueForHTTPHeaderField(contentTypeKey) == nil {
request.setValue("application/x-www-form-urlencoded; charset=\(charset)",
forHTTPHeaderField:contentTypeKey)
}
request.HTTPBody = queryString.dataUsingEncoding(self.stringEncoding)
My Objective-C code:
#property (assign, nonatomic) NSUInteger stringEncoding;
// In this line I get a compiler warning and in runtime it crashes with BAD_EXC
CFStringEncoding cfStringEncoding = CFStringConvertIANACharSetNameToEncoding(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding));
if (![mutableRequest valueForHTTPHeaderField:ContentTypeKey])
{
[mutableRequest setValue:[NSString stringWithFormat:#"application/x-www-form-urlencoded; charset=%u", (unsigned int)cfStringEncoding] forHTTPHeaderField:ContentTypeKey];
}
mutableRequest.HTTPBody = [queryString dataUsingEncoding:self.stringEncoding];
Compiler warning:
Incompatible integer to pointer conversion assigning to 'CFStringEncoding' (aka 'unsigned long') from 'CFStringRef' (aka 'const struct __CFString *')
I don't have strong experience working with CFStringEncoding and CFString so I find it hard to translate the documentation.
Do I really need this conversion, and what is it's purpose?
Try using NSString instead:
NSString *charset =
(NSString *)CFStringConvertEncodingToIANACharSetName
(CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
This is what typically was used before the Swift version, and as I recall AFNetworking used a similar method (if not the same).
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;
I need to generate a UUID string in some code with ARC enabled.
After doing some research, this is what I came up with:
CFUUIDRef uuid = CFUUIDCreate(NULL);
NSString *uuidStr = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
Am I correctly using __bridge_transfer to avoid leaking any objects under ARC?
Looks fine to me. This is what I use (available as a gist)
- (NSString *)uuidString {
// Returns a UUID
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
NSString *uuidString = (__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuid);
CFRelease(uuid);
return uuidString;
}
Edited to add
If you are on OS X 10.8 or iOS 6 you can use the new NSUUID class to generate a string UUID, without having to go to Core Foundation:
NSString *uuidString = [[NSUUID UUID] UUIDString];
// Generates: 7E60066C-C7F3-438A-95B1-DDE8634E1072
But mostly, if you just want to generate a unique string for a file or directory name then you can use NSProcessInfo's globallyUniqueString method like:
NSString *uuidString = [[NSProcessInfo processInfo] globallyUniqueString];
// generates 56341C6E-35A7-4C97-9C5E-7AC79673EAB2-539-000001F95B327819
It's not a formal UUID, but it is unique for your network and your process and is a good choice for a lot of cases.
That looks correct to me.
You have CFRelease'd uuid, which is your responsibility from the CFUUIDCreate()
And you've transferred ownership of the string to ARC, so the compiler knows to release uuidStr at the appropriate time.
From clang docs:
(__bridge_transfer T) op casts the operand, which must have non-retainable pointer type, to the destination type, which must be a retainable object pointer type. ARC will release the value at the end of the enclosing full-expression, subject to the usual optimizations on local values.
So you are doing it right.
Consider the following code:
if([obj isKindOfClass:[NSString class]]) {
NSString *s = [(NSString *)obj stringByAppendingString:#"xyzzy"];
}
I'm a bit confused here. The if statement checks whether or not obj is of the NSString class. If it is, it assigns the object and an appended string to NSString *s, do I understand this correctly? If so, why would you still cast it to (NSString *)?
Doesn't the if statement already check for that and doesn't that make the typecasting unnecessary?
Wouldn't it be perfectly fine to just say:
NSString *s = obj stringByAppendingString:#"xyzzy"];
Thanks in advance.
It all depends on how obj is defined. If it is id obj then no casting is needed, but if it was defined as NSObject *obj the cast is necessary to suppress the compiler warning that stringByAppendingString: is not defined on NSObject. The cast is not needed to make the code work at runtime, it only tells the compiler the "correct" type so it can tell whether the method should exist on the object.
The reason why the cast isn't needed for id is because id means "an object of any type", while NSObject * means "an object of type NSObject".