34

I am trying to figure out a way to use typeof to create a weak reference to self for use in blocks to avoid retain cycles.

When I first read about this it seems that the convention was to use __block typeof(self) bself = self;, which compiles but using __block to avoid retain cycles doesn't work anymore and __weak should be used instead.

However __weak typeof(self) bself = self; results in an error:

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

Is there a way to use typeof or another call to generically create a weak reference to self?

Kazuki Sakamoto
  • 13,929
  • 2
  • 34
  • 96
keegan3d
  • 10,357
  • 9
  • 53
  • 77
  • What's the motivation for using typeof to determine the type, instead of just using the class (TUAccountsViewController) name explicitly? – Chris Gummer Jun 05 '12 at 07:20
  • I want to make a generic define that can work for whatever the current instance of self is. It all started from this commit and discussion: https://github.com/kgn/BBlock/commit/14ccc46830ea29dec50408a5bd7a17e247b72c20 – keegan3d Jun 05 '12 at 17:39

10 Answers10

37

In the latest clang version Apple clang version 4.0 (tags/Apple/clang-421.1.48) (based on LLVM 3.1svn), i.e. Xcode 4.4+, the __typeof__((__typeof__(self))self) trick is not necessary anymore. The __weak typeof(self) bself = self; line will compile just fine.

0xced
  • 25,219
  • 10
  • 103
  • 255
32

This works!

__typeof__(o) __weak

Which I've defined in my BBlock project as BBlockWeakSelf which can be used like this:

BBlockWeakSelf wself = self;

https://github.com/kgn/BBlock/blob/master/BBlock.h

Edited based on Aleph7's response.

keegan3d
  • 10,357
  • 9
  • 53
  • 77
  • 14
    This is the right way of doing it: `__typeof__(self) __weak wself = self;` Note that having __weak before the type is ["technically incorrect"](http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html). – Alejandro Dec 10 '12 at 21:38
  • keegan3d: Could you edit your answer to reflect Alephs comment? What he says is correct. – Christian Kienle Mar 16 '13 at 16:41
18

The correct way to do this is

__weak ActualClassName* weakSelf = self;

Macros only make it unclear what the variable actually is, and what you're actually doing with it, in addition to adding non-portable meta-language to your code.

If you need a more generic version of the class than ActualClassName provides, you aren't dealing with self anymore, since where self is defined, so is the class of self defined.

In those cases, you should use the closest base class name in your inheritance tree, NSObject or better, never id, e.g.

__weak MyBaseClassName* weakObject = object;
Brane
  • 810
  • 1
  • 6
  • 13
16

Generic Weakself Reference (No Import Required + Snippet)


In my experience, the way to go is to use:

__typeof__(self) __weak weakSelf = self;

Note how the ownership qualifier belongs in front of the actual variable.

