Here's my code:
- (void)peripheralManager:(CBPeripheralManager *)peripheralManager central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
{
[self.centralManager retrievePeripherals:#[central.UUID]];
}
I get an error:
Collection element of type 'CFUUIDRef' (aka 'const struct __CFUUID *') is not an Objective-C object
What do I do?
The problem:
The compiler only knows about types, not about runtime behavior. It doesn't know that - most probably - CFUUIDRef can be used just like any normal Objective-C object (although it doesn't officially have a toll-free bridged Foundation class counterpart). It only sees that const struct __CFUUID is not an Objective-C class, and it bails out.
The solution:
I. I presume this will work - just tried it and it indeed works, CFUUID even has a nice description when printed using NSLog(). However, it is not documented. Just cast it to id, like this:
#[(__bridge id)central.UUID]
II. Yes, you can convert it to a string, but that won't make the compiler error go away either - you do need that typecast, because the compiler quirks about the incompatible types:
CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault,#[central.UUID]);
NSString *uuidNSString = (__bridge NSString *)uuidString;
Now this is guaranteed to work.
My recommendation would be to convert it to an NSString and add that to the array.
+ (NSString *)convertUUID:(CFUUIDRef)theUUID
{
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
return (__bridge_transfer NSString *)string;
}
Try converting it to a Objective-C Object:
CFStringRef uuidString = CFUUIDCreateString(kCFAllocatorDefault, yourUUID);
NSString *uuidNSString = (__bridge NSString *)uuidString;
And if you need it back:
CFUUIDRef uuid = CFUUIDCreateFromString(kCFAllocatorDefault, uuidString);
Related
I am getting following error but how to resolve it ?
Error is highlighted with green circle "Reference counted object is used after it is released"
Edited: I am using following method
+ (NSString *)GetUUID
{
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
CFRelease(theUUID);
NSString *str = (__bridge NSString *)string;
CFRelease(string);
return str;
}
Edited: Resolved by using vijay's following simple code
NSUUID *UUID = [NSUUID UUID];
NSString* stringUUID = [UUID UUIDString];
I hope, you are getting this error because of [DBManager GetUUID] method, where you would release the CFRelease(cfUuid).
To get the UUID, try this simplified API
+ (NSString *)GetUUID
{
NSUUID *UUID = [NSUUID UUID];
NSString* stringUUID = [UUID UUIDString];
return stringUUID;
}
After CFUUIDCreateString, you get a string you own. By using __bridge, you set str to the same string. So when you CFRelease(string) you do not own the memory backing str anymore...
To avoid this, either use a Cocoa method like #vijay says, or remove the CFRelease and use __bridge_transfer NSString* instead of __bridge. This tells the compiler you're transferring a CF object you own into the ARC world.
Per the documentation:
__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.
I have this method in a NSObject subclass:
- (CFStringRef)UTITypeForPath:(NSString *)path {
NSString *extension = [path pathExtension];
CFStringRef result = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
return result;
}
That generates this logic Analyzer warning:
Potential leak of an object stored into 'result'
The question is how to deal with it in a clean way:
I can't use CFAutorelease because it's iOS 7+ only.
Can't use Apple Core Foundation naming conventions (Create/Get rules) because it is an Objective-C method and not a C function (in contrast with this related question).
Also I wonder if this method should return a retained object in the first place.
Possible solutions:
Rename your method according to the naming conventions of the Objective-C Basic Memory Management Rules, e.g. start the method name with "copy":
- (CFStringRef)copyUTITypeForPath:(NSString *)path {
NSString *extension = [path pathExtension];
CFStringRef result = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
return result;
}
Then the caller of the method is responsible for releasing the CFStringRef eventually.
Or change your method to return NSString * instead of CFStringRef:
- (NSString *)UTITypeForPath:(NSString *)path {
NSString *extension = [path pathExtension];
CFStringRef result = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
return CFBridgingRelease(result);
}
In this case ARC will take care of releasing the NSString object.
ok I'm completely new to Obj-C and iOS. I'm just trying out a DataLogging example for the Pebble watch on iOS and changing a few things to log the accelerometer reading.
I have this function:
- (BOOL)dataLoggingService:(PBDataLoggingService *)service hasByteArrays:(const UInt8 *const)data numberOfItems:(UInt16)numberOfItems forDataLoggingSession:(PBDataLoggingSessionMetadata *)sessionMetadata{
//NSString *log = [NSString stringWithFormat:#"%s", data]; <-- this line compiles but display garbage on the view. So I try to use the line below.
NSString *log = [[NSString alloc] initWithData:(NSData *)data encoding:NSASCIIStringEncoding]; <-- this line gave build error as in the post title
[self addLogLine:log];
// We consumed the data, let the data logging service know:
return YES;
}
So any help would be greatly appreciated. Thanks.
First your error: it is telling you that cannot take a pointer to something which isn't an Objective-C object - you have a pointer to UInt8 - simply cast it to a pointer to an Objective-C object - NSData in your case as ARC (the Objective-C memory collector) doesn't know how to treat the result. You address this, if possible, with a bridge cast which tells ARC how to handle it. However in your case its not possible as you can't just cast an UInt8 * to an NSData * - the two refer to totally different things.
At a guess your method is passed a pointer to a sequence of bytes (hasByteArrays:) and the number of bytes in the sequence (numberOfItems), if that is correct then the method you are after is initWithBytes:length:encoding:, this method directly takes a pointer to a byte sequence. E.g.:
NSString *log = [[NSString alloc] initWithBytes:data
length:numberOfItems
encoding:NSASCIIStringEncoding];
Try with below approach:
- (BOOL)dataLoggingService:(PBDataLoggingService *)service hasByteArrays:(const UInt8 *const)data numberOfItems:(UInt16)numberOfItems forDataLoggingSession:(PBDataLoggingSessionMetadata *)sessionMetadata{
NSString *log = [NSString stringWithCString:(const char *)data encoding:NSUTF8StringEncoding];
[self addLogLine:log];
// We consumed the data, let the data logging service know:
return YES;
}
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.
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.