본문 바로가기
프로그래밍 놀이터/iOS

[Objective-C] Foundation 프레임워크의 중요 클래스 - NSData, NSArray, NSSet

by 돼지왕 왕돼지 2017. 12. 31.
반응형

 [Objective-C] Foundation 프레임워크의 중요 클래스 - NSData, NSArray


addObject, addObjectsFromArray, allobjects, alloc, appendBytes, appendData, arc, array, arrayByAddingObject, arrayByAddingObjectsFromArray, arrayWithObject, autorelease, Bag, bytes, componentsJoinedByString, containsobject, Count, counted set, data, description, exchangeObjectAtIndex, fast enumeration, fast iteration, firstObjectCommonWithArray, For, for in, getBytes, getObjects, idiom, increaseLengthBy, indexOfObject, initWithArray, initWithBytes, initWithBytesNoCopy, initWithCapacity, initWithContentsOfFile, initWithData, initWithLength, initWithObjects, insertObject, intersetcSet, isEqualToData, isEqualToSet, isEuqlaToArray, isSubsetOfSet, lastObject, length, makeObjectsPerformSelector, MRC, mutableBytes, nextobject, NSArray, nscountedset, NSData, nsenumerator, NSFastEnumerator, NSMutableArray, NSMutableData, NSMutableSet, objectAtIndex, objectEnumerator, pathsMatchingExtensions, rangeOfData, release, removeAllObjects, removeLastObject, removeObject, removeObjectAtIndex, removeObjectsInArray, removeObjectsInRange, replaceBytesInRange, replaceObjectAtIndex, replaceObjectsInRange, resetBytesInRange, retain, reverseobjectenumerator, Set, setArray, setData, setLength, sortedArrayUsingFunction, sortedArrayUsingSelector, sortUsingSelector, subarrayWithRange, subdataWithRange, unionSet, Wrapper, writeToFile, [Objective-C] Foundation 프레임워크의 중요 클래스 - NSData, 객체 삭제, 고속 열거, 고속 열거자와 열거자, 내용물 변경 예외, 데이터 객체 초기화 생성, 데이터 객체 초기화 작성, 데이터 변경, 데이터 추가, 데이터 클래스, 데이터에 접근, 메모리 관리, 바이트 배열, 바이트 배열 길이 변경, 반복문 중첩, 배열 객체 초기화, 배열 객체와 소유권, 배열 클래스, 배열에 접근, 배열에 추가, 백, 변수형, 비교, 사전, 새로운 요소 추가, 수동 카운터 관리 방식, 열거자, 요소 메시지 송신, 작성, 정렬, 집합 클래스, 출력, 치환, 카운터 관리 방식, 카운터 포함 집합, 클래스 클러스터, 파일 입, 파일 입출력


9.3. 데이터 클래스


* 9.3.1. NSData


-

NSData 는 임의의 바이트 배열을 객체로 다루기 위한 랩퍼(wrapper) 이다.



-

일반적인 C 배열을 사용할 때와 비교했을 때의 장점은 객체로 추상화해서 다룰 수 있는 점,

메모리 관리가 쉬운 점, Cocoa API 에서 바이트 배열을 다루는 표준이라는 점.



-

NSData 인터페이스는 한 번 작성되면 데이터 내용을 변경할 수 없다.

데이터 내용을 나중에 변경하려면 NSMutableData 클래스를 사용해야 한다.



-

NSData 는 클래스 클래스터로 제공되므로 NSData 가 인스턴스의 직접 클래스가 아니라는 점, 일반 방법으로는 서브 클래스를 작성할 수 없다는 점에 주의해야 한다.



** 데이터 객체 초기화 작성


-

- (id) initWithBytes: (const void*) bytes length: (NSUinteger) length

     bytes 로 지정한 위치에서 시작하는 길이가 length 인 데이터를 복사해서 데이터 객체 내용으로 초기화한다.

     편의 생성자 : dataWithBytes:length:


