在 Swift 中将自定义对象数组转换为 AnyObject

Convert array of custom object to AnyObject in Swift

在我的应用程序中,我正在做这样的事情:

struct Record {
    var exampleData : String
}

class ExampleClass : UIViewController {
    let records = [Record]()

    override func viewDidLoad() {
        super.viewDidLoad()

        let data = NSKeyedArchiver.archivedDataWithRootObject(self.records) as! NSData
    }

    ...

}

但是在 viewDidLoad() 的最后一行我得到了这个错误:

Argument type '[Record]' does not conform to expected type 'AnyObject'

我该如何解决这个问题?谢谢

AnyObject 表示任何引用类型对象,主要是 class。 struct 是值类型,不能传递给需要 AnyObject 的函数。 Any 可用于接受值类型和引用类型。要修复上面的代码,请将 struct Record 更改为 class Record。但我有一种感觉,您可能出于其他原因想要使用结构。您可以围绕 Record 创建一个 class 包装器,您可以将其相互转换以用于需要 AnyObject.

的函数

如果要保留struct,可以使用withUnsafePointer()对数据进行编码。这是一个例子,我改编自 this Gist:

import UIKit

enum EncodingStructError: ErrorType {
    case InvalidSize
}

func encode<T>(var value: T) -> NSData {
    return withUnsafePointer(&value) { p in
        NSData(bytes: p, length: sizeofValue(value))
    }
}

func decode<T>(data: NSData) throws -> T {
    guard data.length == sizeof(T) else {
        throw EncodingStructError.InvalidSize
    }

    let pointer = UnsafeMutablePointer<T>.alloc(1)
    data.getBytes(pointer, length: data.length)

    return pointer.move()
}

enum Result<T> {
    case Success(T)
    case Failure
}

我添加了一些错误处理并将该方法标记为 throws。这是您可以在 docatch 块中使用它的一种方式:

var res: Result<String> = .Success("yeah")

var data = encode(res)

do {
    var decoded: Result<String> = try decode(data)

    switch decoded {
    case .Failure:
        "failure"
    case .Success(let v):
        "success: \(v)" // => "success: yeah"
    }
} catch {
    print(error)
}

如果 NSData 长度与类型大小不匹配,我添加的错误处理将不会解码。如果您将数据写入磁盘,用户使用相同类型的不同大小版本更新到应用程序的较新版本,然后数据被读入,则通常会发生这种情况。

另请注意,sizeof()sizeofValue() 可能 return 不同设备上的不同值,因此这不是在设备之间发送数据的好解决方案 (NSJSONSerialization可能会更好)。

我做过类似的事情:

    static func encode<T>(value: T) -> NSData {
        var val = value
        return withUnsafePointer(to: &val) { pointer in
            NSData(bytes: pointer, length: MemoryLayout.size(ofValue: val))
        }
    }

    static func decode<T>(data: NSData) -> T {
        guard data.length == MemoryLayout<T>.size.self else {
            fatalError("[Credential] fatal unarchiving error.")
        }

        let pointer = UnsafeMutablePointer<T>.allocate(capacity: 1)
        data.getBytes(pointer, length: data.length)

        return pointer.move()
    }