Reputation: 10371
I can't see any way to copy an NSView and create an identical NSView object. I see google hits about "use an NSData" but I don't understand that.
Upvotes: 14
Views: 4722
Reputation: 309
Since around iOS 12 / macOS 14, the accepted answer by @Dave DeLong
doesn't work anymore in all cases.
The problem is, that some of the methods which were used in @Dave DeLong
s solution don't work anymore for objects that only adhere to the NSCoding
protocol but not the NSSecureCoding
protocol.
Solution
Luckily, there's still a solution that works for copying any Object that adheres to NSCoding
(and not only ones that adhere to NSSecureCoding
) even on the newest operating systems!
There are a few changes in this solution compared to the old one. Most importantly, you'll have to create an instance of NSKeyedUnarchiver
instead of using the more convenient class methods. The convenient class methods only support NSSecureCoding
but not NSCoding
in the newer operating systems.
My implementation looks like this:
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
}
}
Notes
@eskimo
s great answer on this Apple Dev Forum Post: https://developer.apple.com/forums/thread/107533
insecureCopy()
because it works on non-secure coding objects. But, as far as I understand, this method is not in fact insecure. Working with non-secure NSCoding objects is only potentially insecure if you load an insecure archive from an untrusted source (Where a hacker might have modified it). If you just use the archives for deep-copying like in this case, it's perfectly safe.Upvotes: 5
Reputation: 243146
To straight up "copy" an NSView, the view has to implement the NSCopying
protocol. Unfortunately, NSView does not.
Fortunately, it does implement the NSCoding
protocol, which means we can still duplicate a view like:
NSData * archivedView = [NSKeyedArchiver archivedDataWithRootObject:myView];
NSView * myViewCopy = [NSKeyedUnarchiver unarchiveObjectWithData:archivedView];
And voilá! You now have a duplicate of myView
.
Edit: (Swift version)
let archivedView = NSKeyedArchiver.archivedData(withRootObject: myView)
let myViewCopy = NSKeyedUnarchiver.unarchiveObject(with: archivedView)
(archivedView
is of type Data
, not NSData
)
Upvotes: 26