APPDelegate 中的 openURL 转换错误 NSString -> String (Swift & iOS8)

Posted

技术标签:

【中文标题】APPDelegate 中的 openURL 转换错误 NSString -> String (Swift & iOS8)【英文标题】:openURL in APPDelegate conversion error NSString -> String (Swift & iOS8) 【发布时间】:2014-06-16 09:36:20 【问题描述】:

我目前正在开发一个集成 Facebook 的 ios 应用程序,但在使用 Swift 进行调查时遇到了一些问题(使用 ObjC 我没有问题)。

问题是,当来自另一个 APP(在本例中为 WebBrowser 中的 FB)时,这是在 appDelegate 中执行的方法:

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

在该方法中,我在使用“sourceApplication”参数时遇到了真正的问题。我尝试使用它,我得到一个例外。我尝试转换它,另一个异常......甚至无法记录它的值,因为它在访问它的值时崩溃。将函数签名中的参数类型更改为 String 无效。

这是我得到的错误:

EXEC_BAD_ACCESS

我一直在追查,直到我读到这绝对是一个有价值的提示:

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

会不会是 iOS8 的错误? 你们中有人遇到过这个问题和/或知道如何解决吗?

【问题讨论】:

FWIW with ObjC 我也在 iOS8.1 下得到空值。在 iOS7 下,相同的代码可以正常工作。从Mail iOS7下的sourceApplication是“com.apple.mobilemail”。现在它为空。 【参考方案1】:

你犯了两个错误:

    来自app Delegate 的函数声明是func application(application: UIApplication!, openURL url: NSURL!, sourceApplication: String!, annotation: AnyObject!) -> Bool:sourceApplication 是一个可选的String 值而不是NSString。

    由于 sourceApplication 是可选的,它可能会返回 nil 值(在您的情况下返回 nil)。将 nil 类型转换为 String 是不安全的,因此会崩溃。

解决方案:

    您的情况不需要类型转换,因为返回值是 String 类型 使用可选的表单类型转换运算符 as? 来安全地进行类型转换,即

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

【讨论】:

好吧,你是对的!感谢您指出了这一点。解析文档不好,方法签名说明是这样。现在的问题是为什么我在那里得到一个零字符串,但我想那是另一回事。感谢您的帮助和良好的解释。只是一件额外的事情,如果它是可选的,不应该是“字符串?”而不是“字符串!” 当前版本的 Swift 文档 Xcode 6.0.1 没有将 sourceApplication 显示为可选。然而,它似乎经常(总是?)作为 nil 传递......见***.com/questions/25980451/… 感谢@combinatorial 的评论,我可以解决从今天扩展启动应用程序的问题。如果您使用 xCode 6.0 (6A313),使用自动完成后,您必须添加“?”到 sourceApplication 以便您的应用不会崩溃【参考方案2】:

这对我有用(使用 FacebookSDK):

func application(application: UIApplication, openURL url: NSURL, sourceApplication: NSString?, annotation: AnyObject) -> Bool 
    var wasHandled:Bool = FBAppCall.handleOpenURL(url, sourceApplication: sourceApplication)
    return wasHandled

【讨论】:

【参考方案3】:

我在操场上看不到这个。正如您所建议的,可能是 iOS 8 错误 但是为了尝试,你可以试试吗

let appString : String = String(sourceApplication)

【讨论】:

感谢您帮助我解决 SSS。不幸的是,它没有用,结果和以前一样。【参考方案4】:

对于 FB Messenger,这是我为在 AppDelegate 中获得更好处理所做的工作。大多数想法直接取自 FB IOS documentation 并移植到 Swift。

为什么我觉得我应该写一个额外的回复?我有一些使用 Swift 的经验,但我觉得我浪费了足够多的时间来尝试获取正确的代码集来做我想做的事需要 FB Messenger。希望原始代码对某些人有用,只是为了整合很多点点滴滴并节省一些时间。

注意:这不包括您想要/需要的所有 AppDelegate 生命周期方法,但希望这是一个良好的开端

@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


【讨论】:

以上是关于APPDelegate 中的 openURL 转换错误 NSString -> String (Swift & iOS8)的主要内容,如果未能解决你的问题,请参考以下文章

iOS AppDelegate.m:处理 openUrl RCTLinkingManager 和 Twitter - 方法 'application:openURL:options:' 的重复声明

UIApplication sharedApplication openURL

通过 appDelegate openURL 函数呈现 viewController(在导航层次结构中)

Swift 中的应用程序 openURL

什么是注释:openURL 方法中的(id)注释?

如何在swiftUI中获得类似appdelegate的东西