Skip to content

Commit 14b428e

Browse files
alblueparkera
authored andcommitted
Remove non-keyed encoding for data objects (#626)
Instead of having non-keyed encoding supported by some but not all foundation types, remove the non-keyed encoding everywhere and make passing a non-keyed encoder a preconditionFailure.
1 parent 2105e9c commit 14b428e

15 files changed

+176
-314
lines changed

Foundation/NSArray.swift

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,10 @@ open class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCo
4343
}
4444

4545
public required convenience init?(coder aDecoder: NSCoder) {
46-
if !aDecoder.allowsKeyedCoding {
47-
var cnt: UInt32 = 0
48-
// We're stuck with (int) here (rather than unsigned int)
49-
// because that's the way the code was originally written, unless
50-
// we go to a new version of the class, which has its own problems.
51-
withUnsafeMutablePointer(to: &cnt) { (ptr: UnsafeMutablePointer<UInt32>) -> Void in
52-
aDecoder.decodeValue(ofObjCType: "i", at: UnsafeMutableRawPointer(ptr))
53-
}
54-
let objects = UnsafeMutablePointer<AnyObject>.allocate(capacity: Int(cnt))
55-
for idx in 0..<cnt {
56-
// If conversion to NSObject fails then we really can't hold it anyway
57-
objects.advanced(by: Int(idx)).initialize(to: aDecoder.decodeObject() as! NSObject)
58-
}
59-
self.init(objects: UnsafePointer<AnyObject>(objects), count: Int(cnt))
60-
objects.deinitialize(count: Int(cnt))
61-
objects.deallocate(capacity: Int(cnt))
62-
} else if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.objects") {
46+
guard aDecoder.allowsKeyedCoding else {
47+
preconditionFailure("Unkeyed coding is unsupported.")
48+
}
49+
if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.objects") {
6350
let objects = aDecoder._decodeArrayOfObjectsForKey("NS.objects")
6451
self.init(array: objects as! [NSObject])
6552
} else {
@@ -74,6 +61,9 @@ open class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCo
7461
}
7562

