[iOS] NSCoding

RudinP·2025년 6월 7일
0

Study

목록 보기
274/292

직렬화(Serialization)

  • 객체를 파일로 저장하거나 네트워크로 전송 전 바이너리로 바꾸는 과정

역직렬화(Deserialization)

  • 바이너리 데이터를 객체로 바꾸는 과정

아카이빙(Archiving)

  • 데이터를 특정한 형식으로 패키징하거나 압축해서 보관하는 과정
  • 반대는 Unarchiving

NSCoding

  • 직렬화와 아카이빙을 구현하기 위해 사용하는 필수 프로토콜

  • 필수 프로토콜은 이 두가지
    • 생성자: 바이너리 데이터를 읽어서 인스턴스를 생성하는 코드 구현(디코딩)
    • encode: 인스턴스에 저장된 값을 바이너리 형태로 저장하는 코드 구현(인코딩)

구현

1) NSObject, NSCoding 프로토콜을 채택하는 모델 생성

class Language: NSObject, NSCoding {
	let name: String
    let version: Double
    let logo: UIImage
    
    init(name: String, version: Double, logo: UIImage) {
    	self.name= name
        self.version = version
        self.logo = logo
    }
}

2) 필수 메소드 작성

  • encode: 파라미터로 전달되는 coder 객체로 encode 하는 코드 구현
  • 생성자: decode 코드 구현
class Language: NSObject, NSCoding {
	let name: String
    let version: Double
    let logo: UIImage
    //필수 메소드
    func encode(with coder: NSCoder) {
    	coder.encode(name, forKey: "name")
        coder.encode(version, forKey: "version")
        coder.encode(logo, forKey: "logo")
    }
    //필수 메소드
    required init?(coder: NSCoder) {
    	guard let nameValue = coder.decodeObject(forKey: "name") as? String else { return nil }
        name = nameValue
        
        version = coder.decodeDouble(forKey: "version")
        
        guard let img = coder.decodeObject(forKey: "logo") as? UIImage else { return nil }
        logo = img
    }
    
    init(name: String, version: Double, logo: UIImage) {
    	self.name= name
        self.version = version
        self.logo = logo
    }
}

3) 해당 모델을 저장, 사용하는 클래스에서 encode, decode 사용
NSKeyedArchiverNSKeyedUnarchiver사용

  • Archiver로 전달하는 오브젝트는 반드시 NSObject 를 상속해야 한다.
  • 또한 NSCoding을 구현해야 한다. 그렇지 않으면 크래시 발생
  • 따라서 구조체를 저장하는건 불가능하다.
class ViewController: UIViewController {
	...
    func encodeObject() {
    	do {
        	guard let img = UIImage(named: "swift") else { return }
        	
            let obj = Language(name: "Swift", version: 5.9, logo: img)
            //바이너리데이터 리턴
            let data = try NSKeyedArchiver.archivedData(withRootObject:obj, requiringSecureCoding: false)
            
            try data.write(to: fileUrl, options: .atomic)
        } catch {
        	print(error)
        }
    }
    
    func decodeObject() {
    	do {
        	let data = try Data(contentsOf: fileUrl)
            //객체로 decode
            if let language = NSKeyedUnarchiver.unarchivedObject(with: data) as? Language {
            	logoImageView.image = language.logo
                nameLabel.text = language.name
                versionLable.text = "\(language.version)"
            }
        } catch {
        	print(error)
        }
    }
}
  • 그러나 해당 방법은 안전하지 않음(nil 리턴이나 크래시 발생 가능성, 취약점 공격 등)
  • 이를 위해 Secure Coding 필요
profile
iOS 개발자가 되기 위한 스터디룸...

0개의 댓글