- (id) initWithBytesNoCopy: (void*) bytes length: (unsigned) length freeWhenDoen: (BOOL) flag

     복사본은 만들지 않는다.

     flag 가 YES 이면 생성한 데이터 객체가 bytes 의 소유권을 가지고, 객체가 해제될 때 동시에 해제된다.

     flag 가 NO 이면 bytes 는 자동으로 해제되지 않지만 데이터 객체가 있는 한 해제하면 안 된다.

     편의 생성자 : dataWithBytesNoCopy:length:freeWhenDone:


- (id) initWithData: (NSData*) aData

     편의 생성자 : dataWithData:


+ (id) data

     데이터 길이가 0인 빈 데이터를 임시 객체로 반환한다.

     NSMutableData 에서 사용할 때가 많으며 대응하는 초기자는 init 이다.



** 데이터에 접근


-

- (NSUInteger) length


- (const void *) bytes

     바이트 배열의 첫 위치 포인터를 return


- (void) getBytes: (void*) buffer length: (NSUInteger) length

     buffer 가 가리키는 버퍼에 복사한다.

     지정한 범위의 데이터를 얻으려면 메서드 getBytes:range: 를 사용한다.


- (NSData*) subdataWithRange: (NSRange) range


- (NSRange) rangeOfData: (NSData*) dataToFind options: (NSDataSearchOptions) mask range: (NSRange) searchRange



** 비교


-

- (BOOL) isEqualToData: (id) anObject



** 파일 입,출력


-

- (NSString*) description


- (id) initWithContentsOfFile: (NSString*) path options: (NSUInteger) mask error: (NSError**) error

     편의생성자 : dataWithContentsOfFile:options:error:


- (id) initWithContentsOfFile: (NSString*) path

     편의생성자 : dataWithContentsOfFile:


- (BOOL) writeToFile: (NSString*) path atomically: (BOOL) flag




* 9.3.2. NSMutableData


** 데이터 객체 초기화 생성


-

- (id) initWithCapacity: (NSUInteger) capacity

     리시버를 바이트 길이 0으로 초기화

     편의생성자 : dataWithCapacity:


- (id) initWithLength: (NSUInteger) capacity

     인수에서 지정한 길이만큼 바이트 배열을 가지도록 리시버를 초기화한다.

     바이트 배열은 0으로 채운다.

     편의 생성자 : dataWithLength:



** 데이터에 접근


-

- (void*) mutableBytes

     리시버에 저장된 바이트 배열의 첫 부분 포인터를 돌려준다.

     포인터가 가리키는 위치에 쓸 수 있다는 점이 NSData 의 bytes 메서드와 다르다.



** 데이터 추가


-

- (void) appendData: (NSData*) otherData


- (void) appendBytes: (const void*)bytes length: (NSUInteger)length



** 데이터 변경


-

- (void) replaceBytesInRange: (NSRange) range withBytes: (const void*) replacementBytes length: (NSUInteger) replacementLength


- (void) replaceBytesInRange: (NSRange) range withBytes: (const void*) bytes


- (void) setData:(NSData*) aData

     리시버 내용 모두를 인수로 지정한 데이터 객체 내용으로 바꾼다.


- (void) resetBytesInRange: (NSRange) range

     리시버의 바이트 배열 중 range 로 지정한 범위를 0 으로 채운다.



** 바이트 배열 길이 변경


-

- (void) increaseLengthBy: (NSUInteger) extraLength

     리시버 바이트 배열 길이를 인수에서 지정한 만큼 늘린다.

     추가된 배열은 0으로 채워진다.


- (void) setLength: (NSUInteger) length

     리시버 바이트 배열이 인수에서 지정한 길이가 되도록 배로 늘리거나 잘라낸다.

     배로 늘릴 때 추가된 바이트 배열은 0으로 채운다.




9.4. 배열 클래스

* 9.4.1. NSArray


-

카운터 관리 방식을 이용할 때 배열 객체는 저장된 객체에 retain 메서드를 보내어 유지한다.

객체가 해제될 떼에는 저장된 객체 모두에 release 메시지를 보낸다.



-

NSArray 는 클래스 클러스터로 제공되므로 NSArray 가 인스턴스 직접 클래스가 아니라는 점과 일반적인 방법으로는 서브 클래스를 만들 수 없다는 점에 주의해야 한다.



** 배열 객체 초기화, 작성


-

+ (id) array


