Skip to content

Commit d27f02f

Browse files
committed
[SR-377] common Foundation class decoders/encoders
See Docs/Archiving.md for further implementation status notes.
1 parent 43572c3 commit d27f02f

27 files changed

+619
-96
lines changed

Foundation/NSArray.swift

+36-6
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,45 @@ public class NSArray : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NS
6868
}
6969

7070
public required convenience init?(coder aDecoder: NSCoder) {
71-
self.init(objects: nil, count: 0)
71+
if !aDecoder.allowsKeyedCoding {
72+
var cnt: UInt32 = 0
73+
// We're stuck with (int) here (rather than unsigned int)
74+
// because that's the way the code was originally written, unless
75+
// we go to a new version of the class, which has its own problems.
76+
withUnsafeMutablePointer(&cnt) { (ptr: UnsafeMutablePointer<UInt32>) -> Void in
77+
aDecoder.decodeValueOfObjCType("i", at: UnsafeMutablePointer<Void>(ptr))
78+
}
79+
let objects = UnsafeMutablePointer<AnyObject?>.alloc(Int(cnt))
80+
for idx in 0..<cnt {
81+
objects.advancedBy(Int(idx)).initialize(aDecoder.decodeObject())
82+
}
83+
self.init(objects: UnsafePointer<AnyObject?>(objects), count: Int(cnt))
84+
objects.destroy(Int(cnt))
85+
objects.dealloc(Int(cnt))
86+
} else if aDecoder.dynamicType == NSKeyedUnarchiver.self || aDecoder.containsValueForKey("NS.objects") {
87+
let objects = aDecoder._decodeArrayOfObjectsForKey("NS.objects")
88+
self.init(array: objects)
89+
} else {
90+
var objects = [AnyObject]()
91+
var count = 0
92+
while let object = aDecoder.decodeObjectForKey("NS.object.\(count)") {
93+
objects.append(object)
94+
count += 1
95+
}
96+
self.init(array: objects)
97+
}
7298
}
7399

74100
public func encodeWithCoder(aCoder: NSCoder) {
75-
101+
if let keyedArchiver = aCoder as? NSKeyedArchiver {
102+
keyedArchiver._encodeArrayOfObjects(self, forKey:"NS.objects")
103+
} else {
104+
for object in self {
105+
if let codable = object as? NSCoding {
106+
codable.encodeWithCoder(aCoder)
107+
}
108+
}
109+
}
76110
}
77111

78112
public static func supportsSecureCoding() -> Bool {
@@ -643,10 +677,6 @@ public class NSMutableArray : NSArray {
643677
}
644678
}
645679