7663
open func encode(with aCoder: NSCoder) {
64+
guard aCoder.allowsKeyedCoding else {
65+
preconditionFailure("Unkeyed coding is unsupported.")
66+
}
7767
if let keyedArchiver = aCoder as? NSKeyedArchiver {
7868
keyedArchiver._encodeArrayOfObjects(self, forKey:"NS.objects")
7969
} else {

Foundation/NSData.swift

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -317,13 +317,10 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
317317
}
318318

319319
public required convenience init?(coder aDecoder: NSCoder) {
320-
if !aDecoder.allowsKeyedCoding {
321-
if let data = aDecoder.decodeData() {
322-
self.init(data: data)
323-
} else {
324-
return nil
325-
}
326-
} else if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.data") {
320+
guard aDecoder.allowsKeyedCoding else {
321+
preconditionFailure("Unkeyed coding is unsupported.")
322+
}
323+
if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.data") {
327324
guard let data = aDecoder._decodePropertyListForKey("NS.data") as? NSData else {
328325
return nil
329326
}

Foundation/NSDate.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,9 @@ open class NSDateInterval : NSObject, NSCopying, NSSecureCoding {
274274

275275

276276
public required convenience init?(coder: NSCoder) {
277-
precondition(coder.allowsKeyedCoding)
277+
guard coder.allowsKeyedCoding else {
278+
preconditionFailure("Unkeyed coding is unsupported.")
279+
}
278280
guard let start = coder.decodeObject(of: NSDate.self, forKey: "NS.startDate") else {
279281
coder.failWithError(NSError(domain: NSCocoaErrorDomain, code: CocoaError.coderValueNotFound.rawValue, userInfo: nil))
280282
return nil
@@ -304,7 +306,9 @@ open class NSDateInterval : NSObject, NSCopying, NSSecureCoding {
304306
}
305307

306308
open func encode(with aCoder: NSCoder) {
307-
precondition(aCoder.allowsKeyedCoding)
309+
guard aCoder.allowsKeyedCoding else {
310+
preconditionFailure("Unkeyed coding is unsupported.")
311+
}
308312
aCoder.encode(startDate._nsObject, forKey: "NS.startDate")
309313
aCoder.encode(endDate._nsObject, forKey: "NS.endDate")
310314
}

Foundation/NSDictionary.swift

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -54,27 +54,10 @@ open class NSDictionary : NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
5454
}
5555

5656
public required convenience init?(coder aDecoder: NSCoder) {
57-
if !aDecoder.allowsKeyedCoding {
58-
var cnt: UInt32 = 0
59-
// We're stuck with (int) here (rather than unsigned int)
60-
// because that's the way the code was originally written, unless
61-
// we go to a new version of the class, which has its own problems.
62-
withUnsafeMutablePointer(to: &cnt) { (ptr: UnsafeMutablePointer<UInt32>) -> Void in
63-
aDecoder.decodeValue(ofObjCType: "i", at: UnsafeMutableRawPointer(ptr))
64-
}
65-
let keys = UnsafeMutablePointer<NSObject>.allocate(capacity: Int(cnt))
66-
let objects = UnsafeMutablePointer<AnyObject>.allocate(capacity: Int(cnt))
67-
for idx in 0..<cnt {
68-
keys.advanced(by: Int(idx)).initialize(to: aDecoder.decodeObject()! as! NSObject)
69-
objects.advanced(by: Int(idx)).initialize(to: aDecoder.decodeObject()! as! NSObject)
70-
}
71-
self.init(objects: UnsafePointer<AnyObject>(objects), forKeys: UnsafePointer<NSObject>(keys), count: Int(cnt))
72-
keys.deinitialize(count: Int(cnt))
73-
keys.deallocate(capacity: Int(cnt))
74-
objects.deinitialize(count: Int(cnt))
75-
objects.deallocate(capacity: Int(cnt))
76-
77-
} else if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.objects") {
57+
guard aDecoder.allowsKeyedCoding else {
58+
preconditionFailure("Unkeyed coding is unsupported.")
59+
}
60+
if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.objects") {
7861
let keys = aDecoder._decodeArrayOfObjectsForKey("NS.keys").map() { return $0 as! NSObject }
7962
let objects = aDecoder._decodeArrayOfObjectsForKey("NS.objects")
8063
self.init(objects: objects as! [NSObject], forKeys: keys)

Foundation/NSError.swift

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -62,34 +62,20 @@ open class NSError : NSObject, NSCopying, NSSecureCoding, NSCoding {
6262
}
6363

6464
public required init?(coder aDecoder: NSCoder) {
65-
if aDecoder.allowsKeyedCoding {
66-
_code = aDecoder.decodeInteger(forKey: "NSCode")
67-
_domain = aDecoder.decodeObject(of: NSString.self, forKey: "NSDomain")!._swiftObject
68-
if let info = aDecoder.decodeObject(of: [NSSet.self, NSDictionary.self, NSArray.self, NSString.self, NSNumber.self, NSData.self, NSURL.self], forKey: "NSUserInfo") as? NSDictionary {
69-
var filteredUserInfo = [String : Any]()
70-
// user info must be filtered so that the keys are all strings
71-
info.enumerateKeysAndObjects(options: []) {
72-
if let key = $0.0 as? NSString {
73-
filteredUserInfo[key._swiftObject] = $0.1
74-
}
75-
}
76-
_userInfo = filteredUserInfo
77-
}
78-
} else {
79-
var codeValue: Int32 = 0
80-
aDecoder.decodeValue(ofObjCType: "i", at: &codeValue)
81-
_code = Int(codeValue)
82-
_domain = (aDecoder.decodeObject() as? NSString)!._swiftObject
83-
if let info = aDecoder.decodeObject() as? NSDictionary {
84-
var filteredUserInfo = [String : Any]()
85-
// user info must be filtered so that the keys are all strings
86-
info.enumerateKeysAndObjects(options: []) {
87-
if let key = $0.0 as? NSString {
88-
filteredUserInfo[key._swiftObject] = $0.1
89-
}
65+
guard aDecoder.allowsKeyedCoding else {
66+
preconditionFailure("Unkeyed coding is unsupported.")
67+
}
68+
_code = aDecoder.decodeInteger(forKey: "NSCode")
69+
_domain = aDecoder.decodeObject(of: NSString.self, forKey: "NSDomain")!._swiftObject
70+
if let info = aDecoder.decodeObject(of: [NSSet.self, NSDictionary.self, NSArray.self, NSString.self, NSNumber.self, NSData.self, NSURL.self], forKey: "NSUserInfo") as? NSDictionary {
71+
var filteredUserInfo = [String : Any]()
72+
// user info must be filtered so that the keys are all strings
73+
info.enumerateKeysAndObjects(options: []) {
74+
if let key = $0.0 as? NSString {
75+
filteredUserInfo[key._swiftObject] = $0.1
9076
}
91-
_userInfo = filteredUserInfo
9277
}
78+
_userInfo = filteredUserInfo
9379
}
9480
}
9581

@@ -98,16 +84,12 @@ open class NSError : NSObject, NSCopying, NSSecureCoding, NSCoding {
9884
}
9985

10086
open func encode(with aCoder: NSCoder) {
101-
if aCoder.allowsKeyedCoding {
102-
aCoder.encode(_domain._bridgeToObjectiveC(), forKey: "NSDomain")
103-
aCoder.encode(Int32(_code), forKey: "NSCode")
104-
aCoder.encode(_userInfo?._bridgeToObjectiveC(), forKey: "NSUserInfo")
105-
} else {
106-
var codeValue: Int32 = Int32(self._code)
107-
aCoder.encodeValue(ofObjCType: "i", at: &codeValue)
108-
aCoder.encode(self._domain._bridgeToObjectiveC())
109-
aCoder.encode(self._userInfo?._bridgeToObjectiveC())
87+
guard aCoder.allowsKeyedCoding else {
88+
preconditionFailure("Unkeyed coding is unsupported.")
11089
}
90+
aCoder.encode(_domain._bridgeToObjectiveC(), forKey: "NSDomain")
91+
aCoder.encode(Int32(_code), forKey: "NSCode")
92+
aCoder.encode(_userInfo?._bridgeToObjectiveC(), forKey: "NSUserInfo")
11193
}
11294

11395
open override func copy() -> Any {

Foundation/NSGeometry.swift

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,17 @@ extension CGPoint: NSSpecialValueCoding {
3838
}
3939

4040
init?(coder aDecoder: NSCoder) {
41-
if aDecoder.allowsKeyedCoding {
42-
self = aDecoder.decodePointForKey("NS.pointval")
43-
} else {
44-
self = aDecoder.decodePoint()
41+
guard aDecoder.allowsKeyedCoding else {
42+
preconditionFailure("Unkeyed coding is unsupported.")
4543
}
44+
self = aDecoder.decodePointForKey("NS.pointval")
4645
}
4746

4847
func encodeWithCoder(_ aCoder: NSCoder) {
49-
if aCoder.allowsKeyedCoding {
50-
aCoder.encodePoint(self, forKey: "NS.pointval")
51-
} else {
52-
aCoder.encodePoint(self)
48+
guard aCoder.allowsKeyedCoding else {
49+
preconditionFailure("Unkeyed coding is unsupported.")
5350
}
51+
aCoder.encodePoint(self, forKey: "NS.pointval")
5452
}
5553

5654
static func objCType() -> String {
@@ -103,19 +101,17 @@ extension CGSize: NSSpecialValueCoding {
103101
}
104102

105103
init?(coder aDecoder: NSCoder) {
106-
if aDecoder.allowsKeyedCoding {
107-
self = aDecoder.decodeSizeForKey("NS.sizeval")
108-
} else {
109-
self = aDecoder.decodeSize()
104+
guard aDecoder.allowsKeyedCoding else {
105+
preconditionFailure("Unkeyed coding is unsupported.")
110106
}
107+
self = aDecoder.decodeSizeForKey("NS.sizeval")
111108
}
112109

113110
func encodeWithCoder(_ aCoder: NSCoder) {
114-
if aCoder.allowsKeyedCoding {
115-
aCoder.encodeSize(self, forKey: "NS.sizeval")
116-
} else {
117-
aCoder.encodeSize(self)
111+
guard aCoder.allowsKeyedCoding else {
112+
preconditionFailure("Unkeyed coding is unsupported.")
118113
}
114+
aCoder.encodeSize(self, forKey: "NS.sizeval")
119115
}
120116

121117
static func objCType() -> String {
@@ -187,19 +183,17 @@ extension CGRect: NSSpecialValueCoding {
187183
}
188184

189185
init?(coder aDecoder: NSCoder) {
190-
if aDecoder.allowsKeyedCoding {
191-
self = aDecoder.decodeRectForKey("NS.rectval")
192-
} else {
193-
self = aDecoder.decodeRect()
186+
guard aDecoder.allowsKeyedCoding else {
187+
preconditionFailure("Unkeyed coding is unsupported.")
194188
}
189+
self = aDecoder.decodeRectForKey("NS.rectval")
195190
}
196191

197192
func encodeWithCoder(_ aCoder: NSCoder) {
198-
if aCoder.allowsKeyedCoding {
199-
aCoder.encodeRect(self, forKey: "NS.rectval")
200-
} else {
201-
aCoder.encodeRect(self)
193+
guard aCoder.allowsKeyedCoding else {
194+
preconditionFailure("Unkeyed coding is unsupported.")
202195
}
196+
aCoder.encodeRect(self, forKey: "NS.rectval")
203197
}
204198

205199
static func objCType() -> String {

Foundation/NSNotification.swift

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,34 +45,24 @@ open class NSNotification: NSObject, NSCopying, NSCoding {
4545
}
4646

4747
public convenience required init?(coder aDecoder: NSCoder) {
48-
if aDecoder.allowsKeyedCoding {
49-
guard let name = aDecoder.decodeObject(of: NSString.self, forKey:"NS.name") else {
50-
return nil
51-
}
52-
let object = aDecoder.decodeObject(forKey: "NS.object")
53-
// let userInfo = aDecoder.decodeObject(of: NSDictionary.self, forKey: "NS.userinfo")
54-
self.init(name: Name(rawValue: String._unconditionallyBridgeFromObjectiveC(name)), object: object as! NSObject, userInfo: nil)
55-
56-
} else {
57-
guard let name = aDecoder.decodeObject() as? NSString else {
58-
return nil
59-
}
60-
let object = aDecoder.decodeObject()
61-
// let userInfo = aDecoder.decodeObject() as? NSDictionary
62-
self.init(name: Name(rawValue: String._unconditionallyBridgeFromObjectiveC(name)), object: object, userInfo: nil)
48+
guard aDecoder.allowsKeyedCoding else {
49+
preconditionFailure("Unkeyed coding is unsupported.")
50+
}
51+
guard let name = aDecoder.decodeObject(of: NSString.self, forKey:"NS.name") else {
52+
return nil
6353
}
54+
let object = aDecoder.decodeObject(forKey: "NS.object")
55+
// let userInfo = aDecoder.decodeObject(of: NSDictionary.self, forKey: "NS.userinfo")
56+
self.init(name: Name(rawValue: String._unconditionallyBridgeFromObjectiveC(name)), object: object as! NSObject, userInfo: nil)
6457
}
6558

6659
open func encode(with aCoder: NSCoder) {
67-
if aCoder.allowsKeyedCoding {
68-
aCoder.encode(self.name.rawValue._bridgeToObjectiveC(), forKey:"NS.name")
69-
aCoder.encode(self.object, forKey:"NS.object")
70-
aCoder.encode(self.userInfo?._bridgeToObjectiveC(), forKey:"NS.userinfo")
71-
} else {
72-
aCoder.encode(self.name.rawValue._bridgeToObjectiveC())
73-
aCoder.encode(self.object)
74-
aCoder.encode(self.userInfo?._bridgeToObjectiveC())
60+
guard aCoder.allowsKeyedCoding else {
61+
preconditionFailure("Unkeyed coding is unsupported.")
7562
}
63+
aCoder.encode(self.name.rawValue._bridgeToObjectiveC(), forKey:"NS.name")
64+
aCoder.encode(self.object, forKey:"NS.object")
65+
aCoder.encode(self.userInfo?._bridgeToObjectiveC(), forKey:"NS.userinfo")
7666
}
7767

7868
open override func copy() -> Any {

Foundation/NSNumber.swift

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -336,21 +336,10 @@ open class NSNumber : NSValue {
336336
}
337337

338338
public required convenience init?(coder aDecoder: NSCoder) {
339-
if !aDecoder.allowsKeyedCoding {
340-
var objCType: UnsafeMutablePointer<Int8>? = nil
341-
withUnsafeMutablePointer(to: &objCType, { (ptr: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>) -> Void in
342-
aDecoder.decodeValue(ofObjCType: String(_NSSimpleObjCType.CharPtr), at: UnsafeMutableRawPointer(ptr))
343-
})
344-
if objCType == nil {
345-
return nil
346-
}
347-
var size: Int = 0
348-
let _ = NSGetSizeAndAlignment(objCType!, &size, nil)
349-
let buffer = malloc(size)!
350-
aDecoder.decodeValue(ofObjCType: objCType!, at: buffer)
351-
self.init(bytes: buffer, objCType: objCType!)
352-
free(buffer)
353-
} else if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.number") {
339+
guard aDecoder.allowsKeyedCoding else {
340+
preconditionFailure("Unkeyed coding is unsupported.")
341+
}
342+
if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.number") {
354343
let number = aDecoder._decodePropertyListForKey("NS.number")
355344
if let val = number as? Double {
356345
self.init(value:val)

Foundation/NSOrderedSet.swift

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,30 +41,28 @@ open class NSOrderedSet : NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
4141
}
4242

4343
open func encode(with aCoder: NSCoder) {
44-
if aCoder.allowsKeyedCoding {
45-
for idx in 0..<self.count {
46-
aCoder.encode(_SwiftValue.store(self.object(at: idx)), forKey:"NS.object.\(idx)")
47-
}
48-
} else {
49-
NSUnimplemented()
44+
guard aCoder.allowsKeyedCoding else {
45+
preconditionFailure("Unkeyed coding is unsupported.")
46+
}
47+
for idx in 0..<self.count {
48+
aCoder.encode(_SwiftValue.store(self.object(at: idx)), forKey:"NS.object.\(idx)")
5049
}
5150
}
5251

5352
public required convenience init?(coder aDecoder: NSCoder) {
54-
if aDecoder.allowsKeyedCoding {
55-
var idx = 0
56-
var objects : [AnyObject] = []
57-
while aDecoder.containsValue(forKey: ("NS.object.\(idx)")) {
58-
guard let object = aDecoder.decodeObject(forKey: "NS.object.\(idx)") else {
59-
return nil
60-
}
61-
objects.append(object as! NSObject)
62-
idx += 1
53+
guard aDecoder.allowsKeyedCoding else {
54+
preconditionFailure("Unkeyed coding is unsupported.")
55+
}
56+
var idx = 0
57+
var objects : [AnyObject] = []
58+
while aDecoder.containsValue(forKey: ("NS.object.\(idx)")) {
59+
guard let object = aDecoder.decodeObject(forKey: "NS.object.\(idx)") else {
60+
return nil
6361
}
64-
self.init(array: objects)
65-
} else {
66-
NSUnimplemented()
62+
objects.append(object as! NSObject)
63+
idx += 1
6764
}
65+
self.init(array: objects)
6866
}
6967

7068
open var count: Int {

0 commit comments

Comments
 (0)