Xcode-project 不使用 NSKeyedArchiver 存档,但 Playground 可以

Posted

技术标签:

【中文标题】Xcode-project 不使用 NSKeyedArchiver 存档,但 Playground 可以【英文标题】:Xcode-project doesn't archive using NSKeyedArchiver, but Playground does 【发布时间】:2017-03-02 19:23:33 【问题描述】:

我在使用 NSCoding 和 NSObject 归档时遇到了一些问题。这在 Playground 中运行良好。但似乎在 Xcode 中不起作用。有人可以帮我解决这个问题吗?

每次我打电话:

NSKeyedArchiver.archiveRootObject(person, toFile: "person")

它在 Playground 中有效并返回 true,但在项目中返回 false。我不使用模拟器。

我一直在寻找相同类型的问题,但是我似乎找不到与此相关的任何内容。

class Person: NSObject, NSCoding 

private var _name: String = "name"
private var _birthdate: Date = Date()
private var _income: Int = -1
private var _wealth: Int = -1

var name: String 
    get  return _name 
    set (newName)  _name = newName 

var birthdate: Date 
    get  return _birthdate 
    set (newBirthdate)  _birthdate = newBirthdate 

var income: Int 
    get  return _income 
    set (newIncome)  _income = newIncome 

var wealth: Int 
    get  return _wealth 
    set (newWealth)  _wealth = newWealth 


override init()

required convenience init(coder unarchiver: NSCoder) 

    self.init()

    if let name = unarchiver.decodeObject(forKey: "name") as? String 
        self.name = name
    
    if let birthdate = unarchiver.decodeObject(forKey: "birthdate") as? Date 
        self.birthdate = birthdate
    
    let income = unarchiver.decodeInteger(forKey: "income")
    self.income = income

    let wealth = unarchiver.decodeInteger(forKey: "wealth")
    self.wealth = wealth



func encode(with archiver: NSCoder) 

    archiver.encode(name, forKey: "name")
    archiver.encode(birthdate, forKey: "birthdate")
    archiver.encode(income, forKey: "income")
    archiver.encode(wealth, forKey: "wealth")
 

然后我创建一个人并将其归档。

let person = Person()
NSKeyedArchiver.archiveRootObject(person, toFile: "person")

【问题讨论】:

文件路径似乎有问题。据我所知,Playgrounds 实际上使用主目录,但项目会使用沙箱。如果你使用 FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("person") 之类的东西会发生什么? 我不确定 FileManager 是做什么的,但我已经这样使用它了:let person = Person() let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("person") let personWasUploaded: Bool = NSKeyedArchiver.archiveRootObject(person, toFile: "\(path)") print(path) print("person uploaded: \(personWasUploaded)") 它会创建一个像这样的文件:file:///var/mobile/Containers/Data/Application/4843FF38-BEFD-47F0-A1E2-DE4ADDAAD97F/Documents/person。但是,在 Application 和 Documentts 之间,数字/字母每次都会改变 这件事你能帮我吗? 【参考方案1】:

你需要在你的 Person 类中对你的 init 做一个小的编辑。删除convenience关键字并将self.init()替换为super.init()

class Person: NSObject, NSCoding 

    private var _name: String = "name"
    private var _birthdate: Date = Date()
    private var _income: Int = -1
    private var _wealth: Int = -1

    var name: String 
        get  return _name 
        set (newName)  _name = newName 
    
    var birthdate: Date 
        get  return _birthdate 
        set (newBirthdate)  _birthdate = newBirthdate 
    
    var income: Int 
        get  return _income 
        set (newIncome)  _income = newIncome 
    
    var wealth: Int 
        get  return _wealth 
        set (newWealth)  _wealth = newWealth 
    

    override init() 

    required init(coder unarchiver: NSCoder) 

        super.init()

        if let name = unarchiver.decodeObject(forKey: "name") as? String 
            self.name = name
        
        if let birthdate = unarchiver.decodeObject(forKey: "birthdate") as? Date 
            self.birthdate = birthdate
        
        let income = unarchiver.decodeInteger(forKey: "income")
        self.income = income

        let wealth = unarchiver.decodeInteger(forKey: "wealth")
        self.wealth = wealth

    

    func encode(with archiver: NSCoder) 

        archiver.encode(name, forKey: "name")
        archiver.encode(birthdate, forKey: "birthdate")
        archiver.encode(income, forKey: "income")
        archiver.encode(wealth, forKey: "wealth")
     

一旦你这样做了,你可以在任何你想要的地方调用存档器(我在 viewDidLoad 中这样做只是为了测试并且它有效)给它一个这样的路径:

let person = Person()
let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("person").path
let personWasUploaded: Bool = NSKeyedArchiver.archiveRootObject(person, toFile:path)
print(path)
print("person uploaded: \(personWasUploaded)")

【讨论】:

感谢您的回答!我找到了一种没有 FileManager 的方法,只是不使用 FileManager 并且像您建议的那样更改 init() 。我想主要的问题是我如何初始化。

以上是关于Xcode-project 不使用 NSKeyedArchiver 存档,但 Playground 可以的主要内容,如果未能解决你的问题,请参考以下文章

XCode-Project文件.pbxproj - 如何在Version Control中处理它?

将UIColor保存到NSUserDefaults并从NSUserDefaults加载

ios开发使用pod命令

如何将 NSUserDefaults 转换为 CoreData

如何使用 NSUserDefaults 在 iOS 中保存非属性值?

iOS Simulator 自定义 City Run 在 Xcode 之外