Archive

IOS/Objective-C 2015. 8. 20. 19:48

객체 직렬화와 아카이브의 차이
: 코코아 프레임워크에서 직렬화(serialization)는 아카이브와 마찬가지로 객체 그래프를 따라 객체의 데이터 내용을 저장하는 방식이다. 다만, 아카이브와 달리 직렬화는 주로 문자열, 배열이나 사전 컬렉션에 담겨 있는 계층 구조와 참조하는 객체 데이터만 직접적으로 저장하며, 참조 관계에는 관심이 없고 데이터에만 관심이 있다. 예를 들어, 여러 곳에서 하나의 객체를 다중 참조하고 있으면 참조마다 동일한 내용을 각기 저장한다. 그러므로 deserialization 할 때에도, 동일한 객체를 다중 참조하는 것이 아니라 각기 다른 객체가 만들어진다는 것이다. 그리고 데이터에만 관심이 있기 때문에 해당 객체가 가변 객체였는지 불변 객체였는지 판단해서 복원할 수 없다.
객체 직렬화와 직접적으로 관련이 있는 클래스는 NSPropertyListSerialization이 있다. 이 클래스는 Foundation 객체 중에서 NSDictionary, NSArray, NSString, NSDate, NSData, NSNumber 타입으로 저장되어 있는 데이터 구조만 XML 기반 plist 파일로 직렬화 해서 저장한다. 
NSUserDefaults 클래스도 내부적으로 NSPropertyListSerialization을 사용해서 직렬화를 지원한다.

직렬화(Serialization)는 다중 참조 관계나 가변객체 여부등을 복원하지 못하고 저장할 수 있는 클래스 종류도 한정적이다. 이러한 제약 사항을 지원해야 하는 경우라면 <NSCopying> 프로토콜을 사용해야 한다. 

<NSCoding> 프로토콜

- 객체를 Archive, UnArchive하기 위해서는 NSKeyArchiver, NSKeyUnarchiver가 필요.
- Archive 대상이 되는 객체는 NSCoding 프로토콜을 따르고 있어야 함.
- NSCoding 프로토콜 : encodeWithCoder, initWithCoder:

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    [super encodeWithCoder:aCoder];
    // 슈퍼 클래스가 NSCoder프로토콜을 따르지 않으면 불필요.
    [coder encodeObject:객체 forKey:키];
    [coder encodeDouble:실수 forKey:키];
    ....
}

먼저 슈퍼클래스가 NSCoding 프로토콜을 따르고 있으면 super의 encoderWithCoder를 호출해서 인코딩 후 자신을 인코딩함. 클래스가 독자적으로 가지고 있는 인스턴스 변수가 없고, 슈퍼클래스 에 encodeWithCoder:의 정의가 있는 경우라면 이 메소드 정의 자체가 필요 없음.
인코딩할때의 Key는 인스턴스 변수 각각에 다른 키를 지정해야 한다. 슈퍼 클래스에서 지정한 키를
서브 클래스에서 사용하면 안된다. 키는 같은 내부에서만 구별할 수 있으면 되기 때문에 다른 클래스
에서 같은키 사용 가능.
객체의 아카이브 메서드는 encodeObject:forKey:를 사용하는데, 이 함수는 첫 번째 인수인 객체에
대해 encodeWithCoder:를 호출해서 인코딩하므로, 이런 메소드는 재귀 호출한다. 객체 그래프에 순환 참조가 있는 경우, 같은 객체의 인코딩 요구가 여러 번 발생할 수 있지만 일단 아카이브한 객체를 중복해서 아키이브 하지 않음.

*encodeConditionalObject: (다른 곳에서 아카이브되어 있지 않으면 인코딩하지 않는 메서드)
- 아카이브 할때 인스턴스 변수 일부만 아카이브할 수가 있는데, 아카이브 하지 않은 인스턴스 변수를 객체 그래프의 순환참조가 있을경우 다른 곳에서 아카이브를 해버리면 복원하는 시점에 문제가 발생할 수 있다. 이때 사용하는 메서드.

- (id)initWithCoder:(NSCoder *)aCoder
{
    self = [super initWithCoder:aCoder];
    //슈퍼 클래스가 NSCoding 프로토콜을 따르지 않으면 [super init]만 하면 됨.
    
    변수 = [[coder decodeObjectForKey:키] retain];
    .....
    return self;
    
    // 인코딩도 디코딩과 같은 키를 지정하기만 하면, 디코딩하는 순서는 상관없고 복원하지 않는 변수가 있어도 상관 없음.
}

 


'IOS > Objective-C' 카테고리의 다른 글

메소드의 동적 결합  (0) 2015.08.22
Property List  (0) 2015.08.20
Copy  (0) 2015.08.18
Zone  (0) 2015.08.18
클래스 클러스터  (0) 2015.08.12
Posted by 홍성곤
,

Copy

IOS/Objective-C 2015. 8. 18. 12:04

copy, mutableCopy

