'IOS/Objective-C'에 해당되는 글 21건

  1. 2016.12.07 Key-Value Coding(1)
  2. 2016.10.02 Collections의 weak reference
  3. 2016.02.18 NSString과 NSMutableString의 copy
  4. 2015.08.23 멀티 스레드 프로그램
  5. 2015.08.22 메소드의 동적 결합
  6. 2015.08.20 Property List
  7. 2015.08.20 Archive
  8. 2015.08.18 Copy
  9. 2015.08.18 Zone
  10. 2015.08.12 클래스 클러스터

- 애플 문서에서 KVO를 객체의 accessor methods를 통한 접근보다 더 flexiblie하고 general mechanism을 제공한다고 설명한다.

 

Introduction

Using Key-Value Coding Compliant Objects

1. Access object properties

2. Manipulate collection properties

3. Invoke Collection operators on collection objects

4. Access non-object properties

 

Other Cocoa Tchnologies Rely on Key-Value Coding

1. Key-value objserving

2. Cocoa bindings

3. Core Data

4. AppleScript

 

1. Accessing Object Properties

Listing 1-1)
@inetrface BankAccount : NSObject

@property (nonatomic) NSNumber *currentBalance;
@property (nonatomic) Person *owner;
@property (nonatomic) NSArray<Transaction *>* transactions;

@end

KVO를 통해 [myAccount setValue:@(100.0) forKey:@"currentBalance"]; 로 properties에 접근할 수 있다.
또한, keyPath string( ex. @"owner.address" )을 통해 property의 property를 참조할 수 있다. 즉, keyPath string을 통해 객체 맨 하단 hierarchy까지 접근하여 해당 property들을 참조할 수 있는것이다. 

 

Getting Attribute Values Using Keys

- valueForKey:
: 키에 대한 해당 값을 가져옴. 값이 존재하지 않으면 valueForUndefinedKey: 메서드가 불리게 되고 NSObject default로 구현된 동작은 NSUndefinedKeyException을 발생시키는 것이다. 값이 존재하지 않을때의 동작을 Custom하게 구현하려면 해당 메서드를 오버라이드 하면된다.

- valueForKeyPath:
: keyPath에 대한 값을 가져옴. 값이 존재하지 않을경우의 동작은 valueForKey: 같다.

- dictionaryWithValuesForKeys:
: Key들에대한 Value들의 array를 return한다.

* Listing  1-1)에서 property "transactions"이 payee라는 객체들을 포함하고 있다면, keyPath로 "transactions.payee"를 전달하면 transactions에 포함되있는 모든 payee객체들이 array로 return된다. 또한, accounts가 BankAccount의 array property라면 keyPath "accounts.transactions.payee"를 전달하면 accounts안에 모든 transaction의 모든 payee를 array로 return한다. 

 

2. AccessingCollection Properties

Collection properties에 대해서 KVC를 쓸때 해당 데이터를 immutable하게 다루는 것보다 mutable하게 다루는 것이 사용하는데 있어서 편리할때가 많다.
해서, KVC는 NSMutableArray, NSMutableSet, NSMutableOrderedSet을 return하는 메서드를 제공한다. 해당 메서드를 사용해서 adding, removing, replacing동작을 할 경우 해당 데이터를 reference하고 있는 객체에서도 동일하게 작업이 반영된다.

- NSMutableArray: mutableArrayValueForKey:, mutableArrayValueForKeyPath:
- NSMutableSet: mutableSetValueForKey:, mutableSetValueForKeyPath:
- NSMutableOrderedSet: mutableOrderedSetValueForKey, mutableOrderedSetValueForKeyPath:

 

3. Using Collection Operators

valueForKeyPath: 메서드를 호출할 때, keyPath안에 Collection Operator를 넣을 수 있다.

* Operator key path format
"keypathToCollection.@collectionOperator.keyPathToProperty"

Listing 3-1) Linsting 1-1)의 BankAccount.transactions에 포함되는 Tranaction객체.

@interface Transaction : NSObject

