我正在尝试了解有关手动引用计数的更多信息。 我创建了一个带有实例变量的类及其使用手动版本的getter / setter:
@interface Foo: NSObject {
id bar;
}
- (id)bar;
- (void)setBar:(id)value;
@end
@implementation Foo
- (id)bar {
return bar;
}
- (void)setBar:(NSNumber*)value {
[bar release];
bar = value;
}
@end
然后我就这样使用它:
int main() {
Foo *f = [[Foo alloc] init];
NSNumber *n = [[NSNumber alloc] initWithInteger: 3];
[f setBar: n];
[n release];
NSLog(@"%@\n", [[f bar] description]);
return 0;
}
我使用Address Sanitizer编译它并且我期望它陷阱,因为[[f bar] description]
应该在解除分配的对象上调用方法:
clang -fno-objc-arc -fsanitize=address -g -framework Foundation main.m
ASAN_OPTIONS=detect_leaks=1
但令我惊讶的是它运作良好!
2018-04-08 18:18:38.470300-0400 a.out[3457:291626] 3
然后我用NSDate
尝试了它,看它是否有所作为:
NSDate *n = [[NSDate alloc] init];
[c setBar: n];
[n release];
确实如此:
ASAN:DEADLYSIGNAL
=================================================================
==3379==ERROR: AddressSanitizer: SEGV on unknown address 0x7fff0b800018 (pc 0x7fff577f3e9d bp 0x7ffee4491670 sp 0x7ffee44915f8 T0)
==3379==The signal is caused by a READ memory access.
#0 0x7fff577f3e9c in objc_msgSend (libobjc.A.dylib:x86_64h+0x6e9c)
#1 0x7fff5841b014 in start (libdyld.dylib:x86_64+0x1014)
...
我调整NSNumber
的{{1}}方法,发现它没有被调用:
dealloc
与@interface Dealloc: NSObject
@end
@implementation Dealloc
- (void)dealloc {
NSLog(@"dealloc");
}
@end
...
method_exchangeImplementations(class_getInstanceMethod([Dealloc class], @selector(dealloc)),
class_getInstanceMethod([NSNumber class], @selector(dealloc)));
2018-04-08 18:18:38.470300-0400 a.out[3457:291626] 3
相比:
NSDate
所以我接着尝试了一堆其他类:
2018-04-08 18:21:03.899490-0400 a.out[3483:293512] dealloc
2018-04-08 18:21:03.900538-0400 a.out[3483:293512] dealloc
2018-04-08 18:21:03.900598-0400 a.out[3483:293512] dealloc
取消分配NSString
获得分配NSMeasurement
取消分配NSArray
取消分配NSDictionary
取消分配NSData
取消分配这里发生了什么?为什么只有其中一些被Address Sanitizer接收
更新
正如Rob和rmaddy指出的那样,对于NSURL
的小整数值,它被存储为标记指针,实际上并没有分配任何额外的内存:
NSNumber
最后一位设置为1,表示它已被标记,前4位的所有内容都是整数42。
对于带(lldb) p/t n (__NSCFNumber *) $1 = 0b0000000000000000000000000000000000000000000000000010101000100111 (int)42
的常量字符串(__NSCFConstantString
),它似乎不是标记指针,因为最后一位未设置,但它仍然是一个奇怪的地址:
[[NSString alloc] initWithString:@"blah"]
(lldb) p n
(__NSCFConstantString *) $1 = 0x0000000100002068 @"blah"
(lldb) p/t n
(__NSCFConstantString *) $2 = 0b0000000000000000000000000000000100000000000000000010000001101000 @"blah"
和NSDate
都显示在“正常”地址范围内> 0x600000000000。
空NSMeasurement
的地址在此范围内,但不会解除分配,但填充对象会:
NSArray
答案 0 :(得分:2)
如果您想学习手动保留版本,有两个重要细节:
TextBox lastBox = BoxGrid.Children.OfType<TextBox>().Last();
ResultBox.Text = lastBox.Text;
。子类NSObject
并在所述子类上进行实验。框架对象通常会有各种奇怪的实现细节...... 令人惊讶。NSObject
或retainCount
。由此产生的价值在现实世界中毫无意义。将保留计数视为增量;你导致它增加,每增加一次,你必须使它减少。另外,浏览Xcode调试器中的内存窗格。