Skip to content

Commit 43572c3

Browse files
committed
[SR-377] implement NSKeyedArchiver/NSKeyedUnarchiver
This commit implements the NSKeyedArchiver and NSKeyedUnarchiver serialization APIs. The encoders and decoders for specific classes are in separate commits.
1 parent 1bfba41 commit 43572c3

8 files changed

+1980
-191
lines changed

Docs/Archiving.md

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Archiving Notes
2+
3+
There is a preliminary implementation of NSKeyedArchiver and NSKeyedUnarchiver which should be compatible with the OS X version.
4+
5+
* NSKeyedUnarchiver reads the entire plist into memory before constructing the object graph, it should construct it incrementally as does Foundation on OS X
6+
7+
* Paths that raise errors vs. calling _fatalError() need to be reviewed carefully
8+
9+
* The signature of the decoding APIs that take a class whitelist has changed from NSSet to [AnyClass] as AnyClass does not support Hashable. The API change has been marked Experimental.
10+
11+
* classForKeyed[Un]Archiver has moved into NSObject so it can be overridden, move this back into an extension eventually
12+
13+
# Classes
14+
15+
## Implemented
16+
17+
* NSArray
18+
* NSCalendar
19+
* NSCFArray (encodes as NSArray)
20+
* NSCFDictionary (encodes as NSDictionary)
21+
* NSCFSet (encodes as NSSet)
22+
* NSCFString (encodes as NSString)
23+
* NSConcreteValue
24+
* NSData
25+
* NSDate
26+
* NSDictionary
27+
* NSError
28+
* NSLocale
29+
* NSNotification
30+
* NSNull (no-op)
31+
* NSOrderedSet
32+
* NSPersonNameComponents
33+
* NSPort (not supported for keyed archiving)
34+
* NSSet
35+
* NSSpecialValue (for limited number of types)
36+
* NSString
37+
* NSTimeZone
38+
* NSURL
39+
* NSUUID
40+
* NSValue (via class cluster hack)
41+
42+
## TODO
43+
44+
### Pending actual class implementation
45+
46+
* NSAttributedString
47+
48+
### Pending coder implementation
49+
50+
* NSAffineTransform
51+
* NSCharacterSet
52+
* NSDecimalNumber
53+
* NSDecimalNumberHandler
54+
* NSExpression
55+
* NSIndexPath
56+
* NSIndexSet
57+
* NSPredicate
58+
* NSSortDescriptor
59+
* NSTextCheckingResult
60+
* NSURLAuthenticationChallenge
61+
* NSURLCache
62+
* NSURLCredential
63+
* NSURLProtectionSpace
64+
* NSURLRequest

Foundation.xcodeproj/project.pbxproj

