Reputation: 185
I have read about __bridge
, _bridge_retain
and _bridge_transfer
and did some experiments. However the output does not coincide with what I was expecting. In particular, I have the following code:
@interface ViewController ()
@property (nonatomic, strong) NSString *test;
@end
@implementation ViewController
CFStringRef cfString;
- (void)viewDidLoad
{
[super viewDidLoad];
self.test = @"123";
cfString = (__bridge CFStringRef)self.test;
self.test = nil;
}
- (void)viewDidAppear:(BOOL)animated
{
NSLog(@"%@", cfString);
NSLog(@"%@", self.test);
}
I expect the program to crash, based on the following reasoning: _bridge
does not transfer ownership, so while casting self.test
to cfString
, there is no retainCount increment. Once self.test
is set to nil
, ARC
will step in and dealloc the string. So that portion of memory is freed, but cfString
is still pointing there, resulting in a pointer bad access exception. In contrast to my reasoning, the output is 123 and null, and of course the program does not crash.
Moreover, if I replace
self.test = nil;
with
CFRelease(cfString);
I expect the program to crash as well due to a similar reasoning. Even stranger is that the output is now 123 and 123.
Can anyone kindly elaborate why? Btw, the term ownership always troubles me, some explanation will be greatly appreciated.
Upvotes: 1
Views: 145
Reputation: 3955
The problem is that you base your example on a literal NSString value.
In objective-C, constant NSString (constant values known at compile time) are never released. In fact, their main memory managment methods are like:
+ (id)allocWithZone:(NSZone *)zone {
id _uniqueInstance = [self _singletonInstanceOfClass];
if( _uniqueInstance == nil )
_uniqueInstance = [super allocWithZone:zone];
return _uniqueInstance;
}
- (id)copyWithZone:(NSZone *)zone {
(void)zone;
return self;
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax; // denotes an object that cannot be released
}
- (oneway void)release {
//do nothing
return;
}
- (id)autorelease {
return self;
}
As you can see, releasing them is not possible.
Upvotes: 1
Reputation: 4093
Your problem is that you're using a constant string. This is put straight into the programs memory so the reference is unexpectedly remaining valid despite the fact that it shouldn't. Use something less constant than a constant string and your program will brake like you think.
Upvotes: 2