openURL in APPDelegate conversion error NSString -

2019-04-15 07:55发布

I'm currently developing an iOS application that integrates Facebook and I'm having a bit of a problem while investigating this with Swift (with ObjC I have no problems).

The thing is, this is the method that gets executed in the appDelegate when coming from another APP (in this case FB in a WebBrowser):

func application(
    application: UIApplication,
    openURL url: NSURL,
    sourceApplication: NSString,
    annotation: AnyObject)
    -> Bool { 
       let appString : String = sourceApplication as String // Try to convert format => EXCEPTION
       let appString : String = String(sourceApplication)   // 'SSS' Suggestion: EXCEPTION
       println(sourceApplication) // Try to print the value => EXCEPTION
       return FBAppCall.handleOpenURL(url, sourceApplication:sourceApplication,
            withSession:session) // With Parse => EXCEPTION
}

And inside that method I'm having real trouble with the 'sourceApplication' parameter. I try to use it, I get an exception. I try to convert it, another exception...can't even log its value because it crashes when accessing its value. Changing the parameter type in the functions signature to String neither worked.

This is the error I'm getting:

EXEC_BAD_ACCESS

And I've been able to track down until I could read this that it's definitely a valuable hint:

ObjectiveC.NSString.__conversion (ObjectiveC.NSString)() -> Swift.String

Could it be an iOS8 bug? Any of you has had this problem and/or knows how to solve it?

4条回答
够拽才男人
2楼-- · 2019-04-15 07:57

I don't get this in the playground. Could be a iOS 8 bug as you suggest But for the sake of trying, can you try

let appString : String = String(sourceApplication)
查看更多
冷血范
3楼-- · 2019-04-15 08:11

For FB Messenger here's what I did to get some better handling in my AppDelegate. Most of the ideas were taken straight from the FB IOS documentation and ported to Swift.

Why did I feel like I should write an additional reply? I've got some experience with Swift, but felt like I wasted enough time trying to get the right set of code to do what I wanted with FB Messenger. Hopefully the raw code is useful to someone, just to consolidate a lot of bits and pieces and save some time.

NOTE: This does not include all the AppDelegate lifecycle methods you'll want/need, but hopefully it's a head start

@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, FBSDKMessengerURLHandlerDelegate {

var window: UIWindow?
var messengerUrlHandler: FBSDKMessengerURLHandler?
var cancelContext : FBSDKMessengerURLHandlerCancelContext?
var composerContext : FBSDKMessengerURLHandlerOpenFromComposerContext?
var replyContext: FBSDKMessengerURLHandlerReplyContext?

// Facebook Messenger
enum MessengerShareMode : Int {
    case MessengerShareModeCancel
    case MessengerShareModeSend
    case MessengerShareModeComposer
    case MessengerShareModeReply
}

// shareMode holds state indicating which flow the user is in.
// Return the corresponding FBSDKMessengerContext based on that state.
var shareMode : MessengerShareMode?

/*
* Initialize the FB messenger handler and set self as the delegate.
*/
func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
    YARAppearance.setAppearance()

    let rootController = TabBarController()
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    self.window!.rootViewController = rootController
    self.window!.makeKeyAndVisible()

    // Facebook messenger handling
    self.messengerUrlHandler = FBSDKMessengerURLHandler()
    if (self.messengerUrlHandler != nil) {
        self.messengerUrlHandler!.delegate = self
    }
    return true
}

/*
* Handle the cancel context flow.
*/
func messengerURLHandler(messengerURLHandler: FBSDKMessengerURLHandler!,
    didHandleCancelWithContext context: FBSDKMessengerURLHandlerCancelContext!) {
        self.cancelContext = context
        self.shareMode = .MessengerShareModeCancel
}

/*
* When people enter your app through the composer in Messenger,
* this delegate function will be called.
*/
func messengerURLHandler(messengerURLHandler: FBSDKMessengerURLHandler!,
    didHandleOpenFromComposerWithContext context: FBSDKMessengerURLHandlerOpenFromComposerContext!) {
        self.composerContext = context
        self.shareMode = .MessengerShareModeComposer
}

/*
* When people enter your app through the "Reply" button on content
* this delegate function will be called.
*/
func messengerURLHandler(messengerURLHandler: FBSDKMessengerURLHandler!,
    didHandleReplyWithContext context: FBSDKMessengerURLHandlerReplyContext!) {
    self.replyContext = context
    self.shareMode = .MessengerShareModeReply
}

/*
* Handle URL calls from external applications, particularly Messenger
*/
func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
    let wasHandled:Bool = self.messengerUrlHandler!.openURL(url, sourceApplication: sourceApplication)
    return wasHandled
}

/*
* A way to access the context objects elsewhere
*/
func getContextForShareMode() -> FBSDKMessengerContext? {
    // shareMode holds state indicating which flow the user is in.
    // Return the corresponding FBSDKMessengerContext based on that state.
    if (shareMode == .MessengerShareModeSend) {
        // Force a send flow by returning a broadcast context.
        return FBSDKMessengerBroadcastContext()

    } else if (shareMode == .MessengerShareModeComposer) {
        // Force the composer flow by returning the composer context.
        return self.composerContext!

    } else if (shareMode == .MessengerShareModeReply) {
        // Force the reply flow by returning the reply context.
        return self.replyContext!
    }
    return nil
}
}
查看更多
时光不老,我们不散
4楼-- · 2019-04-15 08:15

This is working for me (with FacebookSDK):

func application(application: UIApplication, openURL url: NSURL, sourceApplication: NSString?, annotation: AnyObject) -> Bool {
    var wasHandled:Bool = FBAppCall.handleOpenURL(url, sourceApplication: sourceApplication)
    return wasHandled
}
查看更多
成全新的幸福
5楼-- · 2019-04-15 08:16

You have made two mistakes:

  1. The function declaration from the app Delegate is func application(application: UIApplication!, openURL url: NSURL!, sourceApplication: String!, annotation: AnyObject!) -> Bool : sourceApplication is an optional String value not NSString.

  2. Since sourceApplication is an optional it may return nil value (In your case returning nil) . Type casting nil to String is not safe , therefore it is crashing.

Solutions :

  1. No type casting is required in your case Since returned value is String type
  2. Use optional form type cast operator as? to safely type cast i.e

if let appString = sourceApplication { println(appString as? String) }

查看更多
登录 后发表回答