Question

I'm playing around with swizzling, and can't quite figure this out. My alloc swizzle looks like this:

@interface UIAlertView (Custom)
+ (id)allocCustom;
@end

@implementation UIAlertView (Custom)    
+ (void)load
{
    Method original;
    Method mock;
    original = class_getClassMethod(self, @selector(alloc));
    mock = class_getClassMethod(self, @selector(allocCustom));
    method_exchangeImplementations(mock, original);
}

+ (id)allocCustom
{
    NSLog(@"Custom!");
    return [self allocCustom];
}    
@end

If I pause at the NSLog statement, which gets called repeatedly, in the call stack I see:

* thread #1: tid = 0x2c388a, 0x00003a2f My App`+[UIAlertView(self=0x03825c74, _cmd=0x0327e663) allocCustom] + 31 at MYClass.m:62, queue = 'com.apple.main-thread, stop reason = breakpoint 4.1
    frame #0: 0x00003a2f My App`+[UIAlertView(self=0x03825c74, _cmd=0x0327e663) allocCustom] + 31 at iBFGClientAppDelegate.m:62
    frame #1: 0x036c7b42 CoreFoundation`+[NSTimeZone timeZoneWithName:] + 34
    frame #2: 0x036c7a52 CoreFoundation`+[NSTimeZone systemTimeZone] + 626
    frame #3: 0x036c7767 CoreFoundation`+[NSTimeZone defaultTimeZone] + 71
    frame #4: 0x036e82cd CoreFoundation`CFTimeZoneCopyDefault + 45
    frame #5: 0x036f8b90 CoreFoundation`CFCalendarCreateWithIdentifier + 544
    frame #6: 0x03705f2c CoreFoundation`__CFLogCString + 124
    frame #7: 0x03705e6e CoreFoundation`_CFLogvEx + 270
    frame #8: 0x01581fbc Foundation`NSLogv + 137
    frame #9: 0x01581f28 Foundation`NSLog + 27
    frame #10: 0x00003a3a My App`+[UIAlertView(self=0x03825c74, _cmd=0x0327e663) allocCustom] + 42 at MYClass.m:62
    frame #11: 0x036c7b42 CoreFoundation`+[NSTimeZone timeZoneWithName:] + 34
    frame #12: 0x036c7a52 CoreFoundation`+[NSTimeZone systemTimeZone] + 626
    frame #13: 0x036c7767 CoreFoundation`+[NSTimeZone defaultTimeZone] + 71
    frame #14: 0x036e82cd CoreFoundation`CFTimeZoneCopyDefault + 45
    frame #15: 0x036f8b90 CoreFoundation`CFCalendarCreateWithIdentifier + 544
    frame #16: 0x03705f2c CoreFoundation`__CFLogCString + 124
    frame #17: 0x03705e6e CoreFoundation`_CFLogvEx + 270
    frame #18: 0x01581fbc Foundation`NSLogv + 137
    frame #19: 0x01581f28 Foundation`NSLog + 27
    frame #20: 0x00003a3a My App`+[UIAlertView(self=0x01800f3c, _cmd=0x0327e663) allocCustom] + 42 at MYClass.m:62
    frame #21: 0x023fb8ae UIKit`UIApplicationMain + 60
    frame #22: 0x0000293b My App`main(argc=1, argv=0xbfffedac) + 75 at main.m:18

It seems as though timeZoneWithName: is calling back into my custom alloc method. Clearly there is no recursion when alloc is not swizzled, but I'm confused what's happening here.

Was it helpful?

Solution

Your problem is most likely occurring because you're swizzling a method allocCustom on UIAlertView with the method alloc, which is a method on NSObject. From what I have found, you can successfully swizzle NSObject's alloc method, but it doesn't appear you can do this from a subclass. You can see evidence that this is the case by adding the following to your UIAlertView category:

+ (id)alloc
{
    return [super alloc];
}

By doing that, it will now work correctly. But since alloc is a method on NSObject and clearly not being overridden by UIAlertView anyway, you could just remove your method swizzling, and add your code to your overridden alloc method:

+ (id)alloc
{
    NSLog(@"Custom!");
    return [super alloc];
}

Now this might be a little dangerous to do in case Apple at a future time changed their implementation and for some reason were overriding alloc in UIAlertView. In that case, I think your implementation would override theirs, although I think the exact behavior is technically undefined.

OTHER TIPS

I'm no expert in method swizzling, but I'm guessing that because your allocCustom is a class method, self is actually referring to the class itself. What you really want is something like this

+(id) allocCustom {

 id obj = calloc(class_getInstanceSize(self), 1);
 obj->isa = self;
 obj->retainCount = 1;
 return obj;
}

this link may be of use to you: https://www.mikeash.com/pyblog/friday-qa-2013-01-25-lets-build-nsobject.html

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top