在cocoa/objective-c中复制NSView

Nek*_*ios 13 cocoa objective-c

我看不到任何方法来复制NSView并创建一个相同的NSView对象.我看到谷歌点击"使用NSData",但我不明白.

Dav*_*ong 25

要直接"复制"NSView,视图必须实现NSCopying协议.不幸的是,NSView没有.

幸运的是,它确实实现了NSCoding协议,这意味着我们仍然可以复制一个视图,如:

NSData * archivedView = [NSKeyedArchiver archivedDataWithRootObject:myView];
NSView * myViewCopy = [NSKeyedUnarchiver unarchiveObjectWithData:archivedView];
Run Code Online (Sandbox Code Playgroud)

瞧!你现在有一个副本myView.


编辑:( Swift版)

let archivedView = NSKeyedArchiver.archivedData(withRootObject: myView)
let myViewCopy = NSKeyedUnarchiver.unarchiveObject(with: archivedView)
Run Code Online (Sandbox Code Playgroud)

(archivedView是类型Data,不是NSData)

  • 请注意,如果您是子类,则需要实现归档支持.文档知道所有. (3认同)

Noa*_*ing 5

自 iOS 12 / macOS 14 左右以来,接受的答案@Dave DeLong在所有情况下都不再有效。

问题是,@Dave DeLong解决方案中使用的某些方法对于遵守协议但不遵守协议的对象不再适用NSCodingNSSecureCoding


解决方案

幸运的是,仍然有一个解决方案可以复制任何遵守NSCoding(而不仅仅是遵守NSSecureCoding)的对象,即使在最新的操作系统上也是如此!

与旧解决方案相比,此解决方案有一些变化。最重要的是,您必须创建一个实例,NSKeyedUnarchiver而不是使用更方便的类方法。方便的类方法仅支持NSSecureCodingNSCoding在较新的操作系统中不支持。

我的实现如下所示:

public func insecureCopy<T: NSCoding>(of original: T) throws -> T {
    
    /// See https://developer.apple.com/forums/thread/107533
    
    if #available(macOS 10.13, *) {
    
        let data = try NSKeyedArchiver.archivedData(withRootObject: original, requiringSecureCoding: false)
        
        let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
        unarchiver.requiresSecureCoding = false
        
        let copy = unarchiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! T
        
        return copy
        
    } else { /// Fallback (untested)
        
        let data = NSKeyedArchiver.archivedData(withRootObject: original)
        
        let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
        unarchiver.requiresSecureCoding = false
        
        let copy = unarchiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! T
        
        return copy
        
    }
}
Run Code Online (Sandbox Code Playgroud)

笔记

  • 该解决方案的来源来自@eskimoApple Dev Forum Post 上的精彩回答: https: //developer.apple.com/forums/thread/107533
    以及他们链接到的 WWDC 会议视频。
  • 调用该方法是insecureCopy()因为它适用于非安全编码对象。但是,据我了解,这种方法实际上并非不安全。据我所知,只有当您将不安全的档案保存到文件或从文件加载不安全的档案时,使用不安全的 NSCoding 对象才是不安全的。如果您只是像本例一样使用存档进行复制,则不会。
  • macOS 10.13 及更早版本的后备代码未经测试。