+16
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@
231231
C93559291C12C49F009FD6A9 /* TestNSAffineTransform.swift in Sources */ = {isa = PBXBuildFile; fileRef = C93559281C12C49F009FD6A9 /* TestNSAffineTransform.swift */; };
232232
CE19A88C1C23AA2300B4CB6A /* NSStringTestData.txt in Resources */ = {isa = PBXBuildFile; fileRef = CE19A88B1C23AA2300B4CB6A /* NSStringTestData.txt */; };
233233
D834F9941C31C4060023812A /* TestNSOrderedSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D834F9931C31C4060023812A /* TestNSOrderedSet.swift */; };
234+
D31302011C30CEA900295652 /* NSConcreteValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D31302001C30CEA900295652 /* NSConcreteValue.swift */; };
235+
D39A14011C2D6E0A00295652 /* NSKeyedUnarchiver.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39A14001C2D6E0A00295652 /* NSKeyedUnarchiver.swift */; };
236+
D3BCEB9E1C2EDED800295652 /* NSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BCEB9D1C2EDED800295652 /* NSLog.swift */; };
237+
D3BCEBA01C2F6DDB00295652 /* NSKeyedCoderOldStyleArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3BCEB9F1C2F6DDB00295652 /* NSKeyedCoderOldStyleArray.swift */; };
234238
DCDBB8331C1768AC00313299 /* TestNSData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCDBB8321C1768AC00313299 /* TestNSData.swift */; };
235239
E19E17DC1C2225930023AF4D /* TestNSXMLDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E17DB1C2225930023AF4D /* TestNSXMLDocument.swift */; };
236240
E1A3726F1C31EBFB0023AF4D /* NSXMLDocumentTestData.xml in Resources */ = {isa = PBXBuildFile; fileRef = E1A3726E1C31EBFB0023AF4D /* NSXMLDocumentTestData.xml */; };
@@ -583,6 +587,10 @@
583587
C93559281C12C49F009FD6A9 /* TestNSAffineTransform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSAffineTransform.swift; sourceTree = "<group>"; };
584588
CE19A88B1C23AA2300B4CB6A /* NSStringTestData.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = NSStringTestData.txt; sourceTree = "<group>"; };
585589
D834F9931C31C4060023812A /* TestNSOrderedSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSOrderedSet.swift; sourceTree = "<group>"; };
590+
D31302001C30CEA900295652 /* NSConcreteValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSConcreteValue.swift; sourceTree = "<group>"; };
591+
D39A14001C2D6E0A00295652 /* NSKeyedUnarchiver.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSKeyedUnarchiver.swift; sourceTree = "<group>"; };
592+
D3BCEB9D1C2EDED800295652 /* NSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSLog.swift; sourceTree = "<group>"; };
593+
D3BCEB9F1C2F6DDB00295652 /* NSKeyedCoderOldStyleArray.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSKeyedCoderOldStyleArray.swift; sourceTree = "<group>"; };
586594
DCDBB8321C1768AC00313299 /* TestNSData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSData.swift; sourceTree = "<group>"; };
587595
E19E17DB1C2225930023AF4D /* TestNSXMLDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestNSXMLDocument.swift; sourceTree = "<group>"; };
588596
E1A3726E1C31EBFB0023AF4D /* NSXMLDocumentTestData.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = NSXMLDocumentTestData.xml; sourceTree = "<group>"; };
@@ -1244,6 +1252,8 @@
12441252
children = (
12451253
EADE0B641BD15DFF00C49C64 /* NSJSONSerialization.swift */,
12461254
EADE0B651BD15DFF00C49C64 /* NSKeyedArchiver.swift */,
1255+
D3BCEB9F1C2F6DDB00295652 /* NSKeyedCoderOldStyleArray.swift */,
1256+
D39A14001C2D6E0A00295652 /* NSKeyedUnarchiver.swift */,
12471257
5BDC3F321BCC5DCB00ED97BB /* NSCoder.swift */,
12481258
5BDC3F421BCC5DCB00ED97BB /* NSPropertyList.swift */,
12491259
);
@@ -1330,6 +1340,7 @@
13301340
EADE0B4D1BD09E0800C49C64 /* NSAffineTransform.swift */,
13311341
5BDC3F3D1BCC5DCB00ED97BB /* NSNumber.swift */,
13321342
5BDC3F4C1BCC5DCB00ED97BB /* NSValue.swift */,
1343+
D31302001C30CEA900295652 /* NSConcreteValue.swift */,
13331344
);
13341345
name = Number;
13351346
sourceTree = "<group>";
@@ -1355,6 +1366,7 @@
13551366
EADE0B6D1BD15DFF00C49C64 /* NSOperation.swift */,
13561367
5BDC3F3C1BCC5DCB00ED97BB /* NSLock.swift */,
13571368
5BDC3F401BCC5DCB00ED97BB /* NSPathUtilities.swift */,
1369+
D3BCEB9D1C2EDED800295652 /* NSLog.swift */,
13581370
);
13591371
name = OS;
13601372
sourceTree = "<group>";
@@ -1686,6 +1698,7 @@
16861698
EADE0BB71BD15E0000C49C64 /* NSStream.swift in Sources */,
16871699
5BF7AEBF1BCD51F9008F214A /* NSURL.swift in Sources */,
16881700
5BF7AEBC1BCD51F9008F214A /* NSThread.swift in Sources */,
1701+
D31302011C30CEA900295652 /* NSConcreteValue.swift in Sources */,
16891702
5BF7AEA81BCD51F9008F214A /* NSData.swift in Sources */,
16901703
EADE0BB51BD15E0000C49C64 /* NSScanner.swift in Sources */,
16911704
EADE0BA01BD15DFF00C49C64 /* NSIndexPath.swift in Sources */,
@@ -1705,17 +1718,20 @@
17051718
5B94E8821C430DE70055C035 /* String.swift in Sources */,
17061719
5BF7AEAB1BCD51F9008F214A /* NSDictionary.swift in Sources */,
17071720
EADE0BAA1BD15E0000C49C64 /* NSNumberFormatter.swift in Sources */,
1721+
D39A14011C2D6E0A00295652 /* NSKeyedUnarchiver.swift in Sources */,
17081722
5BF7AEAF1BCD51F9008F214A /* NSHost.swift in Sources */,
17091723
EADE0B4E1BD09E0800C49C64 /* NSAffineTransform.swift in Sources */,
17101724
EADE0BC71BD15E0000C49C64 /* NSXMLDocument.swift in Sources */,
17111725
5BDC3FCE1BCF17D300ED97BB /* NSCFDictionary.swift in Sources */,
17121726
EADE0BA81BD15E0000C49C64 /* NSNotificationQueue.swift in Sources */,
17131727
EADE0B981BD15DFF00C49C64 /* NSDecimalNumber.swift in Sources */,
17141728
5BF7AEA71BCD51F9008F214A /* NSCoder.swift in Sources */,
1729+
D3BCEBA01C2F6DDB00295652 /* NSKeyedCoderOldStyleArray.swift in Sources */,
17151730
EADE0BA71BD15E0000C49C64 /* NSNotification.swift in Sources */,
17161731
5BF7AEB41BCD51F9008F214A /* NSObject.swift in Sources */,
17171732
EADE0B521BD09F2F00C49C64 /* NSByteCountFormatter.swift in Sources */,
17181733
EADE0BC11BD15E0000C49C64 /* NSURLProtocol.swift in Sources */,
1734+
D3BCEB9E1C2EDED800295652 /* NSLog.swift in Sources */,
17191735
61E0117D1C1B5590000037DD /* NSRunLoop.swift in Sources */,
17201736
EADE0BC81BD15E0000C49C64 /* NSXMLDTD.swift in Sources */,
17211737
EADE0BA61BD15E0000C49C64 /* NSMassFormatter.swift in Sources */,

