Swift의 반사 메커니즘을 사용하여 객체 등록 정보 스트리밍
얼마 전에 맥OS 도면 작은 응용 프로그램인 cuImage를 썼는데 그 안의 몇몇 기술점은 줄곧 시간을 내서 정리하고 공유하지 못했다.졸업을 앞두고 일이 많아서 시간을 쪼개야만 했다.본고는 Swift의 반사 메커니즘을 이용하여 대상 속성을 옮겨다니며 코드를 간소화하고 코드 복용률을 높일 것이다.
cuImage에서 각 도상마다 상응하는 설정 정보가 있다. 예를 들어 칠우운의 도상 설정 정보
QiniuHostInfo
이다.나는 그것을 UserDefaults
을 통해 보존하기를 바란다.(그림의 일부 민감한 정보는 암호화해야 하지만 간략하게 설명하기 위해 본고는 암호화와 관련된 점을 언급하지 않는다. 사실 암호화에 있어서 나도 배추다. 왜 Keychain
을 암호화하지 않는지는 별개의 문제다. 여기서 생략한다.)UserDefaults
은 사용자 정의 객체를 지원하지 않으므로 강제로 저장하면 런타임 시 예외가 발생합니다.Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object 'Abc' for key 'Xyz'.
UserDefaults
을 통해 사용자 객체를 영구적으로 저장하려면 NSKeyedArchiver
을 통해 사용자 객체를 NSData 형식으로 인코딩해야 합니다.이것은 NSCoding
협의에 따라 이 협의 성명을 실현하는 두 가지 방법(init(_:)
과 encode(_:)
)이 필요하다.일반적인 실현 방식은 다음과 같다.final class QiniuHostInfo: NSObject, NSCoding {
var name = ""
var accessKey = ""
var secretKey = ""
init(name: String = "", accessKey: String = "", secretKey: String = "") {
self.name = name
self.accessKey = accessKey
self.secretKey = secretKey
super.init()
}
init?(coder aDecoder: NSCoder) {
name = aDecoder.decodeObject(forKey: #keyPath(name)) as! String
accessKey = aDecoder.decodeObject(forKey: #keyPath(accessKey)) as! String
secretKey = aDecoder.decodeObject(forKey: #keyPath(secretKey)) as! String
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: #keyPath(name))
aCoder.encode(accessKey, forKey: #keyPath(accessKey))
aCoder.encode(secretKey, forKey: #keyPath(secretKey))
}
}
final class ImgurHostInfo: NSObject, NSCoding {
var name = ""
var userName = ""
var password = ""
init(name: String = "", userName: String = "", password: String = "") {
self.name = name
self.userName = userName
self.password = password
super.init()
}
init?(coder aDecoder: NSCoder) {
name = aDecoder.decodeObject(forKey: #keyPath(name)) as! String
userName = aDecoder.decodeObject(forKey: #keyPath(userName)) as! String
password = aDecoder.decodeObject(forKey: #keyPath(password)) as! String
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: #keyPath(name))
aCoder.encode(userName, forKey: #keyPath(userName))
aCoder.encode(password, forKey: #keyPath(password))
}
}
이런 방식의 단점은
QiniuHostInfo
이 새로운 속성을 추가하거나 코드를 재구성할 때 속성을 수정하면 NSCoding
이 성명한 두 가지 방법에 대응하는 코드를 추가하거나 수정해야 하기 때문에 누락될 수 있다는 것이다.그리고 도상(예를 들어 ImgurHostInfo
)을 추가해야 할 때 같은 절차에 따라 코드를 훑어보아야 한다.다음은 내가 최종적으로 채택한 방식이다.우선, 나는 각종 그래픽 정보 클래스를 위해 공공 기류
HostInfo
을 썼고 NSCoding
협의 방법을 실현하는 임무를 기류 HostInfo
에 맡기고 한꺼번에 해결했다.앞으로 도상이 하나씩 증가할 때마다 상응하는 도상 정보 서브클래스(예를 들어 QiniuHostInfo
, ImgurHostInfo
)에서 자신의 속성을 정의하면 된다. 이런 종류의 코드는 훨씬 시원해진다.class HostInfo: NSObject, NSCoding {
var name = ""
override init() {
super.init()
}
convenience required init?(coder aDecoder: NSCoder) {
self.init()
forEachChildOfMirror(reflecting: self) { key in
setValue(aDecoder.decodeObject(forKey: key), forKey: key)
}
}
func encode(with aCoder: NSCoder) {
forEachChildOfMirror(reflecting: self) { key in
aCoder.encode(value(forKey: key), forKey: key)
}
}
func forEachChildOfMirror(reflecting subject: Any, handler: (String) -> Void) {
var mirror: Mirror? = Mirror(reflecting: subject)
while mirror != nil {
for child in mirror!.children {
if let key = child.label {
handler(key)
}
}
// Get super class's properties.
mirror = mirror!.superclassMirror
}
}
}
final class QiniuHostInfo: HostInfo {
var accessKey = ""
var secretKey = ""
}
final class ImgurHostInfo: HostInfo {
var userName = ""
var password = ""
}
위의 코드에서
init(_:)
과 encode(_:)
은 모두 반사를 필요로 하기 때문에 나는 공공 부분을 추출하고 하나의 속성에 접근할 때마다 해야 하는 조작을 클로즈업 형식으로 forEachChildOfMirror(_:_:)
함수에 전달했다.그 중에서 superclassMirror
을 사용한 것은 부류에서도 일부 공공 속성이 옮겨야 하기 때문이다. 예를 들어 HostInfo
의 name
속성이다.그래서 현재 클래스의 속성을 두루 훑어본 후 superclassMirror
을 통해 계승 체인을 따라 올라가 계승 연결된 클래스의 모든 속성을 방문할 수 있다.만약 독자들이 다른 괜찮은 실현 방식이 있다면, 당신들의 공유를 기대합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.