@property (nonatomic) NSString *payee;
@property (nonatomic) NSNumber* amount;
@property (nonatomic) NSDate* date

@end 


Aggregation Operators

@avg
: 각 값을 double형으로 변환해서 더한다음 평균값을 구해서 return. 각 값에 대해서 nil인 경우 0으로 변환해서 계산.

NSNumber *transactionAverage = [[self transactions] valueForKeyPath:@"@avg.amount"];

@count
: 객체의 갯수 값 return, right keypath 필요없음. 있으면 무시한다.

NSNumber *numberOfTransactions = [[self transactions] valueForKeyPath:@"@count"];

@max
: 값 중 제일 큰 값을 return. 값 비교는 "compare:" 메서드를 통해 수행함. 고로, right keyPath가 가리키는 property는 "compare:" 메시지에 응답할 수 있는 객체여야 한다.

@min
: 제일 작은 값 return. 동작방식은 @max랑 동일.

@sum
: 값들의 합을 반환. 각 값을 double형으로 반환한 후 계산. 각 값에 대해서 nil인 경우 0으로 변환해서 계산.

NSNumber *amountSum = [[self transactions] valueForKeyPath:@"@sum.amount"];

 

Array Operators
: valueForKeyPath: 메서드에서 Array Operators를 사용할때, leaf Object들 중 하나라도 nil인 경우 exception을 발생시킴.

@distinctUnionOfObjects
: 합집합, 중복제거

NSArray *distinctPayees = [[self transactions] valueForKeyPath:@"@distinctUnionOfObjects.payee"];

@unionOfObjects
: 합집합

NSArray *payees = [[self transactions] valueForKeyPath:@"@unionOfObjects.payee"];


Nesting Operators
: nesting collecction들에 대해서 동작하는 operators이다.
: valueForKeyPath: 메서드에서 Nesting Operators를 사용할 때, leaf Object들 중 하나라도 nil인 경우 exception을 발생시킴.

Listing 3-2)
NSArray *moreTransactions = @[ /* transaction data */ ];
NSArray *arrayOfArrays = @[ [self transactions], moreTransactions ];

@distinctUnionOfArrays
: 합집합, 중복제거

NSArray *collectedDistinctPayees = [arrayOfArrays valueForKeyPath:@"@distinctUnionArrays.payee"];

@unionOfArrays
: 합집합

NSArray *collectedPayees = [arrayOfArrays valueForKeyPath:@"@unionOfArrays.payee"];

@distinctUnionOfSets
: distinctUnionOfArrays의 NSSet버전.
: 중복 NSSet에 대해서 동작함.

 

4. Representing Non-Object Values

KVO의 getter를 통해 얻어오려는 값이 non-object인 경우 NSNumber(for scalars) 또는 NSValue(for structures - CGPoint, NSRange, CGRect, CGSize)로 변환해서 return한다.
비슷한 논리로 setter로 세팅하려는 property가 non-object인 경우, 넘어오는 파라미터에 "<type>Value" 메서드를 호출해서 property에 맞는 타입의 값을 세팅한다.

non-object의 property에 KVO setter값에 nil을 넣으면 setNilValueForKey: 메서드가 불린다. 이 메서드의 default동작은 NSInvalidArgumentException을 발생시킨다. Custom처리를 하려면 해당 메서드를 오버라이드 해야 한다.

Wrapping and Unwrapping Structures

CGPoint, NSRange, CGRect, CGSize이외에 사용자가 정의한 Structure도 가능하다.

Listing 4-1) A sample class using a custom structure

typedef struct
{
   float x, y, z;
} ThreeFloats

@interface MyClass
@property (nonatomic) ThreeFloats threeFloats;
@end

-> wrapping, unwrapping

NSValue *result = [myClass valueForKey:@"threeFloats"];
// NSValue로 자동 wrapping 된다.

ThreeFloats floats = { 1.0, 2.0, 3.0 };
NSValue *value = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
[myClass setValue:value forKey:@"threeFloats"];
// 해당 property로 setting될때는 NSValue의 getValue: 메서드를 이용해 자동 unwrapping되서 저장된다.