+ (id) arrayWithObject: (id) anObject


- (id) initWithObjects: (id) firstObj, ...

     인수 목록 끝은 nil 을 붙여주어야 한다.

     편의 생성자 : arrayWithObjects:


- (id) initWithObjects: (const id*) objects count: (NSUInteger) count

     인수 objects 는 C 언어 배열. 배열의 앞부분부터 count 수만큼 객체를 저장하도록 배열객체를 초기화해서 돌려준다.

     편의 생성자 : arrayWithObjects:count:


- (id) initWithArray: (NSArray*) anArray

     편의 생성자 : arrayWithArray:


- (id) initWithArray: (NSArray*) array copyItems: (BOOL) flag

     flag 가 참이라면 배열의 각 요소를 복사해서 새로운 배열에 저장한다.



** 배열 객체에 접근


-

- (NSUInteger) count


- (NSUInteger) indexOfObject: (id) anObject

     포함되지 않았으면 NSNotFound

     포함되었는지 확인하려면 메서드 containsObject: 를 사용


- (id) objectAtIndex: (NSUInteger) index

     인덱스가 배열 크기를 벗어날 때는 예외 NSRangeException 이 발생


- (id) lastObject

     빈 배열이라면 nil


- (void) getObjects: (id __unsafe_unretained []) aBuffer range: (NSRange) aRange

     aRange 가 나타내는 범위에 든 객체를 aBuffer 로 지정한 C 언어 배열에 복사한다.

     객체 포인터가 복사될 뿐이므로 참조 카운터 값은 변하지 않는다.

     ARC 를 사용할 때 배열 안의 객체를 유지하려면 다른 강한 참조 변수에 대입해야 한다.

     aBuffer 는 지정한 개수가 들어갈 만큼 충분한 크기를 확보해야 한다.


- (NSArray*) subarrayWithRange: (NSRange) range



** 비교


-

- (BOOL) isEuqlaToArray: (id) anObject

     리시버와 인수 객체가 저장된 요소의 개수가 같고 동일한 인덱스 위치에 있는 요소의 값이 서로 같을 때 YES


- (id) firstObjectCommonWithArray: (NSArray*) otherArray

     리시버와 인수 배열에 공통으로 들어 있는 객체 중에서 처음으로 찾은 것이 return



** 새로운 요소 추가


-

- (NSArray*) arrayByAddingObject: (id) anObject


- (NSArray*) arrayByAddingObjectsFromArray: (NSArray*) anArray






** 정렬


-

- (NSArray*) sortedArrayUsingSelector: (SEL) comparator

     요소 비교 메서드는 인수를 하나 받아서 결과로 NSComparisonResult 형으로 정해진 값을 돌려줘야 한다.


- (NSArray*) sortedArrayUsingFunction: (NSInteger(*) (id, id, void *)) comparator context: (void*) context

     세번째 인수 context 에는 임의로 값을 지정할 수 있으므로 이것을 사용해 비교 동작 변경(대소문자 구별 등) 을 추가할 수 있다.



** 요소 메시지 송신


-

배열 객체 요소에 일제히 메시지를 보낼 수 있다.

송신은 배열 앞에서부터 끝가지 순서대로 하나씩 이뤄진다.

요소에 보내는 메시지 송신의 파급 효과로 배열 객체 자체가 변경된다던지 하면 바르게 동작하지 않을 수 있다.



-

- (void) makeObjectsPerformSelector: (SEL) aSelector


- (void) makeObjectsPerformSelector: (SEL) aSelector withObject: (id) anObj



** 파일 입,출력


-

- (NSString*) description


- (id) initWithContentsOfFile: (NSString*) aPath

     편의 생성자: arrayWithContentsOfFile:


- (BOOL) writeToFile: (NSString*) path atomically: (BOOL) flag


- (NSString*) componentsJoinedByString: (NSString*) separator


- (NSArray*) pathsMatchingExtensions: (NSArray*) filterTypes

     리시버의 각 요소는 파일명을 나타내는 문자열일 때 유효하다.

     인수 배열은 파일 확장자를 나타내는 문자열을 요소로 가진다.

     인수 배열에 든 확장자를 가진 리시버 요소만 뽑아내어 return 한다.



