Nina
Nina

Reputation: 93

ARKit – Cannot decode ARAnchor in MCSession

I'm testing out Apple's Multiuser AR demo app with ARKit 2.0 that was introduced in WWDC 2018: Creating a multiuser AR experience.

The documentation says that after each device relocalizes to the same World Map, only the information needed to recreate each user action is shared among devices (e.g. if the user taps on the screen and a 3D object appears, only that new object's ARAnchor should be sent to other devices). For me, while it shows all the 3D characters that were placed by the sending device before it captured and sent a World Map, it doesn't show any objects that are added after the World Map has been sent. The error I'm getting says:

// can't decode data recieved from peer.

Has anyone had this issue and knows what it's about?

I haven't changed anything in the demo code.

Upvotes: 6

Views: 512

Answers (2)

Andy Jazz
Andy Jazz

Reputation: 58113

In MultipeerConnectivity ARSession several peers share data among each other. But sent and received data must be, at first, archived and then unarchived using two instance methods of NSKeyedArchiver and NSKeyedUnarchiver classes:

func archive(worldMap: ARWorldMap) throws {

    let data = try NSKeyedArchiver.archivedData(withRootObject: worldMap,
                                         requiringSecureCoding: true)

    try data.write(to: worldMapURL, options: [.atomic])
}

and:

func unarchive(worldMapData: Data) -> ARWorldMap? {

    guard let unarchievedData = try? NSKeyedUnarchiver.unarchivedObject(ofClass: ARWorldMap.self, 
                                                                           from: worldMapData)
    else { return nil }

    return unarchievedData
}

Hence, if you get the following message in Xcode Console:

"can't decode data received from peer"

it means the error occurred while transferring or unarchiving a ARWorldMap data.

Upvotes: 0

Shawn Ma
Shawn Ma

Reputation: 41

I had the same trouble but I kind of solved it in this way.

(1)first create a variable to check if the world map has send.

var worldMapHasInited: Bool = false

(2)Then in func shareSession(_ button: UIButton) add this line to the end below

self.multipeerSession.sendToAllPeers(data)

self.worldMapHasInited = true

(3)And finally in func receivedData(_ data: Data, from peer: MCPeerID)

check if the world map has sent, if is sent, skip checking if the data contains world map or not.

    if !worldMapHasInited {
        if let worldMap = try NSKeyedUnarchiver.unarchivedObject(ofClass: ARWorldMap.self, from: data)
        {
            //....
            // when received world map, set the receiver's 
            // worldMapHasInited to true  
            self.worldMapHasInited = true                                              
        }
    }
    else
        if let anchor = try NSKeyedUnarchiver.unarchivedObject(ofClass: ARAnchor.self, from: data) {
            // ...
    }

This will directly check if the data contains anchor or not.

Upvotes: 0

Related Questions