5.Validating Properties

- 참조: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/ValidatingProperties.html#//apple_ref/doc/uid/10000107i-CH18-SW1


6. Accessor Search Patterns

- 참조: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueCoding/SearchImplementation.html#//apple_ref/doc/uid/20000955-CJBBBFFA




 

* Performance?
: 애플은 KVC가 indirect level에서의 접근이기 때문에 direct method invocation(직접 method call)보다 flexiblity를 제공하지만 속도측면에서는 약간 느리다고 밝히고 있다. 그래서 KVC가 제공하는 이득을 볼 수 있을때만 사용하라고 권장하고 있다. 하지만 둘간에 performance차이는 아주 경미한 수준이라 performance에 민감한 프로그램이 아니라면 무시해도 괜찮을 것 같다.

Posted by 홍성곤
,


Objective-C에서 일부 Collection을 제외하고 대부분의 Collection이 객체를 strong reference한다.

하지만 특수한 경우에 weak reference하고 있는 Collection들이 필요하기 때문에 몇개의 weak reference를 할 수 있는 collection들이 존재한다. 해당 Collection들은 당연히 Mutable이다.

1. NSPointerArray

- 대응 Collection : NSArray, NSMutableArray

2. NSHashTable

- 대응 Collection : NSSet, NSMutableSet

3. NSMapTable

- 대응 Collection : NSDictionary, NSMutableDictionary


* 이들 Collectinon들은 강한 참조와 약한 참조를 선택 지정할 수 있을 뿐 아니라, 복사를 할것인지, 참조하는 대상이 객체인지 C언어의 문자열이나 구조체인지도 지정할 수 있다. 그리고 메모리를 확보하고 해제하는데 사용되는 함수를 지정하는 것도 가능하다.


Posted by 홍성곤
,

1.NSMutableString의 copy

결과가 어떻게 될까?

예상한대로 두 문자열의 메모리 주소는 다르다. copy했기 때문에 stringA 문자열의 복사본을 다른 메모리 주소에 만들고 그 주소를 stringB에 대입했기 때문이다.


2. NSString의 copy

결과가 어떻게 될까?

예상과 다르게 두 문자열의 메모리 주소는 같다. retain 한것과 결과가 똑같을 것이다. @"aa"의 retainCount도 2가 되었을것이다. 왜일까? 

NSString은 불변객체이기 때문에 @"aa" 라는 문자열 상수가 변경될 일이 없다. 그래서 굳이 복사본을 따로 만들어서 메모리를 낭비시키지 않고 retain과 똑같이 동작하도록 구현한 것이다.


*이해를 돕기 위해서 NSString과 NSMutableString을 예로 든것이다. 불변, 가변객체 구조를 가지고 있는 NSArray, NSMutableArray, NSDictionary, NSMutableDictionary 등도 위와 같은 메커니즘으로 동작한다.

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

Key-Value Coding(1)  (0) 2016.12.07
Collections의 weak reference  (0) 2016.10.02
멀티 스레드 프로그램  (0) 2015.08.23
메소드의 동적 결합  (0) 2015.08.22
Property List  (0) 2015.08.20
Posted by 홍성곤
,

- 카운터 관리 방식을 사용할 경우, 자식 스레드 쪽에서는 객체가 누수되는 것을 막기 위해 부모 스레드와는 다른 자동 해제 풀을 만들어 관리할 필요가 있다.

- 스레드 세이프
    -- 여러 개의 스레드가 하나의 인스턴스를 조작할 때 오작동하지 않을 경우, 그 클래스는 스레드 세이프 하다고 말한다. 일반적으로 불변 객체는 스레드 세이프하고 가변 객체는 스레드 세이프 하지 않다. 즉, 가변 객체를 공유하기 위해서는 상호 배제나 동기화를 적절히 사용해야 한다.

