Skip to content

Commit 7f08595

Browse files
authored
Foundation: more idiomatic Swift in NSKeyedArchiver (#3160)
* Foundation: use class cluster in NSValue implementation * Foundation: use first(where:) in NSSpecialValue Use first(where:) in NSSpecialValue instead of iterating loop, as it is more idiomatic. * Foundation: collapse guard conditional in NSSpecialValue * Foundation: more idiomatic swift in NSKeyedArchiver Eliminate some force-unwrap/force-casts in NSKeyedArchiver and NSKeyedUnarchiver. Some notes about whether unarchiver delegate is called when decoding nil objects. * Foundation: more idiomatic Swift in NSKeyedUnarchiver Unwrapped variable can have same name as optional.
1 parent 091f867 commit 7f08595

File tree

9 files changed

+69
-174
lines changed

9 files changed

+69
-174
lines changed

Docs/Archiving.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ There is a preliminary implementation of NSKeyedArchiver and NSKeyedUnarchiver w
3737
* NSTimeZone
3838
* NSURL
3939
* NSUUID
40-
* NSValue (via class cluster hack)
40+
* NSValue
4141

4242
## TODO
4343

Sources/Foundation/NSGeometry.swift

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,42 +1085,38 @@ public func NSRectFromString(_ aString: String) -> NSRect {
10851085

10861086
extension NSValue {
10871087
public convenience init(point: NSPoint) {
1088-
self.init()
1089-
self._concreteValue = NSSpecialValue(point)
1088+
self.init { NSSpecialValue(point) as! Self }
10901089
}
10911090

10921091
public convenience init(size: NSSize) {
1093-
self.init()
1094-
self._concreteValue = NSSpecialValue(size)
1092+
self.init { NSSpecialValue(size) as! Self }
10951093
}
10961094

10971095
public convenience init(rect: NSRect) {
1098-
self.init()
1099-
self._concreteValue = NSSpecialValue(rect)
1096+
self.init { NSSpecialValue(rect) as! Self }
11001097
}
11011098

11021099
public convenience init(edgeInsets insets: NSEdgeInsets) {
1103-
self.init()
1104-
self._concreteValue = NSSpecialValue(insets)
1100+
self.init { NSSpecialValue(insets) as! Self }
11051101
}
11061102

11071103
public var pointValue: NSPoint {
1108-
let specialValue = self._concreteValue as! NSSpecialValue
1104+
let specialValue = self as! NSSpecialValue
11091105
return specialValue._value as! NSPoint
11101106
}
11111107

11121108
public var sizeValue: NSSize {
1113-
let specialValue = self._concreteValue as! NSSpecialValue
1109+
let specialValue = self as! NSSpecialValue
11141110
return specialValue._value as! NSSize
11151111
}
11161112

11171113
public var rectValue: NSRect {
1118-
let specialValue = self._concreteValue as! NSSpecialValue
1114+
let specialValue = self as! NSSpecialValue
11191115
return specialValue._value as! NSRect
11201116
}
11211117

11221118
public var edgeInsetsValue: NSEdgeInsets {
1123-
let specialValue = self._concreteValue as! NSSpecialValue
1119+
let specialValue = self as! NSSpecialValue
11241120
return specialValue._value as! NSEdgeInsets
11251121
}
11261122
}

Sources/Foundation/NSKeyedArchiver.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -405,11 +405,12 @@ open class NSKeyedArchiver : NSCoder {
405405
Returns true if the object has already been encoded.
406406
*/
407407
private func _haveVisited(_ objv: Any?) -> Bool {
408-
if objv == nil {
409-
return true // always have a null reference
410-
} else {
411-
return self._objRefMap[__SwiftValue.store(objv!)] != nil
408+
guard let objv = objv else {
409+
// always have a null reference
410+
return true
412411
}
412+
413+
return self._objRefMap[__SwiftValue.store(objv)] != nil
413414
}
414415

415416
/**

Sources/Foundation/NSKeyedUnarchiver.swift

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -201,15 +201,15 @@ open class NSKeyedUnarchiver : NSCoder {
201201
}
202202

203203
private func _objectInCurrentDecodingContext<T>(forKey key: String?) -> T? {
204-
var unwrappedKey = key
204+
let unwrappedKey: String
205205

206-
if key != nil {
207-
unwrappedKey = escapeArchiverKey(key!)
206+
if let key = key {
207+
unwrappedKey = escapeArchiverKey(key)
208208
} else {
209209
unwrappedKey = _nextGenericKey()
210210
}
211211

212-
if let v = _currentDecodingContext.dict[unwrappedKey!] {
212+
if let v = _currentDecodingContext.dict[unwrappedKey] {
213213
return v as? T
214214
}
215215
return nil
@@ -272,18 +272,18 @@ open class NSKeyedUnarchiver : NSCoder {
272272
}
273273

274274
private func _isClassAllowed(_ assertedClass: AnyClass?, allowedClasses: [AnyClass]?) -> Bool {
275-
if assertedClass == nil {
275+
guard let assertedClass = assertedClass else {
276276
return false
277277
}
278278

279279
if _flags.contains(.requiresSecureCoding) {
280280
if let unwrappedAllowedClasses = allowedClasses {
281-
if unwrappedAllowedClasses.contains(where: {NSKeyedUnarchiver._classIsKindOfClass(assertedClass!, $0)}) {
281+
if unwrappedAllowedClasses.contains(where: {NSKeyedUnarchiver._classIsKindOfClass(assertedClass, $0)}) {
282282
return true
283283
}
284284
}
285285

286-
fatalError("Value was of unexpected class \(assertedClass!)")
286+
fatalError("Value was of unexpected class \(assertedClass)")
287287
} else {
288288
return true
289289
}
@@ -311,25 +311,25 @@ open class NSKeyedUnarchiver : NSCoder {
311311
return aClass
312312
}
313313

314-
guard let unwrappedClassDict = classDict else {
314+
guard let classDict = classDict else {
315315
return false
316316
}
317317

318318
// TODO is it required to validate the superclass hierarchy?
319-
let assertedClassName = unwrappedClassDict["$classname"] as? String
320-
let assertedClassHints = unwrappedClassDict["$classhints"] as? [String]
321-
let assertedClasses = unwrappedClassDict["$classes"] as? [String]
319+
let assertedClassName = classDict["$classname"] as? String
320+
let assertedClassHints = classDict["$classhints"] as? [String]
321+
let assertedClasses = classDict["$classes"] as? [String]
322322

323-
if assertedClassName != nil {
324-
let assertedClass : AnyClass? = _classForClassName(assertedClassName!)
323+
if let assertedClassName = assertedClassName {
324+
let assertedClass : AnyClass? = _classForClassName(assertedClassName)
325325
if _isClassAllowed(assertedClass, allowedClasses: allowedClasses) {
326326
classToConstruct = assertedClass
327327
return true
328328
}
329329
}
330330

331-
if assertedClassHints != nil {
332-
for assertedClassHint in assertedClassHints! {
331+
if let assertedClassHints = assertedClassHints {
332+
for assertedClassHint in assertedClassHints {
333333
// FIXME check whether class hints should be subject to mapping or not
334334
let assertedClass : AnyClass? = NSClassFromString(assertedClassHint)
335335
if _isClassAllowed(assertedClass, allowedClasses: allowedClasses) {
@@ -339,11 +339,11 @@ open class NSKeyedUnarchiver : NSCoder {
339339
}
340340
}
341341

342-
if assertedClassName != nil {
342+
if let assertedClassName = assertedClassName {
343343
if let unwrappedDelegate = self.delegate {
344344
classToConstruct = unwrappedDelegate.unarchiver(self,
345-
cannotDecodeObjectOfClassName: assertedClassName!,
346-
originalClasses: assertedClasses != nil ? assertedClasses! : [])
345+
cannotDecodeObjectOfClassName: assertedClassName,
346+
originalClasses: assertedClasses ?? [])
347347
if classToConstruct != nil {
348348
return true
349349
}
@@ -417,28 +417,26 @@ open class NSKeyedUnarchiver : NSCoder {
417417
}
418418

419419
private func _replacementObject(_ decodedObject: Any?) -> Any? {
420-
var object : Any? = nil // object to encode after substitution
421-
422-
// nil cannot be mapped
423-
if decodedObject == nil {
420+
// nil cannot be mapped (this appears to differ from Darwin?)
421+
guard let decodedObject = decodedObject else {
424422
return nil
425423
}
426424

427425
// check replacement cache
428-
object = self._replacementMap[__SwiftValue.store(decodedObject!)]
429-
if object != nil {
426+
if let object = self._replacementMap[__SwiftValue.store(decodedObject)] {
430427
return object
431428
}
432-
433-
// object replaced by delegate. If the delegate returns nil, nil is encoded
429+
430+
// object replaced by delegate. If using ARC, the delegate should only return
431+
// nil if the object itself is nil.
434432
if let unwrappedDelegate = self.delegate {
435-
object = unwrappedDelegate.unarchiver(self, didDecode: decodedObject!)
436-
if object != nil {
437-
replaceObject(decodedObject!, withObject: object!)
438-
return object
439-
}
433+
let object = unwrappedDelegate.unarchiver(self, didDecode: decodedObject)
434+
if object != nil {
435+
replaceObject(decodedObject, withObject: object!)
436+
return object
437+
}
440438
}
441-
439+
442440
return decodedObject
443441
}
444442

@@ -470,12 +468,12 @@ open class NSKeyedUnarchiver : NSCoder {
470468
throw InternalError.decodingHasAlreadyFailed
471469
}
472470

473-
if !(objectRef is _NSKeyedArchiverUID) {
471+
guard let objectRef = objectRef as? _NSKeyedArchiverUID else {
474472
throw _decodingError(.coderReadCorrupt,
475473
withDescription: "Object \(objectRef) is not a reference. The data may be corrupt.")
476474
}
477-
478-
guard let dereferencedObject = _dereferenceObjectReference(objectRef as! _NSKeyedArchiverUID) else {
475+
476+
guard let dereferencedObject = _dereferenceObjectReference(objectRef) else {
479477
throw _decodingError(.coderReadCorrupt,
480478
withDescription: "Invalid object reference \(objectRef). The data may be corrupt.")
481479
}
@@ -486,7 +484,7 @@ open class NSKeyedUnarchiver : NSCoder {
486484

487485
if _isContainer(dereferencedObject) {
488486
// check cached of decoded objects
489-
object = _cachedObjectForReference(objectRef as! _NSKeyedArchiverUID)
487+
object = _cachedObjectForReference(objectRef)
490488
if object == nil {
491489
guard let dict = dereferencedObject as? Dictionary<String, Any> else {
492490
throw _decodingError(.coderReadCorrupt,
@@ -523,7 +521,7 @@ open class NSKeyedUnarchiver : NSCoder {
523521
withDescription: "Class \(classToConstruct!) failed to decode. The data may be corrupt.")
524522
}
525523

526-
_cacheObject(object!, forReference: objectRef as! _NSKeyedArchiverUID)
524+
_cacheObject(object!, forReference: objectRef)
527525
}
528526
} else {
529527
object = __SwiftValue.store(dereferencedObject)

Sources/Foundation/NSRange.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,12 +403,11 @@ extension NSRange: NSSpecialValueCoding {
403403

404404
extension NSValue {
405405
public convenience init(range: NSRange) {
406-
self.init()
407-
self._concreteValue = NSSpecialValue(range)
406+
self.init { NSSpecialValue(range) as! Self }
408407
}
409408

410409
public var rangeValue: NSRange {
411-
let specialValue = self._concreteValue as! NSSpecialValue
410+
let specialValue = self as! NSSpecialValue
412411
return specialValue._value as! NSRange
413412
}
414413
}

Sources/Foundation/NSSpecialValue.swift

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,33 +46,17 @@ internal class NSSpecialValue : NSValue {
4646
}
4747

4848
private static func _flagsFromType(_ type: NSSpecialValueCoding.Type) -> Int {
49-
for (F, T) in _specialTypes {
50-
if T == type {
51-
return F
52-
}
53-
}
54-
return 0
49+
return _specialTypes.first(where: { $1 == type })?.0 ?? 0
5550
}
5651

5752
private static func _objCTypeFromType(_ type: NSSpecialValueCoding.Type) -> String? {
58-
for (_, T) in _specialTypes {
59-
if T == type {
60-
return T.objCType()
61-
}
62-
}
63-
return nil
53+
return _specialTypes.first(where: { $1 == type })?.1.objCType()
6454
}
6555

6656
internal static func _typeFromObjCType(_ type: UnsafePointer<Int8>) -> NSSpecialValueCoding.Type? {
6757
let objCType = String(cString: type)
6858

69-
for (_, T) in _specialTypes {
70-
if T.objCType() == objCType {
71-
return T
72-
}
73-
}
74-
75-
return nil
59+
return _specialTypes.first(where: { $1.objCType() == objCType })?.1
7660
}
7761

7862
internal var _value : NSSpecialValueCoding
@@ -98,10 +82,8 @@ internal class NSSpecialValue : NSValue {
9882
preconditionFailure("Unkeyed coding is unsupported.")
9983
}
10084
let specialFlags = aDecoder.decodeInteger(forKey: "NS.special")
101-
guard let specialType = NSSpecialValue._typeFromFlags(specialFlags) else {
102-
return nil
103-
}
104-
guard let specialValue = specialType.init(coder: aDecoder) else {
85+
guard let specialType = NSSpecialValue._typeFromFlags(specialFlags),
86+
let specialValue = specialType.init(coder: aDecoder) else {
10587
return nil
10688
}
10789
self.init(specialValue)
@@ -121,7 +103,6 @@ internal class NSSpecialValue : NSValue {
121103
}
122104

123105
override var classForCoder: AnyClass {
124-
// for some day when we support class clusters
125106
return NSValue.self
126107
}
127108

0 commit comments

Comments
 (0)