- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我不明白这个,除非是因为我要释放属性(property)而不是伊娃。有人可以阐明这个问题吗?
self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000];
[self.dataToBeLoaded release];
警告是不属于调用者的对象的引用计数的不正确减少
。
dataToBeLoaded
属性具有与其 setter 关联的保留属性。
我的理解是 alloc init 增加了保留计数,而属性分配增加了保留计数。由于我只保留一次,所以我在分配后立即释放它。
更新——一些实验结果:
由于我在下面的评论中指出我收到了关于保留属性对合成 setter 的作用的矛盾建议,我想我会使用上面的代码做一个小实验,并用一些日志记录进行修改:
NSLog(@"retain 1 = %d", [dataToBeLoaded_ retainCount]);
self.dataToBeLoaded = [[NSMutableData alloc] initWithLength:10000];
NSLog(@"retain 2 = %d", [dataToBeLoaded_ retainCount]);
[self.dataToBeLoaded release];
NSLog(@"retain 3 = %d", [dataToBeLoaded_ retainCount]);
每个日志语句的结果分别为 0、2 和 1。
显然,不可能进入 alloc 或 init 代码来查看保留计数从 0 到 1 再到 2。我本可以子类化 NSMutableData 类,但我时间不够。
我知道很多人都说你不能依赖 retainCount 属性的值,但我所拥有的似乎是一致的,我希望在代码的短范围内有合理的行为,如示例中所示。所以我倾向于相信先前的建议是正确的——保留属性是在 setter 中包含保留的 promise 。所以在这里我有来自 alloc/init 的保留和来自对 setter 的调用的保留。因此,保留计数设置为 2。
当我运行这段代码时:
NSMutableData *theData;
NSLog(@"retain 1 = %d", [theData retainCount]);
theData= [[NSMutableData alloc] initWithLength:10000];
NSLog(@"retain 1a = %d", [theData retainCount]);
self.dataToBeLoaded = theData;
NSLog(@"retain 2 = %d", [theData retainCount]);
[self.dataToBeLoaded release];
NSLog(@"retain 3 = %d", [theData retainCount]);
每个日志语句的保留计数为 0、1、2、1。
所以我有证据表明 setter 正在提供 retain
。这与其说是暗示,不如说是 promise ,因为它确实在发生。
我愿意接受其他解释。我不想为此傲慢自大。我只想弄清楚正在发生的事情。我看来警告(在这个问题的主题中)真的是虚假的,不用担心。
另一个实验是使用 assign
而不是 retain
作为 @property 语句中的属性。使用相同的代码:
NSMutableData *theData;
NSLog(@"retain 1 = %d", [theData retainCount]);
theData= [[NSMutableData alloc] initWithLength:10000];
NSLog(@"retain 1a = %d", [theData retainCount]);
self.dataToBeLoaded = theData;
NSLog(@"retain 2 = %d", [theData retainCount]);
[self.dataToBeLoaded release];
NSLog(@"retain 3 = %d", [theData retainCount]);
每个日志的保留计数为 0、1、1(setter 没有保留),然后是错误消息:消息已发送到已释放的实例
。上一个版本已将保留计数设置为零,这触发了释放。
更新 2
最后的更新——当合成的 setter 被您自己的代码覆盖时,保留属性将不再被观察到,除非您的 setter 明确包含它。显然(这与我在这里的其他线程中被告知的内容相矛盾)如果你想要的话,你必须在 setter 中包含你自己的保留。虽然我没有在这里测试它,但您可能需要先释放旧实例,否则它会被泄露。
此自定义 setter 不再具有 @propety 声明的属性:
- (void) setDataToBeLoaded:(NSMutableData *)dataToBeLoaded {
dataToBeLoaded_ = dataToBeLoaded;
}
这是有道理的。覆盖合成的 setter 并覆盖所有已声明的属性。使用合成 setter,并在合成实现中观察声明的属性。
@property 属性表示关于如何实现合成 setter 的“ promise ”。一旦您编写了自定义 setter,您就只能靠自己了。
最佳答案
关键是要仔细思考下面的代码在做什么。为了清楚起见,我将完整地写出来:
[self setDataToBeLoaded:[[NSMutableData alloc] initWithLength:10000]];
这将创建一个保留计数为 +1 的对象并将其传递给 setDataToBeLoaded:
。 (*) 然后它会丢弃对该对象的引用,将其泄漏。
[[self dataToBeLoaded] release];
这会调用 dataToBeLoaded
并释放返回的对象。 dataToBeLoaded
返回的对象与传递给 setDataToBeLoaded:
的对象没有任何保证。您可能认为它们是相同的,并且查看您的代码您可能会说服自己它总是以这种方式运行,但这不是 API promise 。
Antwan贴出的代码是正确的:
NSMutableData *data = [[NSMutableData alloc] initWithLength:1000];
self.dataToBeLoaded = data;
[data release];
这会创建一个保留计数为 +1 的对象。然后将它传递给一个方法,然后释放它。
或者,如果你愿意使用自动释放池,你可以将其简化为:
self.dataToBeLoaded = [NSMutableData dataWithLength:1000];
(*) 从技术上讲,这会向 self
传递一条消息,该消息可能会或可能不会导致调用此方法,但这会使问题变得困惑。对于大多数目的,假设它是一个方法调用。但是,不要假装它只是设置属性。它真的会调用一些方法。
编辑:
也许这段代码会使问题更清楚一些。它表示常见的缓存解决方案:
.h
@interface MYObject : NSObject
@property (nonatomic, readwrite, strong) NSString *stuff;
@end
.m
@interface MYObject ()
@property (nonatomic, readwrite, weak) MYStuffManager *manager;
@implementation MYObject
... Initialize manager ...
- (NSString*)stuff {
return [self.manager stuffForObject:self];
}
- (void)setStuff:(NSString *)stuff {
[self.manager setStuff:stuff forObject:self];
}
现在也许 manager
在后台做了一些傻事。也许它缓存了 stuff
的各种副本。也许它复制了它们。也许它将它们包装到其他对象中。重要的是您不能依赖 -stuff
总是返回您传递给 -setStuff:
的同一对象。所以你当然不应该发布它。
请注意,标题中没有任何内容表明这一点,也没有任何内容应该表明这一点。这不关来电者的事。但是,如果调用者释放了 -stuff
的结果,那么您将遇到难以调试的崩溃。
@synthesize
只是编写一些繁琐代码的简写(实现stuff
和setStuff:
的代码作为读写ivar) .但没有人说您必须为您的属性使用 @synthesize
。
关于ios - 此时不拥有的引用计数的不正确减少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10568152/
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: template pass by value or const reference or…? 以下对于将函数
我用相同的参数列表重载了一个运算符两次。但返回类型不同: T& operator()(par_list){blablabla} const T& operator()(par_list){bla
假设我有实现接口(interface) I 的 Activity A。我的 ViewModel 类 (VM) 持有对实现接口(interface) I 的对象的引用: class A extends
PHP 如何解释 &$this ?为什么允许? 我遇到了以下问题,这看起来像是 PHP 7.1 和 7.2 中的错误。它与 &$this 引用和跨命名空间调用以及 call_user_func_arr
谁能解释一下下面“&”的作用: class TEST { } $abc =& new TEST(); 我知道这是引用。但是有人可以说明我为什么以及什么时候需要这样的东西吗?或者给我指向一个对此有很好解
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。 C++ 引用 vs 指针 引用很容易与指针混淆,它们之间有三
目录 引言 背景 结论 引言 我选择写C++中的引用是因为我感觉大多数人误解了引用。而我之所以有这个感受是因为我主持过很多C++的面试,并且我很少
Perl 中的引用是指一个标量类型可以指向变量、数组、哈希表(也叫关联数组)甚至函数,可以应用在程序的任何地方 创建引用 定义变量的时候,在变量名前面加个 \,就得到了这个变量的一个引用 $sc
我编写了一个将从主脚本加载的 Perl 模块。该模块使用在主脚本中定义的子程序(我不是维护者)。 对于主脚本中的一个子例程,需要扩展,但我不想修补主脚本。相反,我想覆盖我的模块中的函数并保存对原始子例
我花了几个小时试图掌握 F# Quotations,但我遇到了一些障碍。我的要求是从可区分的联合类型中取出简单的函数(只是整数、+、-、/、*)并生成一个表达式树,最终将用于生成 C 代码。我知道使用
很多时候,问题(尤其是那些标记为 regex 的问题)询问验证密码的方法。似乎用户通常会寻求密码验证方法,包括确保密码包含特定字符、匹配特定模式和/或遵守最少字符数。这篇文章旨在帮助用户找到合适的密码
我想通过 MIN 函数内的地址(例如,C800)引用包含文本的最后一个单元格。你能帮忙吗? Sub Set_Formula() ' ----------------------------- Dim
使用常规的 for 循环,我可以做类似的事情: for (let i = 0; i < objects.length; i++) { delete objects[i]; } 常规的 for-
在 Cucumber 中,您定义了定义 BDD 语法的步骤;例如,您的测试可能有: When I navigate to step 3 然后你可以定义一个步骤: When /^I navigate t
这是什么UnaryExpression的目的,以及应该怎样使用? 最佳答案 它需要一个 Expression对象并用另一个 Expression 包裹它.例如,如果您有一个用于 lambda 的表达式
给出以下内容 $("#identifier div:first, #idetifier2").fadeOut(300,function() { // I need to reference jus
我不知道我要找的东西的正确术语,但我要找的是一个完整的引用,可以放在双引号之间的语句,比如 *, node()、@* 以及所有列出的 here加上任何其他存在的。 我链接到的答案提供了一些细节,但还
This question's answers are a community effort。编辑现有答案以改善此职位。它当前不接受新的答案或互动。 这是什么? 这是常见问答的集合。这也是一个社区Wi
Closed. This question does not meet Stack Overflow guidelines。它当前不接受答案。 想改善这个问题吗?更新问题,以便将其作为on-topic
考虑下一个代码: fn get_ref(slice: &'a Vec, f: fn(&'a Vec) -> R) -> R where R: 'a, { f(slice) } fn m
我是一名优秀的程序员,十分优秀!