- 스레드 생성                                                                                                                               
    -- NSThread                                                                                                                                       + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument                                                                                                                          
    -- 객체 aTarget에 대한 메소드 호출을 새로운 스레드를 만들어 실행한다. aSelector는 id 타입의 인수를 하나만 사용해서 void를 리턴하는 액션 메소드여야만 한다. 카운터 관리 방식을 사용할 경우 실행되는 메소드 자체가 자동 해제풀을 관리할 필요가 있다. 인수 aTarget과 anArgument에 지정된 객체는 스레드를 만드는 것과 동시에 retain되어 스레드가 종료될때 release된다.

   -- NSApplication                                                                                                             
      --- + (void)detachDrawingThread:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
         ---- 위에 NSTherad의 스레드 생성 메서드를 사용하는데, 카운터 관리 방식일 경우 스레드를 위한자동 해제 풀을 만든다.
      --- + (BOOL)isMultiThreaded                                                                                                
          ---- 여러 개의 스레드가 병행으로 동작하고 있거나 그 시점에서 메인 스레드 밖에 없더라도 이제까지 스레드가 생성된 적이 있다면 YES를 리턴.

- 상호 배제
    -- 여러 개의 스레드 사이에서 전역 변수와 같은 공유 자원의 상호 배제를 하기 위해 NSLock 클래스를사용.
    -- Lock은 프로그램이 멀티 스레드로 동작하기 전에 만들어져야 함.
        --- 어떤 락에 대해 lock이 실행 되면 그 후 반드시 unlock을 1회만 실행해야 한다. lock을 한 후 unlock을 사용하는 것은 같은 스레드에서 해야함.                                                                          
    -- (void)Lock
        --- P조작: 락이 사용 중이라면 스레드는 휴면상태에 들어감. 사용중이 아니라면 락을 사용 중으로 바꾸고 실행을 계속함
    -- (void)unLock
        --- V조작: 사용 중이던 락을 해제, 그 락을 획득하기 위해 휴면 상태에 있는 스레드가 있다면 그 스레드가 해제된 락을 획득
                                                                                                       
    -- (BOOL)tryLock
        --- 리시버인 락 획득을 시도하고 획득을 성공한 경우 YES를 리턴함, 실패한 경우 휴면 상태에 들어가지 않고 NO를 리턴한 후, 실행을 계속함.

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

Collections의 weak reference  (0) 2016.10.02
NSString과 NSMutableString의 copy  (0) 2016.02.18
메소드의 동적 결합  (0) 2015.08.22
Property List  (0) 2015.08.20
Archive  (0) 2015.08.20
Posted by 홍성곤
,

- Objective-C에서는 런타임 시스템의 기능을 사용해서 클래스의 일부 메소드를 런타임에 추가하거나 교체하는 것이 가능함. 

- 단 지나치게 남용하면 유지보수하기 어려움. 

- 최후의 수단으로 사용할 것을 권함.


- @dymamic을 지정한 프로퍼티는 이에 대응하는 접근자 메소드를 클래스에서 정의할수도 있지만, 정의하지 않아도 런타임에 함수를 동적으로 결합하는 것이 가능함.

- Objective-C의 메소드는 IMP 타입으로 표현되는 C함수이다. 첫번째 인수가 self(id타입), 두번째 인수가 SEL이 되어야 함.

- BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);

    - cls는 바인딩시키코 싶은 클래스이고, name은 메소드의 셀렉터, imp는 함수의 포인터, types는 함수의 타입 정보를 나열한 것이다. 바인딩에 성공한 경우 YES를 리턴.

- 실제 바인딩 하기

    - -(void)setList:(NSArray *)obj ----> void set_list(id, SEL, NSArray *)(프로토 타입) 

    - class_addMethod(self, @selector(setList:). (IMP)set_list, "v@:@"); 로 함수 바인딩(클래스 메소드 안에서 호출할 경우 첫번쨰 인수에 self를 집어넣으면 됨)


