IOS Contacts 框架,如何将 imageData 编码和解码为 String 并通过 infoDiscovery 字典与 MPC 广告商一起发送

IOS Contacts framework, how to encode and decode imageData into String and send it via infoDiscovery dictionary with MPC advertiser

我正在使用 IOS 联系人框架 来检索 iPhone 用户联系人的 imageData。如果 imageData 可用,我检索它并需要将其 encode 成一个字符串。这是因为我正在使用 Multipeer Connectivity Framework 并且我想在浏览的对等点列表中的对等点显示名称旁边显示一个图像。我通过 MCNearbyServiceAdvertiser class 的 discoveryInfo 字典参数发送编码的 imageData初始化时。

为了实现这一点,我尝试使用 UTF8Base64imageData 进行编码,但都失败了。

这是我为 UTF8 编码过程尝试过的代码:

// Retrieve user image and initials from global userContact variable  

func retrieveUserImageAndInitials() -> Dictionary<String,String> {  
    let userFirstNameInitial = "\(userContact.firstName[userContact.firstName.startIndex])"
    let userLastNameInitial = "\(userContact.lastName[userContact.lastName.startIndex])"

    if userContact.imageData != nil {
        print("Image data found")

        if let dataString = NSString(data: userContact.imageData!, encoding: NSUTF8StringEncoding) as String! {
            print("Image data encoded successfully")
            return ["firstNameInitial":userFirstNameInitial, "lastNameInitial":userLastNameInitial,"imageData":dataString]
        }
        else {
            print("Image data encoded with failures")
            return ["firstNameInitial":userFirstNameInitial, "lastNameInitial":userLastNameInitial]
        }
    }
    else {
        print("Image data not found")
        return ["firstNameInitial":userFirstNameInitial, "lastNameInitial":userLastNameInitial]
    }
}  

这是使用 UTF8 解码的代码:

func browser(browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {  
    foundPeers.append(peerID)

    let userInitials = info!["firstNameInitial"]! + info!["lastNameInitial"]!

    if let dataString = info!["imageData"] {
        print("Data string found")

        if let imageData = dataString.dataUsingEncoding(NSUTF8StringEncoding) {
            print("Image data fetched succesfully!")
            imagesOfFoundPeers.append(UIImage(data: imageData)!)
        }
        else {
            print("Image data not fetched")
            imagesOfFoundPeers.append(imageFromText(userInitials,
                font: UIFont(name: "Pacifico", size: 24.0)!, maxWidth: 50.0, color: UIColor.mainColor()))
        }
    }
    else {
        print("Data string not found")
        print("Image with initials used instead")
        imagesOfFoundPeers.append(imageFromText(userInitials,
            font: UIFont(name: "Pacifico", size: 24.0)!, maxWidth: 50.0, color: UIColor.mainColor()))
    }

    delegate?.foundPeer()
}  

在使用 UTF8 编码时,我从编码过程中获得的字符串打印为 nil,因此代码甚至无法通过 advertiser

这是我为 Base64 编码过程尝试过的代码:

// Retrieve user image and initials from global userContact variable
func retrieveUserImageAndInitials() -> Dictionary<String,String> {
    let userFirstNameInitial = "\(userContact.firstName[userContact.firstName.startIndex])"
    let userLastNameInitial = "\(userContact.lastName[userContact.lastName.startIndex])"

    if userContact.imageData != nil {
        print("Image data found")

        let dataString = userContact.imageData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)

        print("Image data encoded successfully")
        return ["firstNameInitial":userFirstNameInitial, "lastNameInitial":userLastNameInitial,"imageData":dataString]

    }
    else {
        print("Image data not found")
        return ["firstNameInitial":userFirstNameInitial, "lastNameInitial":userLastNameInitial]
    }
}  

这是使用 Base64 解码的代码:

func browser(browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?)
{
    foundPeers.append(peerID)

    let userInitials = info!["firstNameInitial"]! + info!["lastNameInitial"]!

    if let dataString = info!["imageData"] {
        print("Data string found")

        let imageData = NSData(base64EncodedString: dataString, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
        let userImage = UIImage(data: imageData!)
        print("Image data fetched succesfully!")
        imagesOfFoundPeers.append(userImage!)

    }
    else {
        print("Data string not found")
        print("Image with initials used instead")
        imagesOfFoundPeers.append(imageFromText(userInitials,
            font: UIFont(name: "Pacifico", size: 24.0)!, maxWidth: 50.0, color: UIColor.mainColor()))
    }

    delegate?.foundPeer()
}  

在使用 Base64 编码时,代码确实将数据编码为字符串,但应用程序终止,因为字典 discoveryInfo 包含编码过程产生的字符串被视为 MCNearbyServiceAdvertiser 的无效参数。

它抛出以下消息:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid discoveryInfo passed to MCNearbyServiceAdvertiser'

这是 MCNearbyServiceAdvertiser 和所有 MPCManagement 对象的初始化:

override init()
{
    super.init()

    userContact = retrieveUserContact()

    peer = MCPeerID(displayName: userContact.fullName)

    dataSession = MCSession(peer: peer)
    dataSession.delegate = self

    deviceBrowser = MCNearbyServiceBrowser(peer: peer, serviceType: "dummy-mpc")
    deviceBrowser.delegate = self

    deviceAdvertiser = MCNearbyServiceAdvertiser(peer: peer, discoveryInfo: retrieveUserImageAndInitials(), serviceType: "dummy-mpc")
    deviceAdvertiser.delegate = self
}  

我是不是做错了什么,或者我还有什么其他选择来编码和发送该图像数据?

提前致谢!

一般来说,Base64 是正确的方法,因为它可以对任意二进制数据进行编码。您的代码是正确的,尽管我不会在解码器中使用 IgnoreUnknownCharacters 选项,因为没有理由引入意外字符,因此此设置可能会向您隐藏错误。 UTF-8 永远不会工作,因为它不是任意二进制数据的编码方案。

您的代码失败,因为 discoveryInfo 字典对 key-value 对的大小有限制。

来自documentation of MCNearbyServiceAdvertiser

info

A dictionary of key-value pairs that are made available to browsers. Each key and value must be an NSString object.

This data is advertised using a Bonjour TXT record, encoded according to RFC 6763 (section 6). As a result:

  • The key-value pair must be no longer than 255 bytes (total) when encoded in UTF-8 format with an equals sign (=) between the key and the value.
  • Keys cannot contain an equals sign.

您可以通过大幅降低图像的分辨率来解决此问题,但生成的图像可能无法识别。您也可以将图像拆分到多个字典键中,但这可能会导致发现性能非常差,因为您将尝试通过 DNS TXT 记录传输大量数据。

您可能需要考虑在 建立对等连接后 传输图像数据,而不是将其作为发现的一部分。或者,您可以按照文档中的建议在 Bonjour 之上构建自己的发现机制:

If the data you need to provide is too large to fit within these constraints, you should create a custom discovery class using Bonjour for discovery and your choice of networking protocols for exchanging the information.