Skip to content

Commit 4c0fef0

Browse files
authored
Merge pull request #2232 from millenomi/nsorderedset-nscoding
2 parents 155f1ce + aa3e6e1 commit 4c0fef0

File tree

8 files changed

+165
-55
lines changed

8 files changed

+165
-55
lines changed

Foundation/NSOrderedSet.swift

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,8 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
6969
}
7070

7171
public required convenience init?(coder aDecoder: NSCoder) {
72-
guard aDecoder.allowsKeyedCoding else {
73-
preconditionFailure("Unkeyed coding is unsupported.")
74-
}
75-
var idx = 0
76-
var objects : [AnyObject] = []
77-
while aDecoder.containsValue(forKey: ("NS.object.\(idx)")) {
78-
guard let object = aDecoder.decodeObject(forKey: "NS.object.\(idx)") else {
79-
return nil
80-
}
81-
objects.append(object as! NSObject)
82-
idx += 1
83-
}
84-
self.init(array: objects)
72+
// This uses the same storage setup as NSSet, but without allowing the use of the "NS.objects" key:
73+
self.init(array: NSSet._objects(from: aDecoder, allowDecodingNonindexedArrayKey: false))
8574
}
8675

8776
open var count: Int {
@@ -339,7 +328,7 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
339328
public func description(withLocale locale: Locale?, indent level: Int) -> String {
340329
return _orderedStorage.description(withLocale: locale, indent: level)
341330
}
342-
331+
343332
public convenience init(object: Any) {
344333
self.init(array: [object])
345334
}
@@ -370,7 +359,7 @@ open class NSOrderedSet: NSObject, NSCopying, NSMutableCopying, NSSecureCoding,
370359
public convenience init(array set: [Any], copyItems flag: Bool) {
371360
self.init(array: set, range: NSRange(location: 0, length: set.count), copyItems: flag)
372361
}
373-
362+
374363
public convenience init(array set: [Any], range: NSRange, copyItems flag: Bool) {
375364
var objects = set
376365

@@ -470,7 +459,10 @@ open class NSMutableOrderedSet: NSOrderedSet {
470459
_orderedStorage = _mutableOrderedStorage
471460
}
472461

473-
public required init?(coder aDecoder: NSCoder) { NSUnimplemented() }
462+
public required convenience init?(coder aDecoder: NSCoder) {
463+
// See NSOrderedSet.init?(coder:)
464+
self.init(array: NSSet._objects(from: aDecoder, allowDecodingNonindexedArrayKey: false))
465+
}
474466

475467
open override func copy(with zone: NSZone? = nil) -> Any {
476468
if type(of: self) === NSMutableOrderedSet.self {
@@ -672,6 +664,69 @@ open class NSMutableOrderedSet: NSOrderedSet {
672664
open func sort(using sortDescriptors: [NSSortDescriptor]) {
673665
_mutableOrderedStorage.sort(using: sortDescriptors)
674666
}
667+
668+
// MARK: Convenience initializers that are automatically inherited in ObjC, but not in Swift:
669+
670+
public convenience init() {
671+
self.init(objects: [], count: 0)
672+
}
673+
674+
public convenience init(object: Any) {
675+
self.init(array: [object])
676+
}
677+
678+
public convenience init(orderedSet set: NSOrderedSet) {
679+
self.init(orderedSet: set, copyItems: false)
680+
}
681+
682+
public convenience init(orderedSet set: NSOrderedSet, copyItems flag: Bool) {
683+
self.init(orderedSet: set, range: NSRange(location: 0, length: set.count), copyItems: flag)
684+
}
685+
686+
public convenience init(orderedSet set: NSOrderedSet, range: NSRange, copyItems flag: Bool) {
687+
// TODO: Use the array method here when available.
688+
self.init(array: Array(set), range: range, copyItems: flag)
689+
}
690+
691+
public convenience init(array: [Any]) {
692+
let buffer = UnsafeMutablePointer<AnyObject>.allocate(capacity: array.count)
693+
for (idx, element) in array.enumerated() {
694+
buffer.advanced(by: idx).initialize(to: __SwiftValue.store(element))
695+
}
696+
self.init(objects: buffer, count: array.count)
697+
buffer.deinitialize(count: array.count)
698+
buffer.deallocate()
699+
}
700+
701+
public convenience init(array set: [Any], copyItems flag: Bool) {
702+
self.init(array: set, range: NSRange(location: 0, length: set.count), copyItems: flag)
703+
}
704+
705+
public convenience init(array set: [Any], range: NSRange, copyItems flag: Bool) {
706+
var objects = set
707+
708+
if let range = Range(range), range.count != set.count || flag {
709+
objects = [Any]()
710+
for index in range.indices {
711+
let object = set[index]
712+
objects.append(flag ? (object as! NSObject).copy() : object)
713+
}
714+
}
715+
716+
self.init(array: objects)
717+
}
718+
719+
public convenience init(set: Set<AnyHashable>) {
720+
self.init(set: set, copyItems: false)
721+
}
722+
723+
public convenience init(set: Set<AnyHashable>, copyItems flag: Bool) {
724+
self.init(array: Array(set), copyItems: flag)
725+
}
726+
727+
public convenience init(objects elements: Any...) {
728+
self.init(array: elements)
729+
}
675730
}
676731

677732

Foundation/NSSet.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,17 +86,19 @@ open class NSSet : NSObject, NSCopying, NSMutableCopying, NSSecureCoding, NSCodi
8686
self.init(array: [object])
8787
}
8888

89-
internal class func _objects(from aDecoder: NSCoder) -> [NSObject] {
89+
internal class func _objects(from aDecoder: NSCoder, allowDecodingNonindexedArrayKey: Bool = true) -> [NSObject] {
9090
guard aDecoder.allowsKeyedCoding else {
9191
preconditionFailure("Unkeyed coding is unsupported.")
9292
}
93-
if type(of: aDecoder) == NSKeyedUnarchiver.self || aDecoder.containsValue(forKey: "NS.objects") {
93+
if (allowDecodingNonindexedArrayKey && type(of: aDecoder) == NSKeyedUnarchiver.self) || aDecoder.containsValue(forKey: "NS.objects") {
9494
let objects = aDecoder._decodeArrayOfObjectsForKey("NS.objects")
9595
return objects as! [NSObject]
9696
} else {
9797
var objects: [NSObject] = []
9898
var count = 0
99-
while let object = aDecoder.decodeObject(forKey: "NS.object.\(count)") {
99+
var key: String { return "NS.object.\(count)" }
100+
while aDecoder.containsValue(forKey: key) {
101+
let object = aDecoder.decodeObject(forKey: key)
100102
objects.append(object as! NSObject)
101103
count += 1
102104
}

TestFoundation/FixtureValues.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,26 @@ enum Fixtures {
243243
return NSCharacterSet.alphanumerics as NSCharacterSet
244244
}
245245

246+
// ===== NSOrderedSet, NSMutableOrderedSet =====
247+
248+
static let orderedSetOfNumbers = TypedFixture<NSOrderedSet>("NSOrderedSet-Numbers") {
249+
let numbers = [1, 2, 3, 4, 5].map { NSNumber(value: $0) }
250+
return NSOrderedSet(array: numbers)
251+
}
252+
253+
static let orderedSetEmpty = TypedFixture<NSOrderedSet>("NSOrderedSet-Empty") {
254+
return NSOrderedSet()
255+
}
256+
257+
static let mutableOrderedSetOfNumbers = TypedFixture<NSMutableOrderedSet>("NSMutableOrderedSet-Numbers") {
258+
let numbers = [1, 2, 3, 4, 5].map { NSNumber(value: $0) }
259+
return NSMutableOrderedSet(array: numbers)
260+
}
261+
262+
static let mutableOrderedSetEmpty = TypedFixture<NSMutableOrderedSet>("NSMutableOrderedSet-Empty") {
263+
return NSMutableOrderedSet()
264+
}
265+
246266
// ===== Fixture list =====
247267

248268
static let _listOfAllFixtures: [AnyFixture] = [
@@ -273,6 +293,10 @@ enum Fixtures {
273293
AnyFixture(Fixtures.characterSetString),
274294
AnyFixture(Fixtures.characterSetBitmap),
275295
AnyFixture(Fixtures.characterSetBuiltin),
296+
AnyFixture(Fixtures.orderedSetOfNumbers),
297+
AnyFixture(Fixtures.orderedSetEmpty),
298+
AnyFixture(Fixtures.mutableOrderedSetOfNumbers),
299+
AnyFixture(Fixtures.mutableOrderedSetEmpty),
276300
]
277301

278302
// This ensures that we do not have fixtures with duplicate identifiers:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

TestFoundation/TestNSOrderedSet.swift

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,6 @@
99

1010
class TestNSOrderedSet : XCTestCase {
1111

12-
static var allTests: [(String, (TestNSOrderedSet) -> () throws -> Void)] {
13-
return [
14-
("test_BasicConstruction", test_BasicConstruction),
15-
("test_Enumeration", test_Enumeration),
16-
("test_Uniqueness", test_Uniqueness),
17-
("test_reversedEnumeration", test_reversedEnumeration),
18-
("test_reversedOrderedSet", test_reversedOrderedSet),
19-
("test_reversedEmpty", test_reversedEmpty),
20-
("test_ObjectAtIndex", test_ObjectAtIndex),
21-
("test_ObjectsAtIndexes", test_ObjectsAtIndexes),
22-
("test_FirstAndLastObjects", test_FirstAndLastObjects),
23-
("test_AddObject", test_AddObject),
24-
("test_AddObjects", test_AddObjects),
25-
("test_RemoveAllObjects", test_RemoveAllObjects),
26-
("test_RemoveObject", test_RemoveObject),
27-
("test_RemoveObjectAtIndex", test_RemoveObjectAtIndex),
28-
("test_IsEqualToOrderedSet", test_IsEqualToOrderedSet),
29-
("test_Subsets", test_Subsets),
30-
("test_ReplaceObject", test_ReplaceObject),
31-
("test_ExchangeObjects", test_ExchangeObjects),
32-
("test_MoveObjects", test_MoveObjects),
33-
("test_InsertObjects", test_InsertObjects),
34-
("test_Insert", test_Insert),
35-
("test_SetObjectAtIndex", test_SetObjectAtIndex),
36-
("test_RemoveObjectsInRange", test_RemoveObjectsInRange),
37-
("test_ReplaceObjectsAtIndexes", test_ReplaceObjectsAtIndexes),
38-
("test_Intersection", test_Intersection),
39-
("test_Subtraction", test_Subtraction),
40-
("test_Union", test_Union),
41-
("test_Initializers", test_Initializers),
42-
("test_Sorting", test_Sorting),
43-
("test_reversedEnumerationMutable", test_reversedEnumerationMutable),
44-
("test_reversedOrderedSetMutable", test_reversedOrderedSetMutable),
45-
]
46-
}
47-
4812
func test_BasicConstruction() {
4913
let set = NSOrderedSet()
5014
let set2 = NSOrderedSet(array: ["foo", "bar"])
@@ -513,4 +477,69 @@ class TestNSOrderedSet : XCTestCase {
513477
XCTAssertEqual(work.lastObject as? String, krow.firstObject as? String)
514478
}
515479

480+
let fixtures = [
481+
Fixtures.orderedSetEmpty,
482+
Fixtures.orderedSetOfNumbers
483+
]
484+
485+
let mutableFixtures = [
486+
Fixtures.mutableOrderedSetEmpty,
487+
Fixtures.mutableOrderedSetOfNumbers
488+
]
489+
490+
func test_codingRoundtrip() throws {
491+
for fixture in fixtures {
492+
try fixture.assertValueRoundtripsInCoder()
493+
}
494+
for fixture in mutableFixtures {
495+
try fixture.assertValueRoundtripsInCoder()
496+
}
497+
}
498+
499+
func test_loadedValuesMatch() throws {
500+
for fixture in fixtures {
501+
try fixture.assertLoadedValuesMatch()
502+
}
503+
for fixture in mutableFixtures {
504+
try fixture.assertLoadedValuesMatch()
505+
}
506+
}
507+
508+
static var allTests: [(String, (TestNSOrderedSet) -> () throws -> Void)] {
509+
return [
510+
("test_BasicConstruction", test_BasicConstruction),
511+
("test_Enumeration", test_Enumeration),
512+
("test_Uniqueness", test_Uniqueness),
513+
("test_reversedEnumeration", test_reversedEnumeration),
514+
("test_reversedOrderedSet", test_reversedOrderedSet),
515+
("test_reversedEmpty", test_reversedEmpty),
516+
("test_ObjectAtIndex", test_ObjectAtIndex),
517+
("test_ObjectsAtIndexes", test_ObjectsAtIndexes),
518+
("test_FirstAndLastObjects", test_FirstAndLastObjects),
519+
("test_AddObject", test_AddObject),
520+
("test_AddObjects", test_AddObjects),
521+
("test_RemoveAllObjects", test_RemoveAllObjects),
522+
("test_RemoveObject", test_RemoveObject),
523+
("test_RemoveObjectAtIndex", test_RemoveObjectAtIndex),
524+
("test_IsEqualToOrderedSet", test_IsEqualToOrderedSet),
525+
("test_Subsets", test_Subsets),
526+
("test_ReplaceObject", test_ReplaceObject),
527+
("test_ExchangeObjects", test_ExchangeObjects),
528+
("test_MoveObjects", test_MoveObjects),
529+
("test_InsertObjects", test_InsertObjects),
530+
("test_Insert", test_Insert),
531+
("test_SetObjectAtIndex", test_SetObjectAtIndex),
532+
("test_RemoveObjectsInRange", test_RemoveObjectsInRange),
533+
("test_ReplaceObjectsAtIndexes", test_ReplaceObjectsAtIndexes),
534+
("test_Intersection", test_Intersection),
535+
("test_Subtraction", test_Subtraction),
536+
("test_Union", test_Union),
537+
("test_Initializers", test_Initializers),
538+
("test_Sorting", test_Sorting),
539+
("test_reversedEnumerationMutable", test_reversedEnumerationMutable),
540+
("test_reversedOrderedSetMutable", test_reversedOrderedSetMutable),
541+
("test_codingRoundtrip", test_codingRoundtrip),
542+
("test_loadedValuesMatch", test_loadedValuesMatch),
543+
]
544+
}
516545
}

0 commit comments

Comments
 (0)