* @encode() 

 - Objective-C는 객체를 동적으로 다루는 일이 많아 데이터를 보존하거나 통신을 할 때, 그 데이터가 실제로 어떤 데이터 타입이라는 정보를 알려줘야 하는 경우가 있다.  

 - Objective-C는 데이터 타입을 표현하기 위해 C문자열(const char*)의 타입 코드를 사용하지만, 타입에서 문자열을 쉽게 얻을 수 있도록 @encode()라는 컴파일러 지시자가 제공됨.

 - @encode()는 인수로 타입명을 받아 컴파일할 떄 대응하는 타입으로 교체를 한다. 예를 들어 @encode(int)는 'i'가 되고, @encode(NSSize)는 '{_NSSize=ff}'가 된다.

 - 주요타입의 표

 코드

데이터 타입 

 c 

 char

 s

 short

 i

 int 

 l

 long 

 q

long long 

 f

 float 

 d

 double 

 C

 unsigned char 

 S

 unsigned short 

 I

 unsigned int 

 L

 unsigned long

 Q

 unsigned long long 

 V

 void 

 *

 C문자열(char *) 

 @

 객체 

 #

 킄래스 객체 

 :

 셀렉터 

 [타입]

 배열 

 {이름=타입...}

 구조체 

 ^타입

 타입의 포인터 

 ?

 정해지지 않은 타입이나 요소 


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

NSString과 NSMutableString의 copy  (0) 2016.02.18
멀티 스레드 프로그램  (0) 2015.08.23
Property List  (0) 2015.08.20
Archive  (0) 2015.08.20
Copy  (0) 2015.08.18
Posted by 홍성곤
,

Property List

IOS/Objective-C 2015. 8. 20. 21:06

Cocoa 환경에서 여러 정보를 표현하고, 보존하기 위해 사용하는 표준적인 데이터 형식.

- ASCII, XML, 바이너리 형식의 세 종류 형식을 사용할 수 있음.

   - ASCII : NSString, NSData, NSArray, NSDictionary 표현 가능.

   - XML : 위의 네가지 + NSNumber, NSDate

   - 바이너리 : 위와 같은 형식을 텍스트가 아닌 바이너리 파일로 보존함.


- ASCII 형식의 Property List에서는 NSArray, NSDitionary의 인스턴스에 대해 description 메서드를 사용해서 문자열 형식으로 값을 얻을 수 있고, 이를 다시 객체의 구조로 복원하기 위해서 propertyList메서드를 사용해서 복원할 수 있다.

- XML 형식의 Property List에서는 NSArray, NSDictionary에 대해 writeToFile:atomically:를 사용해서 XML 형식의 프로퍼티 리스트를 파일에 쓸 수 있다. 파일에서 다시 객체로 복원하려면 initWithContentsOfFile을 사용해서 복원.

- 클래스 타입과 프로퍼티 리스트의 문자열 표현

  클래스

 XML 형식의 태그  

 ASCII 형식의 데이터 표현 

 NSString 

 <string> 

 "문자열" 

 NSNumber 

 <integer>, <real>, <true/>, <false/> 

  없음 

 NSData

 <data> 

 <16진수> 

 NSDate 

 <date> 

  없음 

 NSArray 

 <array> 

 (요소, 요소, ...) 

 NSDictionary 

 <dict> 

 {키 = 값; 키 = 값} 


- 프로퍼티 리스트의 변환과 검증

세 종류의 프로퍼티 리스트를 서로 변환하거나 형식을 검증하기 위한 클래스 NSPropertyListSerialization이 제공됨. 프로퍼티 리스트를 복원해서 얻는 객체의 구조를 가변 객체로 구성하는 것도 가능.

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

멀티 스레드 프로그램  (0) 2015.08.23
메소드의 동적 결합  (0) 2015.08.22
Archive  (0) 2015.08.20
Copy  (0) 2015.08.18
Zone  (0) 2015.08.18
Posted by 홍성곤
,

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 홍성곤
,

- Objective-C 에서는 클래스 클러스터를 만들기 위한 언어 자체의 매커니즘은 없다. 하지만 일반적으로, 공개클래스는 추상 클래스로, 구체적인 클래스는 공개 클래스의 비공개 서브 클래스로 구현되어 있음.