NSObject에는  리시버를 복사하는 copy라는 메서드가 있다. 단, 실제 복사 처리를 하는것은 copy가 아니라 copyWithZone:이라는 인스턴스 메서드이다. 인스턴스 객체에 copy메세지를 보내면 인수로 NULL을 지정해서 자기 자신의 copyWithZone을 호출해서 Default Zone에 새로운 인스턴스를 만들 수 있다.

이러한 원리로, 인스턴스가 복사되도록 하기 위해서는 copy 메소드가 아닌 copyWithZone: 메소드를 정의해야 한다. 만약 복사가 실패했을 경우 copy, copyWithZone 둘 다 nil을 리턴한다.

copyWithZone:은 NSCopying 프로토콜 내에서 선언되어 있으므로 이 프로토콜을 적용해서 구현한다.


*인스턴스 객체를 바이트 배열로 간주하고 통째로 복사해서 다른 객체를 리턴하는 함수가 제공 됨.

 - id NSCopyObject(id anObject, NSUInteger extraBytes, NSZone *zone)

   - 인수의 anObject가 원본 객체이고 extraBytes는 보통 0을 지정함, 인수 zone에 NULL을 지정하면 default zone이 사용됨.

   -  문제점 : 원본 객체의 인스턴스 객체들까지 copy가 되지 않는다.(객체 내용의 바이트 배열을 복사하기만 하므로..) 즉, 원본객체와 복사객체 모두 해당 인스턴스 객체를 강한 참조하게 된다, 또한 MRC를 사용할 경우 해당 인스턴스 객체에 retain count가 자동 증가되지 않기 때문에 copy 후 retain을 해줘야 함. -> 즉, 단순히 값을 복사하기만 하면 되는 인스턴스가 많을 경우 유용.


- 불변객체에서 가변객체 복사를 생성하려면 mutableCopy메서드가 위에 copy메서드와 대응되고,    mutablecopyWithZone:이 copyWithZone:과 대응된다. 동작 메커니즘은 똑같다.


얕은복사 vs 깊은
복사
: 얕은복사는 메모리 주소를 복사한다는 것이다. 즉, 똑같은 인스턴스를 두개의 포인터가 가리키고 있게 된다.
깊은 복사는 새로운 메모리 공간을 할당해서 인스턴스의 값을 복사한다는 것이다. 서로 다른 공간의 메모리가 생기고 두개의 포인터는 각각의 메모리 공간을 가리키게 된다.

: NSArray와 같은 파운데이션 프레임워크에 있는 모든 클래스는 얕은 복사를 지원한다. 즉, NSArray에 copy메세지를 보내도 array가 포함하고 있는 각 객체들에게 copy 메세지를 보내서 복사하는게 아니라 메모리 주소만 복사한다.
깊은 복사를 하기 위해서는 array계열 클래스는 'initWithArray:copyItems:' 메서드가 있고, 다른 컬렉션 클래스에도 비슷하게 'copyItems:' 으로 끝나는 메서드가 존재한다. 해당 메서드를 호출할 때 copyItems 인자에 'YES'를 넘기면 각 컬렉션들이 포함하고 있는 객체에 copy메세지를 보내 복사하게 된다. 단 각 객체가 <NSCopying> 프로토콜을 conform 하지 않으면 런타임 에러가 발생한다. 


'IOS > Objective-C' 카테고리의 다른 글

Property List  (0) 2015.08.20
Archive  (0) 2015.08.20
Zone  (0) 2015.08.18
클래스 클러스터  (0) 2015.08.12
BOOL  (0) 2015.08.12
Posted by 홍성곤
,

Zone

IOS/Objective-C 2015. 8. 18. 10:55

Cocoa에서는 동적으로 확보되는 메모리를 관리하기 위해 zone이라는 영역을 사용한다.

동적으로 메모리를 할당하고 해제하는 작업을 반복할 경우 서로 관계가 있는 내용의 데이터가 메모리 상에서는 멀리 떨어진 곳에 흩어질 가능성이 있다. 그래서 메모리 공간에 여러 개의 힙을 만들어 서로 밀접한 관계에 있는 데이터나 객체는 특정 힙 내에서 메모리가 할당되도록 한다. 

이렇게 메모리 상에 만들 수 있는 힙 영역을 Zone이라 부른다.

Zone은 각각 메모리 관리 기능이 있고, 필요에 따라 그 크기가 증가한다. 프로그램이 실행된 직후부터 존재하는 Zone을 Default Zone이라 한다. 그리고 따로 지정하지 않을 경우 인스턴스 객체는 Default Zone에 만들어 진다.

*가비지 컬렉션을 사용하는 경우 Zone 사용 불가.

'IOS > Objective-C' 카테고리의 다른 글

Property List  (0) 2015.08.20
Archive  (0) 2015.08.20
Copy  (0) 2015.08.18
클래스 클러스터  (0) 2015.08.12
BOOL  (0) 2015.08.12
Posted by 홍성곤
,