Swift:복잡한 객체를 UserDefaults로 저장
8807 단어 swift
setObject: forKey:
을 보셨을 거예요. 이 방법으로 저장NSDictionary
도 했고 NSArray
도 했고 문자열도 저장했어요.우연히 한 번에 계승자
JSONModel
의 실체류를 직접 저장한 후에 비극이 되었다.나중에 애플 문서를 찾아봤어요.The value parameter can be only property list objects: NSData, NSString,
NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects,
their contents must be property list objects.
간단하게 말하자면
setObject:forKey:
방법은 NSData
, NSString
따위의 대상을 저장할 수 있다. NSDictionary
와 NSArray
메모리에 넣은 요소도property list objects의 것이어야 한다.구체적으로 property list object가 뭐야?JSONModel
에 관해서는 여기를 봐도 괜찮아요.애플의 API가 이 지경에 이르렀으니 다른 생각은 더 이상 할 수 없다.네, 서류를 저장할 수 있어요.근데 여기서 말하는 건 User Defaults잖아.
이 문제를 해결하는 핵심 사상은 하나의 대상을
NSData
로 전환하거나 서열화하는 것이다NSData
.서열화된 견해가 반드시 정확하지는 않지만 이러한 과정이 존재하고 구체적인 뒤에 자세하게 설명한다.대상이 NSData
로 바뀔 수 있다면 NSUserDefaults
방법setObject: forKey:
이 적용된다.바로 이런 용법이다.//
class UserModel {
var userId: String = ""
var accessToken: String = ""
}
//
let userModel = UserModel()
//
let userDefaults = NSUserDefaults.standardUserDefaults()
let encodedObject = NSKeyedArchiver.archivedDataWithRootObject(object)
userDefaults.setObject(encodedObject, forKey: "UserInfoKey")
userDefaults.synchronize() //
대체적인 의미는 위의 코드에서 모두 구현되었다.하지만 위의 코드를 실행하면 틀림없이 오류가 발생할 것이다.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object UserModel for key UserInfoKey'
property list object가 아니기 때문에 실행 방법
setObject:forKey
을 적용할 때 App이 바로 Crash입니다.이 질문은property list object에 있는 것 같습니다.그러나 다시 말하자면 우리의 사고방식은 이 사용자 정의 실체류의 대상을
NSData
으로 바꾸는 것이다.이럴 때는 NSKeyedArchiver
와NSKeyedUnarchiver
를 써야 하고 이것도 간접적으로NSCoding
인터페이스를 사용해야 한다.하나의 실체류가 실현되지 않으면NSCoding
NSKeyedArchiver
과NSKeyedUnarchiver
에서 오류가 발생할 수 있기 때문이다.위 코드에 대한 작은 개선 사항:
class WeiboUserModel: NSObject, NSCoding { //1
struct PropertyKey {
static let userIdKey = "userId"
static let accessTokenKey = "accessToken"
static let expirationDateKey = "expirationDate"
static let refreshTokenKey = "refreshToken"
}
var userId: String?
var accessToken: String?
var expirationDate: NSDate?
var refreshToken: String?
func encodeWithCoder(aCoder: NSCoder) { //2
aCoder.encodeObject(userId, forKey: PropertyKey.userIdKey)
aCoder.encodeObject(accessToken, forKey: PropertyKey.accessTokenKey)
aCoder.encodeObject(expirationDate, forKey: PropertyKey.expirationDateKey)
aCoder.encodeObject(refreshToken, forKey: PropertyKey.refreshTokenKey)
}
required init?(coder aDecoder: NSCoder) { // 3
userId = aDecoder.decodeObjectForKey(PropertyKey.userIdKey) as? String
accessToken = aDecoder.decodeObjectForKey(PropertyKey.accessTokenKey) as? String
expirationDate = aDecoder.decodeObjectForKey(PropertyKey.expirationDateKey) as? NSDate
refreshToken = aDecoder.decodeObjectForKey(PropertyKey.refreshTokenKey) as? String
}
}
이렇게 수정하면 그들을 뛰게 할 수 있다.다음은 순서대로 설명한다.실현
NSObject
과NSCoding
.NSObject
는 넣지 않아도 되고, @objc
로 어떤 방법을 수식해도 된다.NSCoding
인터페이스는 서열화와 반서열화 대상을 제공할 때의 코딩 방법을 제공한다.UserModel
의 클래스 이름은 WeiboUserModel
로 수정되었습니다.이 부분의 코드는 전체 항목의 일부분이며, 뒤에 보충할 것이다.2. 하나의 대상을 서열화할 때 사용하는 방법func encodeWithCoder(aCoder: NSCoder)
인코딩.3. 역서열화할 때 방법init?(coder aDecoder: NSCoder)
으로 디코딩한다.대체적인 논리가 수정되지 않는 조건하에서 우리는 실체류 대상을 저장할 수 있는 완전한 코드를 보았다.
//
let userModel = WeiboUserModel()
//
let userDefaults = NSUserDefaults.standardUserDefaults()
let encodedObject = NSKeyedArchiver.archivedDataWithRootObject(object)
userDefaults.setObject(encodedObject, forKey: "UserInfoKey")
userDefaults.synchronize() //
이렇게 하면 운행할 수 있다.하지만 우리는 여기서 멈출 수 없다.프로젝트에 저장할 곳이 너무 많을 때, 곳곳에 복사 붙여넣기
NSUserDefaults
실례가 가득 쓰여 있기 때문이다.이런 코드는 너무 경직되어 있다.그리고 마지막 userDefaults.synchronize ()
호출을 잊어버리기 쉽다.이로 인해 객체의 스토리지에 문제가 발생할 수 있습니다.그래서 우리는 이 부분의 코드에 대해 일정한 봉인을 해야 한다.
extension NSUserDefaults { //1
func saveCustomObject(customObject object: NSCoding, key: String) { //2
let encodedObject = NSKeyedArchiver.archivedDataWithRootObject(object)
self.setObject(encodedObject, forKey: key)
self.synchronize()
}
func getCustomObject(forKey key: String) -> AnyObject? { //3
let decodedObject = self.objectForKey(key) as? NSData
if let decoded = decodedObject {
let object = NSKeyedUnarchiver.unarchiveObjectWithData(decoded)
return object
}
return nil
}
}
우리는 접근 방법을 모두
NSUserDefaults
의 확장에 두었다.이렇게 하면 사용자가 사용할 때 NSUserDefaults
자체의 방법과 같을 수 있다.그리고 synchronize()
방법도 안에 봉인되어 있어 더 이상 d대상이 저장되지 않은 것을 잊을 염려가 없습니다.호출된 작은 디테일을 봅시다.userDefaults.saveCustomObject(customObject: userModel, key: "UserInfoKey") //
userDefaults.getCustomObject("UserInfoKey") as? WeiboUserModel //
네, 여기까지.전체 항목의 코드는 여기로 이동하십시오.
to be continued
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
백그라운드에서 값을 계산하고 Swift 동시성 이후에 결과 사용값을 계산해야 하고 메인 스레드를 차단하지 않으려면 계산된 값을 반환하는 Swift Task 구조에서 해당 값을 계산하면 됩니다. Swift 동시성 이전에는 백그라운드 대기열로 이동하여 필요한 값을 계산하고 필요한 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.