- Cocoa에서 많은 클래스가 실제로는 클래스 클러스터로 구현되어 있다. 대표적으로 NSData, NSDate, NSArray, NSDictionary, NSSet, NSString, NSNumber, NSValue 등이 있다. 이들 클래스는 일반적인 방법으로 서브 클래싱을 할 수가 없다.


- 클래스 클러스터 인스턴스의 소속을 확인할 경우.

   - 클래스 클러스터에서 각 인스턴스는 비공개 서브 클래스의 인스턴스이다. 따라서 공개 클래스를 인수로 한 메소드 isMemberOfClass:를 사용해도 어떤 결과가 나올지 알 수 없다. 인스턴스가 속하는 클래스를 확인하기 위해서는 isKindOfClass:나 respondsToSelector:로 확인하는것이 바람직하다.

- 서브 클래스를 만드는 경우 밑에 두가지 방법이 있다. 

1) True Subclass

1. 비공개 데이터 구조를 결정한다.

- 인스턴스 변수로 가질 데이터 구조를 결정한다. 슈퍼 클래스인 클래스 클러스터가 가지는 데이터 구조는 절대 사용하면 안됨.

2. 이니셜라이저를 정의한다.

- init 이외의 슈퍼클래스의 이니셜라이저를 상속받아 사용하면 안됨. 비공개 데이터 구조가 없다면 init을 사용하면 되므로 이니셜라이저의 정의는 필요 없음.

3. 컨비니언스 컨스트럭터를 정의한다. 

- 필요할 경우, 데이터 타입명으로 시작하는 임시 객체를 생성하는 클래스 메소드를 정의합니다. 슈퍼 클래스의 같은 메소드를 상속받아 사용하면 안됩니다.

4. 원시(primitive) 메소드를 정의한다.
- 원시 메소드는 각 클래스 클러스터의 레퍼런스 문서에 나와있다.

5. 그외의 메소드를 정의한다.

- 원시 메소드를 정의하면 공개 클래스에서 선언된 메소드가 일단 동작은 한다. 다만 그 데이터 구조의 특징을 살리기 위해 메소드를 오버라이드 해서 사용할 수 있다.

2) Composite Object

Composite Object의 경우 역시 abstract superclass를 상속 받은 후 데이터 모델을 직접 설계하지 않고 기존의 private cluster object를 맴버로 가지고 그것을 그대로 사용하는 방식입니다.

문제는 실제 데이터가 모두 맴버 변수에 저장되어있기 때문에 primitive methods들을 모두 구현하되 내부에 가지고 있는 private cluster object와 연결 해주어야 합니다.


뭐, 자주 쓰일 일은 없을 것 같지만 일단 두가지 방법으로 서브클래싱이 가능하기 때문에 특정 동작을 위한 컬랙션 같은 것을 구성할 때 편하게 사용할 수 있을듯 합니다.


그럼 어떤 때 이런 Class Cluster에 대한 subclassing이 필요할까요?

먼저 생각이 떠오른 것은,


True subclass의 경우 NSValue가 지원하지 않는형태의 value를 사용해야 한다던지.. (물론 valueWithBytes:objCType: 같은 것으로 해결 할 수도 있을것 같습니다.) file 같은 것에 매핑된 거대한 array같은 것을 사용한다던지, 심지어 서버와 통신하면서 동작하는 NSArray를 구현한다던지(아.. 너무 오버인것 같기도 합니다. 큰 데이터에 sorting 같은 걸 하면 안드로메다 가겠습니다.) 등등 응용분야는 많을듯 합니다.


Composite object의 경우 기존의 collection에 validation처리를 한다던지, logging을 한다던지, 데이터 처리 자체를 변경하지 않는 범위에서 무엇인가 추가작업을 간결하게 하고자 하면 유용할듯 합니다.


  *출처 -  http://maccrazy.tistory.com/102

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

Property List  (0) 2015.08.20
Archive  (0) 2015.08.20
Copy  (0) 2015.08.18
Zone  (0) 2015.08.18
BOOL  (0) 2015.08.12
Posted by 홍성곤
,