2014-04-01 9 views
1

我試圖調酒NSObject中的performSelector:withObject:rentzsch的交叉混合庫,這裏是代碼:混寫的NSObject的performSelector:withObject:給EXC_BAD_ACCESS爲什麼?

#import "NSObject+xxxx.h" 
#import "JRSwizzle.h" 

@implementation NSObject (xxxx) 
+ (void)load 
{ 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     NSError *error; 
     BOOL result = [[self class] jr_swizzleMethod:@selector(performSelector:withObject:) withMethod:@selector(xxxx_performSelector:withObject:) error:&error]; 
     if (!result || error) { 
      NSLog(@"Can't swizzle methods - %@", [error description]); 
     }else{ 
      NSLog(@"done"); 
     }  
    }); 
} 

- (id)xxxx_performSelector:(SEL)aSelector withObject:(id)object{ 
    NSLog(@"called %@ %@",NSStringFromSelector(aSelector), [object description]); 
    return [self xxxx_performSelector:aSelector withObject:object]; // when running it, Xcode stops and highlights this line 
} 

@end 

我的問題是,爲什麼它給了我EXC_BAD_ACCESS,當我運行它?
注意,它總是失敗,在同樣的觀點。而且,我只是在追查這些爭論(沒有其他魔法)。

以下是我在控制檯中看到:

2014-04-01 17:36:40.368 xxxApp debug[7322:90b] done 
2014-04-01 17:36:44.704 xxxApp debug[7322:90b] called layoutSublayersOfLayer: <CALayer: 0xcd75650> 
2014-04-01 17:36:45.536 xxxApp debug[7322:90b] called layoutSublayersOfLayer: <CALayer: 0xcd76240> 
2014-04-01 17:36:45.955 xxxApp debug[7322:90b] called layoutSublayersOfLayer: <CALayer: 0xcd76550> 
2014-04-01 17:36:46.170 xxxApp debug[7322:90b] called layoutSublayersOfLayer: <CALayer: 0xcd7bce0> 
2014-04-01 17:36:46.470 xxxApp debug[7322:90b] called layoutSublayersOfLayer: <UIWindowLayer: 0xcd78140> 

這裏是回溯:

(lldb) bt 
* thread #1: tid = 0x7bd49, 0x01e81de5 libobjc.A.dylib`objc_retain + 21, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x56e58965) 
    frame #0: 0x01e81de5 libobjc.A.dylib`objc_retain + 21 
    * frame #1: 0x000099f0 MyApp debug`-[NSObject(self=0x0f8432a0, _cmd=0x022bd138, aSelector=0x0083aae4, object=0x0f8424f0) xxxx_performSelector:withObject:] + 256 at NSObject+xxxx.m:44 
    frame #2: 0x007e745a QuartzCore`-[CALayer layoutSublayers] + 148 
    frame #3: 0x007db244 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 380 
    frame #4: 0x007e73a5 QuartzCore`-[CALayer layoutIfNeeded] + 160 
    frame #5: 0x00a55ae3 UIKit`-[UIViewController window:setupWithInterfaceOrientation:] + 304 
    frame #6: 0x0096baa7 UIKit`-[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 5212 
    frame #7: 0x0096a646 UIKit`-[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:] + 82 
    frame #8: 0x0096a518 UIKit`-[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] + 117 
    frame #9: 0x0096a5a0 UIKit`-[UIWindow _setRotatableViewOrientation:duration:force:] + 67 
    frame #10: 0x0096963a UIKit`__57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke + 120 
    frame #11: 0x0096959c UIKit`-[UIWindow _updateToInterfaceOrientation:duration:force:] + 400 
    frame #12: 0x0096a2f3 UIKit`-[UIWindow setAutorotates:forceUpdateInterfaceOrientation:] + 870 
    frame #13: 0x0096d8e6 UIKit`-[UIWindow setDelegate:] + 449 
    frame #14: 0x00a47b77 UIKit`-[UIViewController _tryBecomeRootViewControllerInWindow:] + 180 
    frame #15: 0x00963474 UIKit`-[UIWindow addRootViewControllerViewIfPossible] + 591 
    frame #16: 0x009635ef UIKit`-[UIWindow _setHidden:forced:] + 312 
    frame #17: 0x0096386b UIKit`-[UIWindow _orderFrontWithoutMakingKey] + 49 
    frame #18: 0x0096e3c8 UIKit`-[UIWindow makeKeyAndVisible] + 65 
    frame #19: 0x0091ebc0 UIKit`-[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 2097 
    frame #20: 0x00923667 UIKit`-[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 824 
    frame #21: 0x00937f92 UIKit`-[UIApplication handleEvent:withNewEvent:] + 3517 
    frame #22: 0x00938555 UIKit`-[UIApplication sendEvent:] + 85 
    frame #23: 0x00925250 UIKit`_UIApplicationHandleEvent + 683 
    frame #24: 0x0341af02 GraphicsServices`_PurpleEventCallback + 776 
    frame #25: 0x0341aa0d GraphicsServices`PurpleEventCallback + 46 
    frame #26: 0x02130ca5 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53 
    frame #27: 0x021309db CoreFoundation`__CFRunLoopDoSource1 + 523 
    frame #28: 0x0215b68c CoreFoundation`__CFRunLoopRun + 2156 
    frame #29: 0x0215a9d3 CoreFoundation`CFRunLoopRunSpecific + 467 
    frame #30: 0x0215a7eb CoreFoundation`CFRunLoopRunInMode + 123 
    frame #31: 0x00922d9c UIKit`-[UIApplication _run] + 840 
    frame #32: 0x00924f9b UIKit`UIApplicationMain + 1225 
    frame #33: 0x00002997 MyApp debug`main(argc=1, argv=0xbfffedac) + 135 at main.m:16 
+0

「+(無效)負載」 是一次僅調用。不需要「dispatch_once」。 – gagarwal

+0

看起來你忘了在你的問題中包含實際的錯誤,你顯示的輸出正在工作。堆棧錯誤的痕跡和你試圖弄清楚的東西也可能會幫助民衆幫助你。 – CRD

+0

@gagarwal,「dispatch_once」guaranties線程安全 – subzero

回答

3

簡短的回答:

你的問題是ARC,你應該能夠解決它在你的項目配置添加-fno-objc-arc只是這個文件(構建階段>編譯源代碼>編譯器標誌)另外,請確保您設置error到在swizzle之前,在load之前有210個 - 在ARC下自動發生。

說明:

ARC需要知道一個方法調用的返回類型,返回值的所有權,以便它能夠適當地管理的參考。這會導致一個問題performSelector:withObject在Objective-C的選擇是類型化的,因​​此ARC無法知道返回類型。該方法被聲明爲返回id,但有一個適當的選擇器實際上可能會返回void - ARC將嘗試保留返回值,並且在沒有返回任何內容時這樣做並不會很好,因爲返回值案件本質上是垃圾。

關閉ARC只是這一個文件沒有顯著的影響,你xxxx_performSelector:withObject:無需手動內存管理調用。

HTH

0

禁用ARC確實應該是一個快速解決您的問題,而是一個更好的解決方案可以通過服用要返回值加倍小心被發現。

ARC傾向於保留swizzled函數的返回值,如果返回非objC實例(甚至有時甚至是void),則會導致EXC_BAD_ACCESS。 請參閱https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/的第二個腳註,它在較長的細節中解釋了此問題,併爲您提供了一個合適的解決方案(基本上,轉換返回值以便編譯器知道它不應保留它)。

+0

對不起,但您的鏈接解決方案不適用於此。在這種情況下,選擇器是已知的(它的方法正在調試中),因此它是否返回一個不可保留的類型。在這種情況下,選擇器是一個變量'aSelector',因此它不能靜態地確定它的返回類型是什麼以及是否需要強制轉換。 – CRD

相關問題