弱引用的通用typeof自身引用

34

我正在尝试使用 typeof 来创建一个弱引用以避免在块中出现保留周期。

当我第一次阅读相关资料时,似乎约定俗成的方法是使用 __block typeof(self) bself = self;,虽然这样编译可以通过,但是使用 __block 避免保留周期已经不再起作用了,现在应该使用 __weak 来代替。

然而,__weak typeof(self) bself = self; 会导致错误:

The type 'typeof (self)' (aka 'TUAccountsViewController *const __strong') already has retainment attributes set on it

是否有一种方法可以使用 typeof 或其他调用来通用地创建对 self 的弱引用?


使用 typeof 确定类型的动机是什么,而不是显式地使用类(TUAccountsViewController)名称? - Chris Gummer
我想创建一个通用的定义,可以适用于当前实例。这一切始于这个提交和讨论:https://github.com/kgn/BBlock/commit/14ccc46830ea29dec50408a5bd7a17e247b72c20 - keegan3d
10个回答

37

在最新的Clang版本 Apple clang version 4.0 (tags/Apple/clang-421.1.48) (基于LLVM 3.1svn),即Xcode 4.4+中,__typeof__((__typeof__(self))self) 技巧不再必要。现在只需编译 __weak typeof(self) bself = self; 这一行即可。


1
嗯 - 我刚发现在Xcode 4.6.1中我需要"_ _ typeof(self) _ _"(去掉空格)。 - David H

32

14
这是正确的做法:__typeof__(self) __weak wself = self;请注意,在类型前面使用__weak是"技术上不正确"的。 - Alejandro
keegan3d:你能否编辑你的答案以反映Aleph的评论?他说得对。 - Christian Kienle

18

正确的做法是

__weak ActualClassName* weakSelf = self;
宏只会让变量含义不明确,也不清楚你实际在做什么,而且还会在代码中添加非可移植的元语言。
如果您需要比ActualClassName提供的类更通用的版本,则不再处理self,因为定义self的地方也定义了self的类。
在这种情况下,您应该在继承树中使用最接近的基类名称,例如NSObject或更好,永远不要使用id。
__weak MyBaseClassName* weakObject = object;

16

通用Weakself引用(无需导入 + 代码片段)


我的经验是使用:

__typeof__(self) __weak weakSelf = self;

注意所有权限定符应在实际变量之前。

当使用它时,会非常明显正在发生什么,并且可以将其制作成Xcode中的便捷代码片段,这使得在任何需要的项目或类中使用它变得更加容易。(我使用“ws”作为片段的完成快捷方式)

嗯..我需要一个弱引用在这里..

ws{return}

搞定了。不需要在未来的项目中再包含头文件,只需使用片段。


Xcode代码片段


标题:通用Weak Self Reference
平台:所有
语言:Objective-C
完成快捷方式:ws
完成范围:函数或方法
代码:__typeof__(self) __weak weakSelf = self;


编辑:根据评论添加了有关所有权限定符位置的注意事项,以及Xcode片段信息


1
所有权限定符号应该放在实际变量之前。你可以在最新的苹果文档中看到这一点。 例如: MyClass *__weak myWeakReference; MyClass *__unsafe_unretained myUnsafeReference;https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html - Steve M
@SteveM 正确。大多数人没有意识到这一点,因为编译器会“宽容”这种违规行为。在这个例子中,我们有 TYPE | OWNERSHIP | VARIABLE NAME = VALUE; - Beltalowda

3

我认为使用这个可以:

__weak __typeof(&*self)weakSelf = self;

它引用了AFNetworking的AFURLConnectionOperation.m代码。


没问题,而且对于旧版本的clang也具有向后兼容性,但是索引无法帮助您,而@Brane上面的建议将向您显示调用者/被调用者。如果您不是在构建github库,则我会选择那条路线。 - Scott Corscadden

3

你尝试过检查C语言方言吗?

前往工程导航器 -> 工程 -> 目标 -> 构建设置

在那里找到C语言方言。将其从c11更改为GNU99。

希望对你有所帮助 :)


3
为什么不直接使用?
__weak id bself = self;

1
我考虑过这一点,但是仍需要进行强制类型转换才能访问对象上的任何属性,例如:在类型为“__weak id const”的对象上找不到属性“isAddingAccount” - keegan3d
1
如果您的对象有共同点,请声明具有此属性的协议,并声明__weak id <YourProtocol> bself = self; - Denis Mikhaylov
1
这些都是很好的建议,只是不够通用,不过我想我想要的可能不存在... - keegan3d

1

declareBlockSafe(self)然后在块内使用blk(self)。Self可以是任何变量或实例变量。对于属性和方法返回,请使用declareBlockSafeAs。

如果导入Mike Ash的出色MAZeroingWeakRef,则也适用于非ARC。 https://github.com/mikeash/MAZeroingWeakRef

#if __has_feature(objc_arc)

#define declareBlockSafe(__obj__) __weak typeof(__obj__) __tmpblk##__obj__ = __obj__
#define blockSafe(__obj__) __tmpblk##__obj__
#define blk(__obj__) blockSafe(__obj__)

#define declareBlockSafeAs(__obj__, __name__) \
__weak typeof((__obj__)) __tmpblk##__name__ = (__obj__)

#else

#define declareBlockSafe(__obj__) MAZeroingWeakRef *__tmpblk##__obj__ = [MAZeroingWeakRef refWithTarget:__obj__]
#define blockSafe(__obj__) ((typeof(__obj__))__tmpblk##__obj__##.target)
#define blk(__obj__) blockSafe(__obj__)

#define declareBlockSafeAs(__obj__, __name__) \
MAZeroingWeakRef *__tmpblk##__name__ = (__obj__)
#endif

你在ARC中不一定需要使用blk(),只是为了让宏在非ARC情况下也能以同样的方式使用。


1
我有这个宏。
#define weaken(object) __typeof__(self) __weak weakSelf = object

"我是这样使用它的:"
weaken(self);
//The block referencing weakSelf goes here

0

__unsafe_unretained是怎么样的?它不像__weak那么安全,但这是我能想到的唯一选择。另外,你为什么要使用typeof()?


我想创建一个通用的 define,可以适用于当前 self 的任何实例。这一切始于这个提交和讨论:https://github.com/kgn/BBlock/commit/14ccc46830ea29dec50408a5bd7a17e247b72c20 - keegan3d
不幸的是,__unsafe_unretained 会产生相同的错误:**类型 'typeof (self)'(又名 'TUAccountsViewController *const __strong')已经设置了保留属性**。 - keegan3d
1
这能在NSObject类别中使用吗? -(instancetype)weakReference { __weak id obj = self; return obj; } - lbrndnr
看起来这个很管用!我的定义看起来像这样:#define BBlockWeakSelf __weak typeof([self weakReference]),使用方法如下:BBlockWeakSelf wself = self;。完整代码在这里:https://github.com/kgn/BBlock/commit/195f6289092ac31e9b50c45e3457fade446eec5b - keegan3d
这在调试时可以运行,但在进行归档发布时会出现以下错误:4. Running pass 'Aggressive Dead Code Elimination' on function '@"\01-[NSObject(BBlockWeakReference) weakReference]"'。完整错误信息请参考:http://cl.ly/102r1D1b0x4304240c3X - keegan3d
这似乎是个有效的方法,它可以实现归档:#define BBlockWeakSelf __weak typeof((typeof(self))self)。如果您发现任何问题,请告诉我。 - keegan3d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接