2014-08-27 1 views
12

내 프로젝트에는 Objective-C와 Swift 코드가 있습니다. 몇 가지 UITableView 구성을 정리하는 블록을 포함하는 속성이있는 개체가 있습니다. Objective-C에서 작동하지만 Swift를 사용할 때 충돌합니다.Objective-C 블록으로 호출하면 신속한 종료가 발생합니다.

문제를 가능한 한 최소화하면서 재현성을 유지했습니다.

// in Objective-C 
@interface MyClass : NSObject 
@property (copy, nonatomic) NSString* (^block)(); 
- (NSString *)callTheBlock; 
@end 

@implementation MyClass 
- (NSString *)callTheBlock { 
    if (self.block) { 
     return self.block(); 
    } else { 
     return @"There is no spoon"; 
    } 
} 
@end 

// In Swift 
// I actually have this in my AppDelegate to run when the app starts, but that shouldn't matter 

class AppDelegate: UIResponder, UIApplicationDelegate { 
    var myClass: MyClass? 

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool { 
    self.myClass = MyClass() 
    self.myClass?.block = {() -> String in 
     NSLog("In Closure") 
     var string = "String From Closure" // <-- "po string" correctly prints the string 
     return string // <-- This is where it crashes 
    } 

    let output = self.myClass?.callTheBlock() 
    NSLog("\(output)") 
... 

} 

나는 EXC_BAD_ACCESS을 받고 결국, 그래서 나는이 출시되고 뭔가 함께 할 수있는 뭔가가 추측하고있어 말아야 때,하지만 난 내가 잘못 뭘하는지 알아낼 수 없습니다. 내가 훨씬 더 이야기 스택 추적을 얻을

// MyClass 
@property (copy, nonatomic) NSString* (^block)(NSString *string); 

// Using it in Swift 
self.myClass?.block = { (inString: String!) -> String in 
    NSLog("In Closure") 
    var string = "String From Closure" 
    return string 
} 

: 나는 문자열을 매개 변수로 원하는 블록을 변경하는 경우,

* thread #1: tid = 0x4a8b6a, 0xbff2d9c8, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0xbff2d9c8) 
    * frame #0: 0xbff2d9c8 
    frame #1: 0xbff2d9e0 

그러나 :

스택 추적

은 아주 최소한의

* thread #1: tid = 0x4a9a38, 0x01b07e63 libobjc.A.dylib`objc_release + 19, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x40000013) 
    frame #0: 0x01b07e63 libobjc.A.dylib`objc_release + 19 
    * frame #1: 0x0005e442 MyApp`MyApp.AppDelegate.(inString=Some) -> (ObjectiveC.UIApplication, didFinishLaunchingWithOptions : Swift.Optional<ObjectiveC.NSDictionary>) -> Swift.Bool).(closure #1) + 594 at AppDelegate.swift:22 
    frame #2: 0x0005e4ad MyApp`reabstraction thunk helper from @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 77 at AppDelegate.swift:19 
    frame #3: 0x0005cbaa MyApp`partial apply forwarder for reabstraction thunk helper from @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 90 at AppDelegate.swift:0 
    frame #4: 0x0005e5e7 MyApp`reabstraction thunk helper from @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 71 at AppDelegate.swift:19 
    frame #5: 0x0005ce64 MyApp`partial apply forwarder for reabstraction thunk helper from @callee_owned (@in Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@out Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) + 132 at AppDelegate.swift:0 
    frame #6: 0x0005e7ee MyApp`reabstraction thunk helper from @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) -> (@owned Swift.ImplicitlyUnwrappedOptional<Swift.String>) to @callee_unowned @objc_block (@unowned Swift.ImplicitlyUnwrappedOptional<ObjectiveC.NSString>) -> (@autoreleased Swift.ImplicitlyUnwrappedOptional<ObjectiveC.NSString>) + 478 at AppDelegate.swift:19 
    frame #7: 0x0008fa3f MyApp`-[MyClass callTheBlock](self=0x7beadc50, _cmd=0x000edee6) + 143 at MyClass.m:38 
    frame #8: 0x0005bcf8 MyApp`MyApp.AppDelegate.application (application=0x7c160390, launchOptions=None, self=0x7c162d50)(ObjectiveC.UIApplication, didFinishLaunchingWithOptions : Swift.Optional<ObjectiveC.NSDictionary>) -> Swift.Bool + 1544 at AppDelegate.swift:24 
    frame #9: 0x0005cf55 MyApp`@objc MyApp.AppDelegate.application (MyApp.AppDelegate)(ObjectiveC.UIApplication, didFinishLaunchingWithOptions : Swift.Optional<ObjectiveC.NSDictionary>) -> Swift.Bool + 101 at AppDelegate.swift:0 
    frame #10: 0x0090d14f UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 309 
    frame #11: 0x0090daa1 UIKit`-[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1810 
    frame #12: 0x00912667 UIKit`-[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 824 
    frame #13: 0x00926f92 UIKit`-[UIApplication handleEvent:withNewEvent:] + 3517 
    frame #14: 0x00927555 UIKit`-[UIApplication sendEvent:] + 85 
    frame #15: 0x00914250 UIKit`_UIApplicationHandleEvent + 683 
    frame #16: 0x03b9df02 GraphicsServices`_PurpleEventCallback + 776 
    frame #17: 0x03b9da0d GraphicsServices`PurpleEventCallback + 46 
    frame #18: 0x01cf6ca5 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53 
    frame #19: 0x01cf69db CoreFoundation`__CFRunLoopDoSource1 + 523 
    frame #20: 0x01d2168c CoreFoundation`__CFRunLoopRun + 2156 
    frame #21: 0x01d209d3 CoreFoundation`CFRunLoopRunSpecific + 467 
    frame #22: 0x01d207eb CoreFoundation`CFRunLoopRunInMode + 123 
    frame #23: 0x00911d9c UIKit`-[UIApplication _run] + 840 
    frame #24: 0x00913f9b UIKit`UIApplicationMain + 1225 
    frame #25: 0x0005dbae MyApp`top_level_code + 78 at AppDelegate.swift:12 
    frame #26: 0x0005dbeb MyApp`main + 43 at AppDelegate.swift:0 
    frame #27: 0x024e3701 libdyld.dylib`start + 1 

편집 : 원래 비동기 적으로 호출되는 것과 관련이 있다고 생각했지만 r eproducible 나중에 직접 호출, 그래서 코드를 수정하고 그것을 반영하기 위해 스택 추적.

답변

12

나는 팝업 문서의 도움으로 그것을 알아 냈다! Objective-C를 다룰 때는 대부분 !이 필요합니다. Objective-C에는 Swift와 같은 Optionals 개념이 없기 때문에 이것이 확실하다고 확신합니다.

대신으로 내 폐쇄 정의 : 의미가

... self.myClass?.block = { (inString: String!) -> String! in ... 

그 팝업 설명서에 권장 무엇 때문에, :로 변경 때 작동

... self.myClass?.block = { (inString: String!) -> String in ... 

.

+2

사용하는 것이 더 좋을까요? 오히려! 그렇게하면 Swift 컴파일러는 런타임에 알아 내기보다는 시도하지 않고 nil에 액세스하지 않는 코드를 작성할 수 있습니다. –

+1

동의합니다. 스위프트 전용 코드를 작성하는 것이 좋습니다. 'inString'에 대해서는 아마도 좋은 생각 일 겁니다. 그러나 반환 값에 대해! 실제로 필요합니다. ? 실제로는 컴파일 오류입니다. 'MyClass' 블록에 대한 자동 생성 된 서명은'var block : ((String!) -> String!)입니다! {get set} '을 선택하십시오. – cjwirth

+0

우리는 단지 문제의 원인을 알아 내고 그 중 절반을 기다렸습니다. 그것은 그것이 었습니다 :/고마워요! –