646-
public required convenience init(coder: NSCoder) {
647-
self.init()
648-
}
649-
650680
public override subscript (idx: Int) -> AnyObject {
651681
get {
652682
return objectAtIndex(idx)

Foundation/NSCFArray.swift

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ internal final class _NSCFArray : NSMutableArray {
4242
override func removeObjectAtIndex(index: Int) {
4343
CFArrayRemoveValueAtIndex(_cfMutableObject, index)
4444
}
45+
46+
override var classForCoder: AnyClass {
47+
return NSMutableArray.self
48+
}
4549
}
4650

4751
internal func _CFSwiftArrayGetCount(array: AnyObject) -> CFIndex {

Foundation/NSCFDictionary.swift

+4
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ internal final class _NSCFDictionary : NSMutableDictionary {
8787
override func setObject(anObject: AnyObject, forKey aKey: NSObject) {
8888
CFDictionarySetValue(_cfMutableObject, unsafeBitCast(aKey, UnsafePointer<Void>.self), unsafeBitCast(anObject, UnsafePointer<Void>.self))
8989
}
90+
91+
override var classForCoder: AnyClass {
92+
return NSMutableDictionary.self
93+
}
9094
}
9195

9296
internal func _CFSwiftDictionaryGetCount(dictionary: AnyObject) -> CFIndex {

Foundation/NSCFSet.swift

+4
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ internal final class _NSCFSet : NSMutableSet {
2727
required init(capacity numItems: Int) {
2828
fatalError()
2929
}
30+
31+
override var classForCoder: AnyClass {
32+
return NSMutableSet.self
33+
}
3034
}

Foundation/NSCFString.swift

+8
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ internal class _NSCFString : NSMutableString {
5151
override func replaceCharactersInRange(range: NSRange, withString aString: String) {
5252
CFStringReplace(unsafeBitCast(self, CFMutableStringRef.self), CFRangeMake(range.location, range.length), aString._cfObject)
5353
}
54+
55+
override var classForCoder: AnyClass {
56+
return NSMutableString.self
57+
}
5458
}
5559

5660
internal final class _NSCFConstantString : _NSCFString {
@@ -107,6 +111,10 @@ internal final class _NSCFConstantString : _NSCFString {
107111
override func replaceCharactersInRange(range: NSRange, withString aString: String) {
108112
fatalError()
109113
}
114+
115+
override var classForCoder: AnyClass {
116+
return NSString.self
117+
}
110118
}
111119

112120
internal func _CFSwiftStringGetLength(string: AnyObject) -> CFIndex {

Foundation/NSCalendar.swift

+94-7
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,52 @@ public class NSCalendar : NSObject, NSCopying, NSSecureCoding {
106106
return unsafeBitCast(self, CFCalendarRef.self)
107107
}
108108

109-
public required init?(coder aDecoder: NSCoder) {
110-
NSUnimplemented()
109+
public convenience required init?(coder aDecoder: NSCoder) {
110+
if aDecoder.allowsKeyedCoding {
111+
guard let calendarIdentifier = aDecoder.decodeObjectOfClass(NSString.self, forKey: "NS.identifier") else {
112+
return nil
113+
}
114+
115+
self.init(calendarIdentifier: calendarIdentifier.bridge())
116+
117+
if let timeZone = aDecoder.decodeObjectOfClass(NSTimeZone.self, forKey: "NS.timezone") {
118+
self.timeZone = timeZone
119+
}
120+
if let locale = aDecoder.decodeObjectOfClass(NSLocale.self, forKey: "NS.locale") {
121+
self.locale = locale
122+
}
123+
self.firstWeekday = aDecoder.decodeIntegerForKey("NS.firstwkdy")
124+
self.minimumDaysInFirstWeek = aDecoder.decodeIntegerForKey("NS.mindays")
125+
if let startDate = aDecoder.decodeObjectOfClass(NSDate.self, forKey: "NS.gstartdate") {
126+
self._startDate = startDate
127+
}
128+
} else {
129+
NSUnimplemented()
130+
}
131+
}
132+
133+
private var _startDate : NSDate? {
134+
get {
135+
return CFCalendarCopyGregorianStartDate(self._cfObject)?._nsObject
136+
}
137+
set {
138+
if let startDate = newValue {
139+
CFCalendarSetGregorianStartDate(self._cfObject, startDate._cfObject)
140+
}
141+
}
111142
}
112143

113144
public func encodeWithCoder(aCoder: NSCoder) {
114-
NSUnimplemented()
145+
if aCoder.allowsKeyedCoding {
146+
aCoder.encodeObject(self.calendarIdentifier.bridge(), forKey: "NS.identifier")
147+
aCoder.encodeObject(self.timeZone, forKey: "NS.timezone")
148+
aCoder.encodeObject(self.locale, forKey: "NS.locale")
149+
aCoder.encodeInteger(self.firstWeekday, forKey: "NS.firstwkdy")
150+
aCoder.encodeInteger(self.minimumDaysInFirstWeek, forKey: "NS.mindays")
151+
aCoder.encodeObject(self._startDate, forKey: "NS.gstartdate");
152+
} else {
153+
NSUnimplemented()
154+
}
115155
}
116156

117157
static public func supportsSecureCoding() -> Bool {
@@ -171,7 +211,12 @@ public class NSCalendar : NSObject, NSCopying, NSSecureCoding {
171211
_CFDeinit(self)
172212
}
173213

174-
public var calendarIdentifier: String { NSUnimplemented() }
214+
public var calendarIdentifier: String {
215+
get {
216+
return CFCalendarGetIdentifier(_cfObject)._swiftObject
217+
}
218+
}
219+
175220
/*@NSCopying*/ public var locale: NSLocale? {
176221
get {
177222
return CFCalendarCopyLocale(_cfObject)._nsObject
@@ -1214,12 +1259,54 @@ public class NSDateComponents : NSObject, NSCopying, NSSecureCoding {
12141259
return false
12151260
}
12161261

1217-
public required init?(coder aDecoder: NSCoder) {
1218-
NSUnimplemented()
1262+
public convenience required init?(coder aDecoder: NSCoder) {
1263+
if aDecoder.allowsKeyedCoding {
1264+
self.init()
1265+
1266+
self.era = aDecoder.decodeIntegerForKey("NS.era")
1267+
self.year = aDecoder.decodeIntegerForKey("NS.year")
1268+
self.quarter = aDecoder.decodeIntegerForKey("NS.quarter")
1269+
self.month = aDecoder.decodeIntegerForKey("NS.month")
1270+
self.day = aDecoder.decodeIntegerForKey("NS.day")
1271+
self.hour = aDecoder.decodeIntegerForKey("NS.hour")
1272+
self.minute = aDecoder.decodeIntegerForKey("NS.minute")
1273+
self.second = aDecoder.decodeIntegerForKey("NS.second")
1274+
self.nanosecond = aDecoder.decodeIntegerForKey("NS.nanosec")
1275+
self.weekOfYear = aDecoder.decodeIntegerForKey("NS.weekOfYear")
1276+
self.weekOfMonth = aDecoder.decodeIntegerForKey("NS.weekOfMonth")
1277+
self.yearForWeekOfYear = aDecoder.decodeIntegerForKey("NS.yearForWOY")
1278+
self.weekday = aDecoder.decodeIntegerForKey("NS.weekday")
1279+
self.weekdayOrdinal = aDecoder.decodeIntegerForKey("NS.weekdayOrdinal")
1280+
self.leapMonth = aDecoder.decodeBoolForKey("NS.leapMonth")
1281+
self.calendar = aDecoder.decodeObjectOfClass(NSCalendar.self, forKey: "NS.calendar")
1282+
self.timeZone = aDecoder.decodeObjectOfClass(NSTimeZone.self, forKey: "NS.timezone")
1283+
} else {
1284+
NSUnimplemented()
1285+
}
12191286
}
12201287

12211288
public func encodeWithCoder(aCoder: NSCoder) {
1222-
NSUnimplemented()
1289+
if aCoder.allowsKeyedCoding {
1290+
aCoder.encodeInteger(self.era, forKey: "NS.era")
1291+
aCoder.encodeInteger(self.year, forKey: "NS.year")
1292+
aCoder.encodeInteger(self.quarter, forKey: "NS.quarter")
1293+
aCoder.encodeInteger(self.month, forKey: "NS.month")
1294+
aCoder.encodeInteger(self.day, forKey: "NS.day")
1295+
aCoder.encodeInteger(self.hour, forKey: "NS.hour")
1296+
aCoder.encodeInteger(self.minute, forKey: "NS.minute")
1297+
aCoder.encodeInteger(self.second, forKey: "NS.second")
1298+
aCoder.encodeInteger(self.nanosecond, forKey: "NS.nanosec")
1299+
aCoder.encodeInteger(self.weekOfYear, forKey: "NS.weekOfYear")
1300+
aCoder.encodeInteger(self.weekOfMonth, forKey: "NS.weekOfMonth")
1301+
aCoder.encodeInteger(self.yearForWeekOfYear, forKey: "NS.yearForWOY")
1302+
aCoder.encodeInteger(self.weekday, forKey: "NS.weekday")
1303+
aCoder.encodeInteger(self.weekdayOrdinal, forKey: "NS.weekdayOrdinal")
1304+
aCoder.encodeBool(self.leapMonth, forKey: "NS.leapMonth")
1305+
aCoder.encodeObject(self.calendar, forKey: "NS.calendar")
1306+
aCoder.encodeObject(self.timeZone, forKey: "NS.timezone")
1307+
} else {
1308+
NSUnimplemented()
1309+
}
12231310
}
12241311

12251312
static public func supportsSecureCoding() -> Bool {

Foundation/NSCoder.swift

+3-12
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,9 @@ public class NSCoder : NSObject {
291291

292292
public func failWithError(error: NSError) {
293293
if let debugDescription = error.userInfo["NSDebugDescription"] {
294-
fatalError("*** NSKeyedUnarchiver.init: \(debugDescription)")
294+
NSLog("*** NSKeyedUnarchiver.init: \(debugDescription)")
295+
} else {
296+
NSLog("*** NSKeyedUnarchiver.init: decoding error")
295297
}
296298
}
297299

@@ -303,14 +305,3 @@ public class NSCoder : NSObject {
303305
NSRequiresConcreteImplementation()
304306
}
305307
}
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-
}

Foundation/NSConcreteValue.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ internal class NSConcreteValue : NSValue {
110110
return NSString(self._typeInfo.name).UTF8String // XXX leaky
111111
}
112112

113-
override var classForKeyedArchiver: AnyClass? {
113+
override var classForCoder: AnyClass {
114114
return NSValue.self
115115
}
116116

Foundation/NSData.swift

+21-7
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,30 @@ public class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
162162
}
163163

164164
public func encodeWithCoder(aCoder: NSCoder) {
165-
165+
if let aKeyedCoder = aCoder as? NSKeyedArchiver {
166+
aKeyedCoder._encodePropertyList(self, forKey: "NS.data")
167+
} else {
168+
aCoder.encodeBytes(UnsafePointer<UInt8>(self.bytes), length: self.length)
169+
}
166170
}
167171

168172
public required convenience init?(coder aDecoder: NSCoder) {
169-
NSUnimplemented()
173+
if !aDecoder.allowsKeyedCoding {
174+
if let data = aDecoder.decodeDataObject() {
175+
self.init(data: data)
176+
} else {
177+
return nil
178+
}
179+
} else if aDecoder.dynamicType == NSKeyedUnarchiver.self || aDecoder.containsValueForKey("NS.data") {
180+
guard let data = aDecoder._decodePropertyListForKey("NS.data") as? NSData else {
181+
return nil
182+
}
183+
self.init(data: data)
184+
} else {
185+
var len = 0
186+
let bytes = aDecoder.decodeBytesForKey("NS.bytes", returnedLength: &len)
187+
self.init(bytes: bytes, length: len)
188+
}
170189
}
171190

172191
public static func supportsSecureCoding() -> Bool {
@@ -544,11 +563,6 @@ public class NSMutableData : NSData {
544563
self.init(bytes: nil, length: 0)
545564
}
546565

547-
public required convenience init?(coder aDecoder: NSCoder) {
548-
NSUnimplemented()
549-
}
550-
551-
552566
internal override init(bytes: UnsafeMutablePointer<Void>, length: Int, copy: Bool, deallocator: ((UnsafeMutablePointer<Void>, Int) -> Void)?) {
553567
super.init(bytes: bytes, length: length, copy: copy, deallocator: deallocator)
554568
}

Foundation/NSDate.swift

+16-3
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,17 @@ public class NSDate : NSObject, NSCopying, NSSecureCoding, NSCoding {
7171
_timeIntervalSinceReferenceDate = ti
7272
}
7373

74-
public required init?(coder aDecoder: NSCoder) {
75-
NSUnimplemented()
74+
public convenience required init?(coder aDecoder: NSCoder) {
75+
if aDecoder.allowsKeyedCoding {
76+
let ti = aDecoder.decodeDoubleForKey("NS.time")
77+
self.init(timeIntervalSinceReferenceDate: ti)
78+
} else {
79+
var ti: NSTimeInterval = 0.0
80+
withUnsafeMutablePointer(&ti) { (ptr: UnsafeMutablePointer<Double>) -> Void in
81+
aDecoder.decodeValueOfObjCType("d", at: UnsafeMutablePointer<Void>(ptr))
82+
}
83+
self.init(timeIntervalSinceReferenceDate: ti)
84+
}
7685
}
7786

7887
public override func copy() -> AnyObject {
@@ -88,7 +97,11 @@ public class NSDate : NSObject, NSCopying, NSSecureCoding, NSCoding {
8897
}
8998

9099
public func encodeWithCoder(aCoder: NSCoder) {
91-
100+
if aCoder.allowsKeyedCoding {
101+
aCoder.encodeDouble(_timeIntervalSinceReferenceDate, forKey: "NS.time")
102+
} else {
103+
NSUnimplemented()
104+
}
92105
}
93106

94107
/**

Foundation/NSDecimalNumber.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ public class NSDecimalNumber : NSNumber {
5151
NSUnimplemented()
5252
}
5353

54+
public required convenience init(bytes buffer: UnsafePointer<Void>, objCType type: UnsafePointer<Int8>) {
55+
NSRequiresConcreteImplementation()
56+
}
57+
5458
public func descriptionWithLocale(locale: AnyObject?) -> String { NSUnimplemented() }
5559

5660
// TODO: "declarations from extensions cannot be overridden yet"
@@ -96,7 +100,7 @@ public class NSDecimalNumber : NSNumber {
96100
// ignore exactnessException
97101
// raise on overflow, underflow and divide by zero.
98102

99-
public var objCType: UnsafePointer<Int8> { NSUnimplemented() }
103+
public override var objCType: UnsafePointer<Int8> { NSUnimplemented() }
100104
// return 'd' for double
101105

102106
public override var doubleValue: Double { NSUnimplemented() }

0 commit comments

Comments
 (0)