* 9.4.2. NSMutableArray


** 배열 객체 초기화


-

- (id) initWithCapacity: (NSUInteger) numItems

     편의생성자 : arrayWithCapacity:



** 배열에 추가, 치환


-

- (void) addObject: (id) anObject


- (void) addObjectsFromArray: (NSArray*) otherArray


- (void) insertObject: (id) anObject atIndex: (NSUInteger) index


- (void) replaceObjectAtIndex: (NSUinteger) index withObject: (id) anObject


- (void) replaceObjectsInRange: (NSRange) aRange withObjectsFromArray: (NSArray*) otherArray


- (void) setArray: (NSArray*) otherArray


- (void) exchangeObjectAtIndex: (NSUInteger) idx1 withObjectAtIndex: (NSUInteger) idx2



** 객체 삭제


-

- (void) removeAllObjects


- (void) removeLastObject


- (void) removeObjectAtIndex: (NSUInteger) index


- (void) removeObjectsInRange: (NSRange) aRange


- (void) removeObject: (id) anObject


- (void) removeObjectsInArray: (NSArray*) otherArray



** 정렬


-

- (void) sortUsingSelector: (SEL) comparator



* 9.4.3. 배열 객체와 소유권


-

카운터 관리 방식을 이용할 때 배열 객체에 저장된 객체 소유권에 주의해야 한다.



-

배열 객체는 저장된 객체에 retain 메시지를 보내서 유지한다.

또한 배열 객체가 해제될 때는 저장된 객체 모두에 release 메시지를 보낸다.

배열 객체에 저장된 객체를 삭제할 때도 그 객체에 release 메시지를 보낸다.



-

수동 카운터 관리 방식은 다음과 같은 코드를 사용하면 안 된다.

NSArray* arr = [[NSArray alloc] initWithObjects:[[Card alloc] init], [[Player alloc] init], nil];


이 코드를 실행한 객체를 obj 라고 하면 obj 는 배열에 있는 두 요소의 소유자가 된다.

동시에 배열 객체에 저장되어 있으므로 배열 arr 도 요소의 소유권을 가진다.

하지만 나중에 arr 가 해제되더라도 arr 가 가진 소유권은 파기되지만 obj 소유권은 그대로 남아 있어 요소를 해제시킬 수 없다.


ARC 에서는 문제가 없다.


MRC 에서는 아래와 같이 코드가 바뀌어야 한다.

NSArray* arr = [[NSArray alloc] initWithObjects:[[[Card alloc] init] autoRelease], [[[Player alloc] init] autoRelease], nil];



-

마찬가지로 제거할 때도 문제가 된다.

아래와 같이 retain 을 먼저 한 후에 배열에서 remove 를 해야 문제가 없다.

id obj = [[arr objectAtIndex: index] retain] autorelease];

[arr removeObjectAtIndex:index];



-

컬렉션 객체들이 요소를 저장할 때는 retain 메시지를 보내고, 삭제될 때 release 메시지를 보내기 때문에,

MRC 에서는 위와 같은 상황에 항상 주의해야 한다.




** 9.4.4. 고속 열거


-

Objective-C 2.0 에는 배열과 집합, 사전 같은 컬렉션에 저장되는 요소 객체를 반복해서 순서대로 추출하기 위한 구문을 사용할 수 있다.

이 기능을 고속 열거(fast enumeration) 라고 부른다.



-

for in 문의 실행은 컬렉션이 변경 가능하든지 변경 불가능하든지 관계 없으나 변경 가능한 컬렉션은 반복문을 실행하는 사이에 내용을 바꿀 수가 없다.

내용을 바꾸면 예외가 발생해서 실행이 중단된다.



-

컬렉션 배열일 때는 앞에서부터 요소를 추출하고 집합일 때는 요소를 추출하는 순서가 내부 구현에 의존한다.

컬렉션 사전 객체일 때 for..in 문에서 추출하는 것 키이며, 추출하는 순서는 내부 구현에 의존한다.



-

반복문은 중첩이 가능하다.



-

for 괄호 속에서 변수형을 지정할수도 안 할수도 있다.




* 9.4.5. 열거자 NSEnumerator