It's very apparent what's happening when it is used and it can be made into a handy code snippet in Xcode which makes it even easier to use in any project or class where this is needed. (I use "ws" as the snippet's completion shortcut)

Hmm.. I need a weak reference here..

ws{return}

Done. No need to ever include a header in future projects for this, just use the snippet.


Xcode Snippet


Title: Generic Weak Self Reference
Platform: All
Language: Objective-C
Completion Shortcut: ws
Completion Scopes: Function or Method
Code: __typeof__(self) __weak weakSelf = self;


Edit: Added note about ownership qualifier position based on comments, and Xcode Snippet Info

Community
  • 1
  • 1
Beltalowda
  • 4,558
  • 2
  • 25
  • 33
  • 1
    The ownership qualifier belongs in front of the actual variable. You can see this in any of the latest Apple Documentation. for example: MyClass * __weak myWeakReference; MyClass * __unsafe_unretained myUnsafeReference; https://developer.apple.com/library/ios/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html – Steve M Feb 19 '14 at 20:29
  • @SteveM Correct. Most people don't realize this because the compiler "forgives" that transgression. In this example we have `TYPE | OWNERSHIP | VARIABLE NAME = VALUE;` – Beltalowda Feb 20 '14 at 16:23
3

why don't just use

__weak id bself = self;
Denis Mikhaylov
  • 2,035
  • 21
  • 24
  • 1
    I thought about that but a cast would still be needed to access any properties on the object, for example: `Property 'isAddingAccount' not found on object of type '__weak id const'` – keegan3d Jun 05 '12 at 06:25
  • 1
    or if your objects have something in common declare protocol with this property and declare __weak id bself = self; – Denis Mikhaylov Jun 05 '12 at 07:12
  • 1
    These are all good suggestions, just not as generic as I was hoping for. But what I want may not exist... – keegan3d Jun 05 '12 at 08:34
3

i think use this to be ok:

__weak __typeof(&*self)weakSelf = self;

it reference AFNetworking's AFURLConnectionOperation.m codes.

kitsionchen
  • 67
  • 1
  • 2
  • It's ok, and is further-backwards-compatible for older clang versions, but indexing can't help you whereas @Brane's suggestion above will show you callers/callees. If you aren't building a github library, I'd go that route instead. – Scott Corscadden Oct 31 '13 at 17:45
3

Did you try check the C Language Dialect?

Go to Project Navigator -> Project -> Target -> Build Settings

There look for C Language Dialect. Change it from c11 to GNU99.

I hope it helps :)

Ricardo Anjos
  • 1,417
  • 18
  • 22
1

declareBlockSafe( self ) then blk( self ) inside the block. Self can be any variable or instance variable. Use declareBlockSafeAs for properties and method returns.

Also works with non-ARC if you import Mike Ash's splendid MAZeroingWeakRef. 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

You don't REALLY need blk() for ARC, it's just so that the macros can be used in the same way for non-ARC.

Rod
  • 52,748
  • 3
  • 38
  • 55
SeruK
  • 987
  • 1
  • 8
  • 14
1

I have this macro

#define weaken(object) __typeof__(self) __weak weakSelf = object

And i use it like this

weaken(self);
//The block referencing weakSelf goes here
Maciej Swic
  • 11,139
  • 8
  • 52
  • 68
0

What about __unsafe_unretained? That's not as safe as __weak but it's the only thing I could think of. Also, why do you use typeof()?

lbrndnr
  • 3,361
  • 2
  • 24
  • 34
  • I want to make a generic `define` that can work for whatever the current instance of `self` is. It all started from this commit and discussion: https://github.com/kgn/BBlock/commit/14ccc46830ea29dec50408a5bd7a17e247b72c20 – keegan3d Jun 05 '12 at 16:55
  • Unfortunately `__unsafe_unretained` yields the same error: **The type 'typeof (self)' (aka 'TUAccountsViewController *const __strong') already has retainment attributes set on it** – keegan3d Jun 05 '12 at 17:41
  • 1
    Does this work in a category of NSObject? -(instancetype)weakReference { __weak id obj = self; return obj; } – lbrndnr Jun 05 '12 at 18:28
  • That appears to do the trick! My define looks like this: `#define BBlockWeakSelf __weak typeof([self weakReference])` and it's used like this: `BBlockWeakSelf wself = self;`. Full code here: https://github.com/kgn/BBlock/commit/195f6289092ac31e9b50c45e3457fade446eec5b – keegan3d Jun 06 '12 at 08:08
  • This works in debug but when doing an archive release this error occurs: `4. Running pass 'Aggressive Dead Code Elimination' on function '@"\01-[NSObject(BBlockWeakReference) weakReference]"'`. Full Error: http://cl.ly/102r1D1b0x4304240c3X – keegan3d Jun 06 '12 at 08:14
  • This seems to do the trick and it archives: `#define BBlockWeakSelf __weak typeof((typeof(self))self)`. Lemme know if you see any problems with this. – keegan3d Jun 06 '12 at 09:16