2014-04-01 2 views
1

은 여기, NSObject의의 performSelector:withObject:rentzsch의 스위 즐링 라이브러리를 스위 즐링 (swizzle)을 시도하는 코드입니다 해요 : 그것은 나에게 EXC_BAD_ACCESS를 제공하는 이유swizzling 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 

내 질문은, 내가 그것을 실행 해요있다?
항상 같은 지점에서 실패합니다. 그리고 또한, 나는 그 논쟁을 추적하고 있습니다 (다른 마법은 없습니다). 여기

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

"+ (void) load"는 한 번만 호출됩니다. "dispatch_once"가 필요 없습니다. – gagarwal

+0

질문에 실제 오류를 포함하는 것을 잊어 버린 것처럼 보입니다. 표시되는 결과가 효과적입니다. 오류의 스택 추적과 그것을 파악하기 위해 시도한 것은 아마도 민중이 당신을 도울 수있을 것입니다. – CRD

+0

@gagarwal, "dispatch_once"는 스레드 안전성을 보장합니다. – subzero

답변

3

짧은 답변 :

귀하의 문제는 해결할 수있을 것입니다, ARC입니다 프로젝트 설정 (빌드 단계> 컴파일 소스> 컴파일러 플래그)에서이 파일에 -fno-objc-arc을 추가하여 error을으로 설정했는지 확인하십시오 210에서 load을 누르십시오. ARC에서 자동으로 발생합니다.

설명 : ARC가 적절하게 참조를 관리 할 수 ​​있도록, 메소드 호출의 반환 형식 및 반환 값의 소유권을 알 필요가

. 이로 인해 performSelector:withObject에서 Objective-C의 선택자가 형식화되지 않으므로 ARC가 반환 유형을 알 수 없습니다. 이 메서드는 id을 반환하도록 선언되었지만 적절한 선택기를 사용하면 실제로 void을 반환 할 수 있습니다. - ARC는 반환 값을 유지하려고 시도하지만 아무 것도 실제로 반환되지 않으면 해당 반환 값으로 작동하지 않습니다. 케이스는 본질적으로 쓰레기입니다.

이 파일 하나에 대해서만 ARC를 끄면 큰 영향이 없으므로 xxxx_performSelector:withObject:에는 수동 메모리 관리 호출이 필요 없습니다. ARC는 참으로 문제에 대한 빠른 수정,하지만 더 나은 솔루션을해야 비활성화

HTH

0

는 반환 할 값의 각별한주의를 복용하여 볼 수 있습니다.

ARC는 swizzled 함수의 반환 값을 유지하는 경향이 있는데, 이는 objC가 아닌 인스턴스가 반환 될 때 (또는 때로는 void에서도) EXC_BAD_ACCESS를 발생시킵니다. 두 번째 각주 https://blog.newrelic.com/2014/04/16/right-way-to-swizzle/을 참조하십시오.이 문제는 더 긴 세부 사항을 설명하며 적절한 해결책을 제공합니다 (기본적으로 반환 값을 캐스팅하여 컴파일러에서 유지해야 함을 알 수 있음).

+0

죄송합니다. 링크 된 솔루션은 여기에 적용되지 않습니다. 이 경우 선택기가 알려지며 (메서드가 swizzled 됨) 유지할 수없는 형식을 반환하는지 여부가 결정됩니다. 이 경우 selector는 변수 'aSelector'이므로 반환 유형이 무엇이며 캐스트가 필요한지 정적으로 결정할 수 없습니다. – CRD

관련 문제