-

열거자를 나타내는 추상 클래스는 NSEnumerator 로 컬렉션 클래스 인스턴스 메서드에 따라 구체적인 인스턴스가 돌아온다.

이 인스턴스는 임시 객체이며, NSEnumerator 자체에 alloc 등을 송신하는 일은 없다.



-

- (id) nextObject

     열거된 다음 요소를 추출한다.

     더 이상 추출할 요소가 없으면 nil 을 돌려준다.


- (NSArray*) allObjects

     아직 추출하지 않은 모든 요소를 NSArray 형으로 모아 임시 배열 객체로 돌려준다.

     다만, 이 메서드를 구현하지 않은 열거자도 있다.



-

열거자를 돌려주는 메서드명은 컬렉션의 클래스에 따라 다르다.

배열의 경우 다음 두가지이다.


- (NSEnumerator*) objectEnumerator


- (NSEnumerator*) reverseObjectEnumerator



-

Idiom

NSEnumerator* enumerator = [array objectEnumerator];

id obj;

while( (obj = [enumerator nextObject]) != nil ){

     // do sth..

}



-

변경 가능한 컬렉션 클래스 인스턴스에 열거자를 사용해서 처리할 경우 열거 반복문 안에서 저장된 객체를 삭제하거나 새로운 객체를 추가하는 건 위험하다.

예상하지 못한 결과를 얻게 된다.



-

카운터 관리 방식을 사용할 때 NSEnumerator 인스턴스는 요소를 열거하는 동안 그 컬렉션 객체를 유지한다.

마지막 요소를 추출한 후에 컬렉션 객체에 대한 소유권은 파기된다.




* 9.4.6. 고속 열거자와 열거자


-

고속 열거는 C 언어를 사용해서 효율화를 꾀하기 때문에 매번 메서드를 호출하는 열거자 방법보다 훨씬 빠르게 실행된다.

즉, 고속 열거란 기존 방법인 열거자보다 빠르다는 의미로 그렇게 부른다.



-

열거자는 더 이상 사용되지 않는 걸까?

그렇지 않다.

반복문 속의 처리가 복잡하고 조건에 따라 요소를 건너뛰어야 할 때는 열거자를 사용하는 쪽이 작성하기 쉽다.


또한 열거자 자체도 for..in 문에 사용될 수 있어, 반대 순서 처리 등에 좋다. ( reverseObjectEnumerator 를 in 뒤에 넣는 방법 )



-

고속 열거가 가능한 클래스는 NSFastEnumerator 프로토콜을 구현한다.

열거자 클래스 NSEnumerator 도 이 프로토콜을 구현하므로 for..in 문을 사용할 수 있다.



-

고속 열거를 스스로 만든 클래스에 구현할 수도 있지만 조금 복잡하다.

또한 실제 프로그램에서는 배열 같은 기존 컬렉션으로 충분하다.




** 9.4.7. 집합 클래스


-

배열 객체와는 달리 요소 사이에 순서가 없는, 같은 요소가 여러 번 포함되지 않는 컬렉션을 집합 객체 또는 단순히 집합(set) 이라고 부른다.



-

같은 객체를 여러번 포함될 수 있는 집합을 카운터 포함 집합 (counted set) 또는 백(bag) 이라고 부른다.

NSCountedSet 이 그것이다.



-

+ (id) set


- (id) initWithArray: (NSArray*) array


- (NSUInteger) count


- (NSArray*) allObjects


- (BOOL) containsObject: (id) anObject


- (BOOL) isEqualToSet: (NSSet*) otherSet


- (BOOL) isSubsetOfSet: (NSSet*) otherSet


- (BOOL) intersetcSet: (NSSet*) otherSet



-

NSMutableSet


- (id) initWithCapacity: (NSUInteger) numItems

     편의 생성자 : setWithCapacity:


- (void) addObject: (id) anObject


- (void) removeObject: (id) anObject


- (void) unionSet: (NSSet*) otherSet

     합집합을 구성한다.

     minusSet: 은 공통 요소를 제거한다.

     intersectSet: 은 리시버 집합과 인수 집합의 공통 요소만 남긴 교집합을 구성한다.





반응형

댓글