Search code examples
iosswiftswift4core-mediaxcode11

Swift 4.2 if let fails with CMTime on Xcode 11.2


Ever since upgrading to Xcode 11.2 and building & running my app, Swift if let block is reporting failure which always used to work otherwise. Here is the code that fails.

public func remoteClient(receivedData data: [String : Any]?, fromPeer peerID: MCPeerID) {

  let params = data?["params"] as? [String:Any] 

  NSLog("Received image \(params!["timestamp"])")

  if let imgData = params?["image"] as? Data, let timeStamp = params?["timestamp"] as? CMTime
   {
           NSLog("Handling image response")
           handleImageResponse(imgData, timeStamp: timeStamp)

    } else {
           NSLog("Image response failed")
    }

}

And here is what gets printed on console

  2019-11-02 23:47:52.342324+0530 MyApp [312:9779] Received image Optional(CMTime: {34515835925000/1000000000 = 34515.836})
  2019-11-02 23:47:52.343251+0530 MyApp[312:9779] Image response failed

Removing the check for CMTime in 'if let' solves the issue, but then how do I extract CMTime from params dictionary?

  1. What has suddenly changed when building with Xcode 11.2, I wonder?

  2. params!["timestamp"] is printing CMTime in the console, what fails in the if let assignment then?

And it's CMTime that is failing, I tried this:

   if let imgData = params?["image"] as? Data, let timeStamp = params?["timestamp"] as? Any {

      let time = timeStamp as! CMTime

   }

And I get a crash:

 Could not cast value of type 'CMTimeAsValue' (0x10ce321d8) to '__C.CMTime' (0x2355bab00).

Solution

  • Apparently the time is stored in the dictionary as an NSValue wrapping a CMTime. In that case the correct way to extract the time is

    if let val = params["timestamp"] as? NSValue {
        let time = val.timeValue
        // ...
    }
    

    See also NSValue(time:) and NSValue.timeValue.