You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用NSCoder保存RoomPlan的CapturedRoom对象?

解决RoomPlan中CapturedRoom无法通过NSCoding保存的问题

问题背景

开发房间平面图APP时,原方案用ARWorldMap搭配ARPlaneAnchors实现,切换到RoomPlan Beta版的CapturedRoom后,沿用之前基于NSCoding保存ARWorldMap的方式,抛出错误:

-[__SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x141c18110

原CapturedRoom编码类代码:

import RoomPlan

class RoomPlanScan: NSObject, NSCoding {
    
    var capturedRoom: CapturedRoom
    var title: String
    var notes: String
    
    init(capturedRoom: CapturedRoom, title: String, notes: String) {
        self.capturedRoom = capturedRoom
        self.title = title
        self.notes = notes
    }
    
    required convenience init?(coder: NSCoder) {
        guard let capturedRoom = coder.decodeObject(forKey: "capturedRoom") as? CapturedRoom,
              let title = coder.decodeObject(forKey: "title") as? String,
              let notes = coder.decodeObject(forKey: "notes") as? String
        else { return nil }
        
        self.init(
            capturedRoom: capturedRoom,
            title: title,
            notes: notes
        )
    }
    
    func encode(with coder: NSCoder) {
        coder.encode(capturedRoom, forKey: "capturedRoom")
        coder.encode(title, forKey: "title")
        coder.encode(notes, forKey: "notes")
    }
    
}

对比之下,使用ARWorldMap的代码可正常运行:

import RoomPlan

class RoomPlanScan: NSObject, NSCoding {
    
    var worldMap: ARWorldMap
    var title: String
    var notes: String
    
    init(worldMap: ARWorldMap, title: String, notes: String) {
        self.worldMap = worldMap
        self.title = title
        self.notes = notes
    }
    
    required convenience init?(coder: NSCoder) {
        guard let worldMap = coder.decodeObject(forKey: "worldMap") as? ARWorldMap,
              let title = coder.decodeObject(forKey: "title") as? String,
              let notes = coder.decodeObject(forKey: "notes") as? String
        else { return nil }
        
        self.init(
            worldMap: worldMap,
            title: title,
            notes: notes
        )
    }
    
    func encode(with coder: NSCoder) {
        coder.encode(worldMap, forKey: "worldMap")
        coder.encode(title, forKey: "title")
        coder.encode(notes, forKey: "notes")
    }
    
}

解决方案

CapturedRoom并未实现NSCoding协议,而是遵循Swift原生的Codable协议。因此需要先将CapturedRoom序列化为Data,再通过NSCoder保存该数据;解码时反向操作,先取出Data再反序列化为CapturedRoom。

修改后的代码如下:

import RoomPlan

class RoomPlanScan: NSObject, NSCoding {
    
    var capturedRoom: CapturedRoom
    var title: String
    var notes: String
    
    init(capturedRoom: CapturedRoom, title: String, notes: String) {
        self.capturedRoom = capturedRoom
        self.title = title
        self.notes = notes
    }
    
    required convenience init?(coder: NSCoder) {
        // 先解码出CapturedRoom对应的Data
        guard let roomData = coder.decodeObject(forKey: "capturedRoomData") as? Data,
              let title = coder.decodeObject(forKey: "title") as? String,
              let notes = coder.decodeObject(forKey: "notes") as? String else {
            return nil
        }
        
        // 将Data反序列化为CapturedRoom
        guard let capturedRoom = try? JSONDecoder().decode(CapturedRoom.self, from: roomData) else {
            return nil
        }
        
        self.init(
            capturedRoom: capturedRoom,
            title: title,
            notes: notes
        )
    }
    
    func encode(with coder: NSCoder) {
        // 将CapturedRoom序列化为Data
        if let roomData = try? JSONEncoder().encode(capturedRoom) {
            coder.encode(roomData, forKey: "capturedRoomData")
        }
        coder.encode(title, forKey: "title")
        coder.encode(notes, forKey: "notes")
    }
    
}

原理说明

  • ARWorldMap是Objective-C兼容类型,实现了NSCoding协议,因此可直接通过NSCoder编码解码;
  • CapturedRoom是纯Swift类型,仅遵循Codable协议,没有实现encodeWithCoder:方法,直接调用coder.encode(capturedRoom)会触发未识别选择器的错误;
  • 通过JSONEncoder/JSONDecoder将CapturedRoom转为Data后,即可用NSCoder保存该二进制数据,同时保留原有的NSCoding结构。

内容的提问来源于stack exchange,提问作者Dennis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 20:06:22