Foundation/NSCoder.swift

+57-6
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,20 @@ public class NSCoder : NSObject {
5050
public func decodeObjectOfClass<DecodedObjectType : NSCoding where DecodedObjectType : NSObject>(cls: DecodedObjectType.Type, forKey key: String) -> DecodedObjectType? {
5151
NSUnimplemented()
5252
}
53-
53+
54+
/*!
55+
@method decodeObjectOfClasses:forKey:
56+
@abstract Decodes an object for the key, restricted to the specified classes.
57+
@param classes An array of the expected classes.
58+
@param key The code key.
59+
@return The decoded object.
60+
@discussion This function signature differs from Foundation OS X in that
61+
classes is an array of Classes, not a NSSet. This is because AnyClass cannot
62+
be casted to NSObject, nor is it Hashable.
63+
*/
64+
/// - Experiment: This is a draft API currently under consideration for official import into Foundation
5465
@warn_unused_result
55-
public func decodeObjectOfClasses(classes: NSSet?, forKey key: String) -> AnyObject? {
66+
public func decodeObjectOfClasses(classes: [AnyClass], forKey key: String) -> AnyObject? {
5667
NSUnimplemented()
5768
}
5869

@@ -71,8 +82,19 @@ public class NSCoder : NSObject {
7182
NSUnimplemented()
7283
}
7384

85+
/*!
86+
@method decodeTopLevelObjectOfClasses:
87+
@abstract Decodes an top-level object for the key, restricted to the specified classes.
88+
@param classes An array of the expected classes.
89+
@param key The code key.
90+
@return The decoded object.
91+
@discussion This function signature differs from Foundation OS X in that
92+
classes is an array of Classes, not a NSSet. This is because AnyClass cannot
93+
be casted to NSObject, nor is it Hashable.
94+
*/
95+
/// - Experiment: This is a draft API currently under consideration for official import into Foundation
7496
@warn_unused_result
75-
public func decodeTopLevelObjectOfClasses(classes: NSSet?, forKey key: String) throws -> AnyObject? {
97+
public func decodeTopLevelObjectOfClasses(classes: [AnyClass], forKey key: String) throws -> AnyObject? {
7698
NSUnimplemented()
7799
}
78100

@@ -253,13 +275,42 @@ public class NSCoder : NSObject {
253275
NSUnimplemented()
254276
}
255277

256-
public var allowedClasses: Set<NSObject>? {
278+
/*!
279+
@property allowedClasses
280+
@abstract The set of coded classes allowed for secure coding. (read-only)
281+
@discussion This property type differs from Foundation OS X in that
282+
classes is an array of Classes, not a Set. This is because AnyClass is not
283+
hashable.
284+
*/
285+
/// - Experiment: This is a draft API currently under consideration for official import into Foundation
286+
public var allowedClasses: [AnyClass]? {
257287
get {
258288
NSUnimplemented()
259289
}
260290
}
261291

262292
public func failWithError(error: NSError) {
263-
NSUnimplemented()
293+
if let debugDescription = error.userInfo["NSDebugDescription"] {
294+
fatalError("*** NSKeyedUnarchiver.init: \(debugDescription)")
295+
}
296+
}
297+
298+
internal func _decodeArrayOfObjectsForKey(key: String) -> [AnyObject] {
299+
NSRequiresConcreteImplementation()
300+
}
301+
302+
internal func _decodePropertyListForKey(key: String) -> Any {
303+
NSRequiresConcreteImplementation()
264304
}
265-
}
305+
}
306+
307+
// TODO: Could perhaps be an extension of NSCoding instead. The reason it is an extension of NSObject is the lack of default implementations on protocols in Objective-C.
308+
extension NSObject {
309+
public var classForCoder: AnyClass {
310+
return self.dynamicType
311+
}
312+
313+
public func replacementObjectForCoder(aCoder: NSCoder) -> AnyObject? {
314+
return self
315+
}
316+
}

0 commit comments

Comments
 (0)