Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Macro capturing Self in block

I have a problem with the below macro which i use to log various bits of information

#define JELogVerbose(fmt, ...)  
DDLogVerbose((@"%@ %@ - " fmt), NSStringFromClass([self class]),
                                NSStringFromSelector(_cmd), ##__VA_ARGS__)

The problem occurs when this final macro is used inside a block, it will obviously strongly capture self which can be problematic.

Here are some requirements for a solution:

  1. It can be a multiline macro where you define weakSelf but that doesn't solve it as you can get a redefinition of the __weak pointer you create.
  2. Using __FILE__ or __PRETTY_FUNCTION__ because they capture will capture the superclass rather than the subclass. So in the case of an abstract that class that is used to create many instances the logging does not differentiate between each instance. Capturing the current class is absolutely necessary
  3. The solution only requires modification of the macro or some other global config option to fix this without the need to add additional extensive libraries
like image 558
Ben Chester Avatar asked Apr 29 '14 16:04

Ben Chester


2 Answers

UPDATE:

Now I see what's the problem. This macro should work:

#define LOG_CLASS_NAME(obj) typedef typeof(*(obj)) SelfType; \
                            NSLog(@"typeof self is %@", [SelfType class]);

LOG_CLASS_NAME(self) // typeof self is JEViewController

because typeof(*self) is resolved at compile time there is no need for the compiler to retain self instance. That means it is safe to use this macro inside block.

First answer:

How about __PRETTY_FUNCTION__ ? It prints a class name as well as selector.

NSLog("func: %s", __PRETTY_FUNCTION__); // func: [UIViewController viewDidAppear:]
like image 169
MarekR Avatar answered Oct 31 '22 03:10

MarekR


Maybe use this: https://github.com/jspahrsummers/libextobjc

#import "EXTScope.h"

/* some code */

@weakify(self);
[SomeClass runOnBackgroundCode:^{
    @strongify(self);
    /* do something */
}];

/* some code */

I use this solution for quite some time - no need to add weekSelf or anything else.

like image 33
Kamil Tustanowski Avatar answered Oct 31 '22 03:10

Kamil Tustanowski