Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 为什么UIAlertView&x27;s alloc方法导致递归?_Objective C_Cocoa Touch_Core Foundation_Swizzling - Fatal编程技术网

Objective c 为什么UIAlertView&x27;s alloc方法导致递归?

Objective c 为什么UIAlertView&x27;s alloc方法导致递归?,objective-c,cocoa-touch,core-foundation,swizzling,Objective C,Cocoa Touch,Core Foundation,Swizzling,我在玩swizzling,但我不太明白这一点。我的alloc swizzle看起来像这样: @interface UIAlertView (Custom) + (id)allocCustom; @end @implementation UIAlertView (Custom) + (void)load { Method original; Method mock; original = class_getClassMethod(self, @selector(a

我在玩swizzling,但我不太明白这一点。我的alloc swizzle看起来像这样:

@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
如果我在NSLog语句处暂停(该语句会被反复调用),我会在调用堆栈中看到:

* 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

似乎timeZoneWithName:正在调用我的自定义alloc方法。显然,当alloc没有被swizzle时没有递归,但我对这里发生的事情感到困惑。

我不是方法swizzle方面的专家,但我猜,因为您的
allocCustom
是一个类方法,
self
实际上是指类本身。你真正想要的是这样的东西

+(id) allocCustom {

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

此链接可能对您有用:

您的问题最有可能发生,因为您正在使用
UIAlertView
上的方法
alloc
NSObject
上的方法
allocustom
进行滑动。根据我的发现,您可以成功地swizzle
NSObject
的alloc方法,但您似乎无法从子类执行此操作。通过将以下内容添加到您的
UIAlertView
类别中,您可以看到这种情况的证据:

+ (id)alloc
{
    return [super alloc];
}
通过这样做,它现在将正常工作。但由于
alloc
NSObject
上的一个方法,而且显然不会被
UIAlertView
覆盖,因此您可以删除方法swizzling,并将代码添加到被覆盖的
alloc
方法中:

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

现在这样做可能有点危险,以防苹果在将来更改其实现,并且出于某种原因在
UIAlertView
中覆盖
alloc
。在这种情况下,我认为您的实现将覆盖他们的实现,尽管我认为确切的行为在技术上是未定义的。

Allocustom已被禁用。在这种情况下,它调用alloc的真正实现。@rmaddy他正在滑动方法,因此它实际上调用的是真正的
alloc
,或者至少应该是。问题是
alloc
位于
NSObject
中,而不是
UIAlertView
。阅读我的答案。alloc也是一个类方法,所以我不认为这应该是一个问题。出于好奇,我尝试了这段代码,但它与calloc创建的void指针不匹配。是的!我应该意识到这一点。如果你看一下alloc实现的指针,它将与超级类相同,所以我真的在使用NSObject的alloc,这不是我想要做的。谢谢您可以使用类_replaceMethod()替换方法实现或添加新的方法实现,如果该类还没有自己的实现。@BenFlynn这也是为什么我复制您的代码时,这样做会导致程序在启动时立即崩溃,而不是只显示一次
UIAlertView
。仍然有点不清楚为什么会发生递归。显然,调用原始实现(现在名为
allocustom
)将无法工作,因为选择器不在NSObject的接口中。但我会假设一些“不响应选择器”错误。递归似乎违反直觉。@NikolaiRuhe:Allocustom调用NSLog,NSLog分配一个NSTimeZone(请参阅堆栈回溯),它再次调用Allocustom。