【问题标题】:How to declare a pointer member variable in a class with ARC in Objective C?如何在Objective C中使用ARC在类中声明指针成员变量?
【发布时间】:2012-05-17 13:46:24
【问题描述】:

我有一个类 RemoteImageLoader,它有一个 loadImage 方法:

- (void) loadImage: (NSString*) url setTarget:(NSData **)target;

我在这里使用了 NSData** 因为我需要间接返回 NSData* ,就像一些典型的方法一样:

- (BOOL)save:(NSError**)

由于该方法实际上会调用另一个异步方法,因此我必须将目标保存为成员变量,以便以后可以访问它。但是当我定义一个 NSData ** 成员变量时:

@interface RemoteImageLoader : NSObject    
@property NSData** target;
@end

编译器抱怨“指向非常量类型 'NSData*' 的指针没有明确的所有权”。我在谷歌上做了一些搜索,但没有找到答案。谁能帮我解决这个问题?非常感谢

我已经尝试将声明替换为

@interface RemoteImageLoader : NSObject    
@property NSData * __autoreleasing * target;
@end

但问题依然存在

【问题讨论】:

  • Automatic Reference Counting: Pointer to non-const type 'NSError *' with no explicit ownership 的可能副本。基本逻辑相同。哦,SO也有一个搜索栏:)
  • 检查 ARC 过渡文档。我相信你的情况类似于 NSError。
  • 您不需要需要间接返回 NSData。进行间接返回的唯一原因是您还需要一个 direct 返回值。当方法返回成功/失败BOOL 或失败时对象/nil 时,使用NSError ** 参数技术。你的方法没有使用它的返回值,所以你应该只返回新的NSData;这将使每个人的生活变得更简单(您和客户编码人员)。

标签: objective-c ios memory pointers automatic-ref-counting


【解决方案1】:

ARC Transition Notes 建议您使用 __autoreleasing 声明指向 NSData 和 NSError 对象的间接指针,例如 (NSData * __autoreleasing *)target;

__autoreleasing 被称为 生命周期限定符,它告诉编译器返回对象的自动释放实例。

因此,需要重写您的方法签名。

- (void) loadImage: (NSString*) url setTarget:(NSData* __autoreleasing *)target;

请注意,__autoreleasing 对象的寿命极短。将您的 NSData** 声明为 __strong 以覆盖默认的 __autoreleasing 以获得更长的生命周期。

【讨论】:

  • 谢谢@CodaFi,实际上我之前已经找到了 NSError* 示例并尝试了解决方案,但问题仍然存在。 NSData** 或 (NSData* __autoreleasing *) 方法 loadImage 的签名都可以。但是对于成员变量,都没有编译成功。
  • 这个答案解决了 OP 所面临的确切技术问题,代价是忽略了 e 试图做一个坏主意的事实,至少有两个原因。
【解决方案2】:

我认为你的方法签名会造成麻烦。调用者很可能会假设一旦您的方法返回,指向的指针就会被填充。同样,它们很可能会传递一个不会长期有效的堆栈变量的地址。最后,您的方法无法让调用者知道指向的指针何时已被值填充。

你最好从调用者那里获取一个完成块。完成块将接收一个 NSData 指针作为参数。比如:

- (void) loadImage: (NSString*) url completionHandler:(void (^)(NSData* data))block;

这也反映了我认为您正在使用的底层框架 API,它总是有利于减少“阻抗不匹配”。

至于您从编译器遇到的具体狭窄问题,我怀疑问题是当您分配给*target 时,编译器无法知道它是否应该发出保留和释放。它希望您显式声明指向指针的所有权特征。我目前无法检查,但我想将其声明为 __strong NSData** target 会起作用。也就是说,它对target 是否拥有它所指向的东西不感兴趣,因为一个人不能拥有一个指针。它对target 指向的NSData* 指针是否拥有它指向的NSData 对象感兴趣。

【讨论】:

  • 哇,是的,通过引用异步传回一个值……这是我整个星期听到的最糟糕的想法之一。
【解决方案3】:

如果没有看到您的代码,我无法确定您要做什么,但您为什么要尝试创建指向 NSData 对象的指针(这是指向 NSData 的指针)。因为您正在创建一个指向指针的指针,这可能就是您收到错误的原因。尝试删除其中一个指针,看看会发生什么。

【讨论】:

  • 因为我需要间接返回 NSData* ,就像一些典型的方法一样: - (BOOL)save:(NSError**);
【解决方案4】:

通常,当您在 ARC 之外执行此类操作时,您会执行以下操作:

NSData* returnedParm;
[someObj doSomething:&returnedParm];

在调用方。我没有看到您与上面的returnedParm 相当。 (我从未在 ARC 上尝试过这个,但我认为基础知识必须相似。)

将一个属性声明为NSData** 是在声明一个指向非对象的指针,它不会被保留(因为没有要保留的对象)。

我的猜测是你应该将你的函数原型化为:

-(void)doSomething:(NSData* __autoreleasing*)theReturnParm

并使用*theReturnParm = something;在该函数内分配给它。

然后在调用方,您会将 returnedParm 作为自动释放的值(因此,如果您想保留它,您应该相对快速地将其分配给 strong 指针)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 2012-12-23
    相关资源
    最近更新 更多