Basically, I want to print each time a class object is instantiated. The following code shows the intent.
@interface NSObject (ILogger)
+ (void)initialize;
@end
@implementation NSObject (ILogger)
+ (void)initialize
{
NSLog(@"Initializing %s", class_getName([self class]));
}
@end
This does not work because NSObject already has a +initialize method so this approach results in undefined behavior. The compiler also warns about the issue: warning: category is implementing a method which will also be implemented by its primary class
One idea would be to somehow swizzle +[NSObject initialize] and do the logging. How do I do that safely?
EDIT:
Maybe I'm using the wrong terminology but the goal is to know if a class is used at all in the app. If many objects of a class are created, there is no need to log every time, once is sufficient.

After Edit Answer
You are correct about use of
+[NSObject initialize]method for tracking the first use of a class. I don't know anything more appropriate for that. The swizzling would look like this:There are a few things to be advised about:
initializedoesn't fallback to theNSObjectimplementation (which is swizzled above) if derived classes have this method implemented AND don't have[super initialize];called. Thus for any custom class inherited from Cocoa classes either don't implement this method OR call[super initialize];somewhere in your implementation:Cocoa classes are rarely as straightforward as they look like. Quite a lot of interfaces and classes are hidden under the same name and sometimes the logs will be somewhat misleading (e.g. in place of
NSNumberyou will getNSValueclass reported). Thus, take any logging out of Foundation classes with a grain of salt and always double-check where it comes from (also be ready that those classes won't be reported at all).First use of
NSLogalso triggers some classes to initialise themselves and it make them to call+[NSObject initialize]. In order to avoid an infinite loop or bad_access errors I decided to useprintfto log the fact of initialisation in my implementation.Original Answer
The
+ (void)initializemethod has very little to do with objects instantiation, since it gets called for each Objective-C class shortly before it's first time used in your client code. It might be called multiple times if subclasses of a given class don't have this method implemented and never gets called afterward. Thus it's just a bad choice if you want to track objects instantiation.However there are still a few options you may want to employ to track occasions of objects instantiation.
Swizzling
-[NSObject init]First, I would consider
initmethod ofNSObject:It will work fine as long as instances falls back to the
-[NSObject init]method. Unfortunately quite a lot of Cocoa classes don't do that. Consider the following scenario:-[NSURL initWithString:]and-[NSMutableString initWithString:]somehow avoidsNSObject's default constructor being called. It will still work for any custom classes which don't have any fancy initialisation:Swizzling
+[NSObject alloc]Alternatively you can swizzle the
allocmethod:It will intercept almost all Cocoa classes instantiation (the exception must be some of the fabric methods, where class-specific optimisation takes place, e.g.
+[NSNumber numberWith..]family of methods), but there are other problems to be aware of. The allocated instances returned fromallocmethod are not always that straightforward. E.g. forNSMutableStringexample aboveNSLogwill printNSPlaceholderMutableString:That's is because Foundation framework uses Class Cluster design pattern heavily and instances returned by
allocare often some kind of abstract factories, which are later leveraged by Cocoa classes to make a concrete instance of the class requested.Both approaches have their own downsides, but I struggle to come up with anything more concise and reliable.