1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
//
// EVObject.swift
//
// Created by Edwin Vermeer on 5/2/15.
// Copyright (c) 2015 evict. All rights reserved.
//
import Foundation
/**
Object that implements EVReflectable and NSCoding. Use this object as your base class
instead of NSObject and you wil automatically have support for all these protocols.
*/
@objcMembers
open class EVObject: NSObject, NSCoding, EVReflectable {
// These are redundant in Swift 2+: CustomDebugStringConvertible, CustomStringConvertible, Hashable, Equatable
/**
Implementation of the setValue forUndefinedKey so that we can catch exceptions for when we use an optional Type like Int? in our object. Instead of using Int? you should use NSNumber?
This method is in EVObject and not in NSObject extension because you would get the error: method conflicts with previous declaration with the same Objective-C selector
- parameter value: The value that you wanted to set
- parameter key: The name of the property that you wanted to set
*/
open override func setValue(_ value: Any!, forUndefinedKey key: String) {
if let kvc = self as? EVGenericsKVC {
kvc.setGenericValue(value as AnyObject?, forUndefinedKey: key)
} else {
self.addStatusMessage(.IncorrectKey, message: "The class '\(EVReflection.swiftStringFromClass(self))' is not key value coding-compliant for the key '\(key)'")
evPrint(.IncorrectKey, "\nWARNING: The class '\(EVReflection.swiftStringFromClass(self))' is not key value coding-compliant for the key '\(key)'\n There is no support for optional type, array of optionals or enum properties.\nAs a workaround you can implement the function 'setValue forUndefinedKey' for this. See the unit tests for more information\n")
}
}
/**
Implementation of the NSObject isEqual comparisson method
This method is in EVObject and not in NSObject extension because you would get the error: method conflicts with previous declaration with the same Objective-C selector
- parameter object: The object where you want to compare with
- returns: Returns true if the object is the same otherwise false
*/
open override func isEqual(_ object: Any?) -> Bool { // for isEqual:
if let obj = object as? EVObject {
return EVReflection.areEqual(self, rhs: obj)
}
return false
}
/**
Returns the pritty description of this object
- returns: The pritty description
*/
open override var description: String {
get {
return EVReflection.description(self, prettyPrinted: true)
}
}
/**
Returns the pritty description of this object
- returns: The pritty description
*/
open override var debugDescription: String {
get {
return EVReflection.description(self, prettyPrinted: true)
}
}
/**
This basic init override is needed so we can use EVObject as a base class.
*/
public required override init() {
super.init()
}
/**
Decode any object
This method is in EVObject and not in NSObject because you would get the error: Initializer requirement 'init(coder:)' can
only be satisfied by a `required` initializer in the definition of non-final class 'NSObject'
-parameter coder: The NSCoder that will be used for decoding the object.
*/
public convenience required init?(coder: NSCoder) {
self.init()
EVReflection.decodeObjectWithCoder(self, aDecoder: coder, conversionOptions: .DefaultNSCoding)
}
/**
Encode this object using a NSCoder
- parameter aCoder: The NSCoder that will be used for encoding the object
*/
open func encode(with aCoder: NSCoder) {
EVReflection.encodeWithCoder(self , aCoder: aCoder, conversionOptions: .DefaultNSCoding)
}
//MARK - Default implementation of protocol functions that we can override
/**
By default there is no aditional validation. Override this function to add your own class level validation rules
- parameter dict: The dictionary with keys where the initialisation is called with
*/
open func initValidation(_ dict: NSDictionary) {
}
/**
Override this method when you want custom property mapping.
This method is in EVObject and not in extension of NSObject because a functions from extensions cannot be overwritten yet
- returns: Return an array with value pairs of the object property name and json key name.
*/
open func propertyMapping() -> [(keyInObject: String?, keyInResource: String?)] {
return []
}
/**
Override this method when you want custom property value conversion
This method is in EVObject and not in extension of NSObject because a functions from extensions cannot be overwritten yet
- returns: Returns an array where each item is a combination of the folowing 3 values: A string for the property name where the custom conversion is for, a setter function and a getter function.
*/
open func propertyConverters() -> [(key: String, decodeConverter: ((Any?)->()), encodeConverter: (() -> Any?))] {
return []
}
/**
You can add general value decoding to an object when you implement this function. You can for instance use it to base64 decode, url decode, html decode, unicode, etc.
- parameter value: The value that we will be decoded
- parameter key: The key for the value
- returns: The decoded value
*/
open func decodePropertyValue(value: Any, key: String) -> Any? {
return value
}
/**
You can add general value encoding to an object when you implement this function. You can for instance use it to base64 encode, url encode, html encode, unicode, etc.
- parameter value: The value that we will be encoded
- parameter key: The key for the value
- returns: The encoded value.
*/
open func encodePropertyValue(value: Any, key: String) -> Any {
return value
}
/**
This is a general functon where you can filter for specific values (like nil or empty string) when creating a dictionary
- parameter value: The value that we will test
- parameter key: The key for the value
- returns: True if the value needs to be ignored.
*/
open func skipPropertyValue(_ value: Any, key: String) -> Bool {
return false
}
/**
When a property is declared as a base type for multiple inherited classes, then this function will let you pick the right specific type based on the suplied dictionary.
- parameter dict: The dictionary for the specific type
- returns: The specific type
*/
open func getSpecificType(_ dict: NSDictionary) -> EVReflectable? {
return nil
}
/**
Return a custom object for the object
- returns: The custom object (single value, dictionary or array)
*/
open func customConverter() -> AnyObject? {
return nil
}
}