- 카테고리란? 클래스의 행위(메소드)를 일정 기준으로 분리, 정의한 것을 의미한다.
- 카테고리 선언 방법클래스의 구현 파일
@implementation ClassName
-(void)method1{
// method1에 대한 기능 정의
}
@end
@implement ClassName(CategoryName)
-(void)method2{
// method2에 대한 기능 정의
}
@end - 카테고리의 목적
Objective-C 카테고리
Objective-C 아카이빙
- 아카이빙이란? 데이터를 저장하고, 불러올 수 있는 메카니즘을 의미한다.
- 아카이빙 메커니즘에 대한 그림은 아래와 같다.

- 아카이빙에서는 아카이버를 이용하여 데이터를 저장하고, 언 아카이버를 이용하여 저장한 데이터를 불러온다.
- iOS용 파운데이션
- 아카이버 : NSKeyedArchiver
- 언 아카이버 : NSKeyedUnarchiver
- 아카이빙을 사용하기 위해서는 우선 NSCoding 프로토콜에 대해서 알아야한다.
- NSCoding 프로토콜
- 객체를 저장하고, 불러올 수 있는 encoding/decoding 메소드를 제공한다.
- 구성은 아래와 같다.NSCoding 프로토콜
@protocol NSCoding
-(void)encodeWithCoder:(NSCoder *)aEncoder;
-(id)initWithCoder:(NSCoder *)aDecoder;
@end - NSCoder를 클래스에서 인코딩 시에 키-값 형태로 저장한다.NSCoding 프로토콜 채택 후 구현
// encoding
-(void)encodeWithCoder:(NSCoder *)aEncoder {
[aEncoder encodeInt:10 forKey:@"TEST"];
}
// decoding
-(id) initWithCoder:(NSCoder *) aDecoder {
self = [super init];
if(self) {
int value = [aDecoder decodeIntForKey:@"TEST"];
}
return self;
} - NSCoding 프로토콜로 정의된 객체에 아카이빙을 이용하여 파일로 저장하거나 NSData로 저장 후에 다시 불러올 수 있다.
- 파일로 저장 후 불러오기아카이빙을 파일을 이용
// 파일에 저장
ClassName *obj = [[ClassName alloc] init];
// 객체 값 설정
NSString *filePath = @"파일경로";
[NSKeyedArchiver archiverRootObject:obj toFile:filePath];
// 파일로 저장하면서 자동으로 인코딩 메소드 동작
// 파일에 저장된 내용 불러오기
ClassName *obj2 = [NSKeyedUnarchiver unarchiverObjectWithFile:filePath];
// 파일에서 읽어오면서 자동으로 디코딩 코드 동작 - NSData를 이용하여 저장 후 불러오기아카이빙을 NSData를 이용
// NSMutableData에 저장
NSMutableData *mdata = [NSMutableData data];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:mdata];
// 데이터 인코딩
[archiver encodingObject:@"ClassName" forKey:@"STRING"];
// 인코딩 마무리
[archiver finishEncoding];
// NSMutableData에 저장된 내용 불러오기
NSKeyedUnarchiber *unarchibver = [[NSKeyedUnarchiver alloc] initForReadingWithData:mdata];
// 데이터 디코딩
NSString *str = [unarchiver decodingObjectForKey:@"STRING"];
- 아래는 NSData를 이용한 데이터 저장 및 불러오기를 구현한 소스이다.

- 위의 소스 코드를 실행하면 아래와 같은 결과를 얻을 수 있다.

Objective-C 프로토콜
- 프로토콜이란? 구현부 없이 헤더파일만 존재하는 상태로 프로토콜 내에 메소드만 정의되어 있는 형태를 의미하며, 자바의 Interface, C/C++의 virtual class 와 동일한 기능을 한다.
- 프로토콜 선언 방법
위와 같이 정의하고, 별도의 구현파일은 존재하지 않는다.프로토콜 선언@protocol ProtocalName<NSObject>
-(void)method1;
@end - 프로토콜의 사용은 클래스가 프로토콜을 채택하여 프로토콜에 정의된 메소드를 구현한다.
- 아래는 클래스에서 프로토콜을 채택하는 방법이다.프로토콜 채택
// 헤더 파일에서 프로토콜 채택
@interface ClassName : NSObject <ProtocalName>
@end
// 구현파일에서 프로토콜 채택
@interface ClassName() <ProtocolName>
...
@end - 아래는 클래스에서 프로토콜을 채택하는 방법을 소스로 나타낸 예제이다.

- 클래스에서는 다수의 프로토콜을 채택하여 사용하는 것이 가능하며, 다수의 클래스에서 하나의 프로토콜을 채택해서 사용할 수도 있다.
- 아래는 클래스에서 다수의 프로토콜을 채택한 경우이다.다수의 프로토콜 채택
// Protocol 1
@protocol Protocal1<NSObject>
-(void)method1;
@end
// Protocol 2
@protocol Protocal2<NSObject>
-(void)method2;
@end
// Protocol 1, 2를 모두 채택
@interface ClassName : NSObject <Protocal1, Protocal2>
...
@end - 아래는 하나의 프로토콜을 다수의 클래스가 채택한 경우이다.다수의 클래스가 하나의 프로토콜 채택
// Protocol 1
@protocol Protocal<NSObject>
-(void)method1;
@end
// Protocol 1 채택
@interface ClassName1 : NSObject <Protocal>
...
@end
// Protocol 1 채택
@interface ClassName2 : NSObject <Protocal>
...
@end
Objective-C 메모리 관리
- 메모리란? 프로그램을 실행 시에 사용되는 저장 공간으로 프로그램 실행이나 개발 시에 메모리라하면 RAM을 뜻하며, 컴퓨터의 전원이 종료되면 저장되어 있던 데이터가 없어지는 휘발성을 갖는다.
- 메모리는 외장하드, 디스크처럼 용량이 많지 않기 때문에 사용하지 않는 영역은 해제하여 사용할 수 있는 메모리를 확보하는 것이 필요하다.
- 한정된 메모리를 사용하기 때문에 아래와 같은 기본관리를 따른다.
- 프로그램에서의 메모리 할당은 객체 생성 시에 발생한다.
- 사용 중인 객체는 유지하고, 사용하지 않는 객체는 해제를 하여 메모리를 관리한다.
- 메모리 부족으로 프로그램인 종료 되기도 하므로 항상 메모리 관리를 따르도록 한다.
- Objective-C에서의 메모리 관리
- 리테인 카운트라고하는 객체에 소유된 개수를 확인하여 해당 개수가 '0'이 되면 사용하지 않는다고 판단하여 메모리에서 해제하도록 한다.
- 메모리 관리는 ARC(Automatic Reference Counting) 라는 기술로 리테인 카운트를 관리한다.
- 실제로 해당 코드를 확인하면 리테인 카운트 관리 코드가 들어 있으며, 이는 자동으로 생성된다.
- iOS5, LLVM 3.0 이후부터 반영되었다.
- 객체를 소유하여 메모리를 할당 받고, 메모리가 해제되는 시점 확인하는 예제는 아래와 같다.
- 객체를 생성하여 메모리할당을 받고, 'nil'을 이용하여 해제하게 된다.

- 위에서 메모리가 해제되는 시점이 어딘지를 확인해보면 아래와 같다.

- obj2에서 nil로 먼저 메모리를 해제를 하여 먼저 해제 메시지가 나오고, obj1은 프로그램이 종료되는 것과 동시에 메모리가 해제되는 것을 확인할 수 있다.
- 객체를 할당하여 메모리 할당을 받을 때 메모리의 여러 영역 중에서 힙(Heap) 영역에 할당을 받게 된다.
- 객체는 선언되는 속성에 따라서 지역 변수와 멤버 변수로 나누게 된다.
- 지역 변수(Local Variable)은 메소드 내에서 선언되는 변수로 해당 선언된 코드 단위가 종료되면 메모리 해제가 발생한다.
- 멤버변수(프로퍼티)는 객체 내에서 선언되는 변수로 객체가 해제되면 메모리 해제가 발생한다.
- 지역변수와 멤버변수 관련된 메모리 해제 시점은 아래 그림을 참조하면 된다. (지역변수: 빨간색, 멤버변수: 파란색)

- 메모리 할당 시 제약 사항
- 프로퍼티 이름은 new로 시작하지 못한다.
- 순환 참조에 주의한다.
- 아래와 같이 서로 참조하게 되면 리테인 카운트가 0이 되지 못하여 메모리가 할당된 상태가 유지되므로 주의한다.

- 위 그림은 Car 객체를 Engine 객체에서 소유하고, Engine 객체를 Car 객체에서 소유하므로 서로 소유하는 관계가 되어 메모리 해제가 안될 수도 있다.
- 리테인 카운트 관련 메소드는 사용하지 못한다.
- 아래의 함수를 사용할 수 없다.
- -(id)retain
- -(void)release
- -(id)autorelease
- (NSUInteger)retainCount
- 메모리 해제 용도로 dealloc 메소드는 사용하지 못한다.
Objective-C 파일 다루기
- 파일 시스템을 다루는 클래스 : NSFileManager
- 객체를 얻는 방법 : +(NSFileManager *)defaultManager;
- 멀티 쓰레드 환경에서는 alloc/init을 사용한다.
- NSFileManager에서 자주 쓰이는 메소드
- 파일 존재 확인 : -(BOOL)fileExistsAtPath:(NSString *)path;
- 파일 복사, 이동, 삭제
- 파일 복사 : -(BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;
- 파일 삭제 : -(BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error;
- 파일 이동은 파일 복사 후에 source 파일을 삭제한다.
- 파일 권한 확인
- 읽기 전용 : -(BOOL)isReadableFileAtPath:(NSString *)path;
- 쓰기 전용 : -(BOOL)isWritableFileAtPath:(NSString *)path;
- 디렉토리 내용 확인 : (NSArray *)contentsOfDirectoryAtPath(NSString *)path error:(NSError **) error;
- 문자열을 파일로 저장
- NSString 클래스의 -(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile encoding:(NSStringEncoding)enc error:(NSError **)error; 메소드로 문자열을 파일로 저장

- 위의 코드를 실행하면 아래와 같이 해당 경로에 파일이 생성되고, 파일에 문자열이 저장된 것을 확인할 수 있다.

- 파일 에러 처리
- 파일 시스템의 동작 수행 중에 오류 발생하면 에러 객체 전달
- 에러 파라미터 : NSError ** 로 정의
- 사용법 : 포인터의 주소를 넘긴다.(&사용)
파일 동작 에러 처리 __autoreleasing NSError *error = nil;
...
BOOL ret = [fm removeItemAtPath:path error:&error];
if(!ret) {
NSLog(@"에러 : %@", [error locaizedDescription]);
} - 에러 처리 시에는 주의할 점은 에러는 더블 포인터로 정의되어 있어 "&" 를 이용한 주소 값으로 넘겨준다.
- 아래와 같이 파일이 없는데 삭제 요청을 하는 경우

- 아래와 같이 에러 메시지를 출력한다.

- NSError : 에러 정보를 표시한다.
- 에러에 대한 정보 표시 메소드
- -(NSString *)localizedDescription;
- -(NSString *)localizedFailureReason;
Objective-C 날짜 다루기
- 날짜와 시간 정보는 기준 시(1970년 1월 1일) 이후 지나간 시간을 다룬다.
- 날짜와 시간정보를 다루는 클래스 : NSDate, NSDateFormatter, NSCalender 등 있다.
- NSDate 클래스 : Time Interval 을 이용한 시간 정보
- 주로 사용되는 메소드
- NSDateFormatter 클래스 : 날짜 표시 형식
- -(void)setDateFormat:(NSString *)string; : 함수를 이용하여 원하는 날짜 표시 형식으로 출력할 수 있다.

- 아래는 위 코드를 출력한 내용이다.

- NSLocale 클래스 : 날짜와 시간 표시 형식을 정의하기 위한 클래스이다.
- 주로 사용되는 메소드
- NSCalendar, NSDateComponents 클래스 : 날짜 구성 요소를 다루는 클래스로 년, 월, 일, 요일 등의 정보를 다룬다.
- NSDateComponents 클래스 : 날짜 정보를 얻거나 설정한다.
- 날짜 정보 얻기
- -(NSInteger)year; : 날짜 정보의 년도
- -(NSInteger)month; : 날짜 정보의 월
- -(NSInteger)day; : 날짜 정보의 일
- -(NSInteger)weekday; : 날짜 정보의 요일(1부터 시작)
- -(NSInteger)weekOfYear; : 날짜 정보의 일년 중 몇 째 주에 대한 정보
- 날짜 정보 설정
- -(void)setYear:(NSInteger)year; : 날짜 정보의 연도를 설정
- -(void)setMonth:(NSInteger)month; : 날짜 정보의 월을 설정
- -(void)setDay:(NSInteger)day; : 날짜 정보의 일을 설정
- NSCalendar 클래스 : 달력 시스템에서 날짜 정보를 얻어온다.
- 객체 생성 메소드 : +(id)currentCalendar;
- NSDateComponents와 NSCalendar 클래스를 이용한 방법은 아래와 같다.

- 아래는 해당 내용을 출력한 것이다.
Objective-C 콜렉션
- 콜렉션이란? 다수의 데이터를 다루는 용도로 사용되는 클래스를 의미한다.
- 콜렉션 클래스는 id 타입의 객체만 저장 가능하며 원시 타입이나 구조체는 래퍼 클래스를 사용한다.
- 주로 사용되는 콜렉션 클래스는 NSArray, NSDictionary, NSSet이 있다.
- NSArray : 인덱스 기반으로 동작하는 콜렉션으로 인덱스와 매칭하여 여러 개의 객체를 저장
- NSArray 클래스는 불가변형으로 할당된 상태에서 값을 저장하면 변경할 수 없다.
- NSArray 클래스의 가변형은 NSMutableArray 클래스로 할당된 상태에서 값을 저장하고 변경이 가능하다.
- 아래 그림은 NSArray 클래스가 저장하는 형태를 나타낸 것이다.

- NSArray 객체 생성 방법
- 단일 객체 생성
- 다수 객체 생성 시 마지막에는 nil 로 종료한다.(첨자표기는 nil로 종료하지 않음)
- 인스턴스 메소드 : -(instancetype)initWithObjects:(id)firstObject, (id)secondObject, ... , nil;
- 팩토리 메소드 : +(instancetype)arrayWithObjects:(id)firstObject, (id)secondObject, ..., nil;
- 첨자표기 : [(id)firstObject, (id)secondObject, ...];

- 배열 사용 시 주의할 사항은 배열의 인덱스가 범위를 벗어나지 않도록 주의한다.
- NSDictionary : 키-값 기반으로 동작하는 콜렉션으로 키와 매칭하여 여러 개의 객체를 저장한다.
- NSDictionary 클래스는 불가변형으로 할당된 상태에서 값을 저장하면 변경할 수 없다.
- NSDictionary 클래스의 가변형은 NSMutableDictionary 클래스로 할당된 상태에서 값을 저장하고 변경이 가능하다.
- 아래 그림은 NSDictionary 클래스가 저장하는 형태를 나타낸 것이다.

- NSDictionary 객체 생성 방법
- NSSet : 인덱트 기반으로 동작하는 콜렉션으로 인덱스와 매칭하여 여러개의 객체를 저장하나 저장된 객체는 모두 유일하며 중복되는 객체는 없도록 구성된 콜렉션 클래스이다.
- NSSet 클래스는 불가변형으로 할당된 상태에서 값을 저장하면 변경할 수 없다.
- NSSet 클래스의 가변형은 NSMutableSet 클래스로 할당된 상태에서 값을 저장하고 변경이 가능하다.
- NSSet 객체 생성 방법
- 콜렉션 순회 방법
Objective-C 파운데이션 프레임워크
- 프레임워크(Framework)란? 어플리케이션에서 구현할 기능들을 하나의 묶음으로 작성한 것을 의미한다.
- 파운데이션 프레임워크는 iOS에서 사용할 기능들을 하나의 묶음으로 제공하게 된다.
- 호출 방법 : #import <Foundation/Foundation.h>
- 파운데이션 프레임워크는 클래스 이름 앞에 "NS"를 붙여서 사용한다.
ex) String -> NSString, int -> NSSInteger - 파운데이션 프레임워크에서 가장 상위 객체 : NSObject
- NSObject는 모든 클래스의 부모 클래스이다.
- NSObject 주요 기능
- 메모리 관리
- 객체를 메모리에 할당하고, 해제하여 메모리를 관리한다.
- alloc 함수로 객체를 메모리에 할당
- dealloc 함수로 객체를 메모리에 해제
- 객체 비교
- 비교 시에 타입에 주의를 한다.
- 원시 타입은 '==' 으로 값을 비교
- 포인터 타입은 '==' 로 주소 비교로 동일 객체 여부를 판단

- 위 코드의 경우 결과는 아래와 같이 나온다.

- 동일한 값이지만, 다른 문자열 객체로 나오게 되는데 포인터 타입의 경우 주소를 비교하기 때문이다.
- 포인터 타입의 값을 비교는 NSObject 클래스 내에 isEqual 함수를 이용

- 객체의 상황을 설명
- 파운데이션 프레임워크에서의 데이터 종류
Objective-C 셀렉터와 프로퍼티
- 셀렉터
- 셀렉터란? 클래스에 선언된 메소드를 구별하고, 선언된 메소드가 있는지 확인 및 실행해준다.
- 메소드를 구별하는 항목
- 메소드 이름
- 메소드의 파라미터 개수
- 메소드의 파라미터 레이블
- 셀렉터에서 메소드 구별하는 예시
- -(int)setWidth:(int)newWidth; -> setWidth:
- -(int)setWidth:(int)newWidth height:(int)newHeight; -> setWidth:height:
- -(int)setWidth:(int)newWidth height:(int)newHeight range:(int)tRange -> setWidth:height:range:
- 셀렉터 사용하기
- 형태 : @selector(메소드)
- SEL 타입 : SEL selector = @selector(length);
- 셀렉터 사용 예시
- -(int)setWidth:(int)newWidth; -> SEL s = @selector(setWidth:);
- -(int)setWidth:(int)newWidth height:(int)newHeight; -> SEL s = @selector(setWidth:height:);
- -(int)setWidth:(int)newWidth height:(int)newHeight range:(int)tRange -> SEL s = @selector(setWidth:height:range:);
- 셀렉터로 메소드 실행하기
- 셀렉터 실행 메소드
- -(id)performSelector:(SEL)aSelector
- -(id)performSelector:(SEL)aSelector withObject:(id)object
- -(id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2
- 셀렉터로 메소드 호출 (NSString 클래스에 있는 length 함수 호출)
셀렉터로 메소드 호출하는 형태 NSString *obj = [[NSString alloc] init];
SEL selector = @selector(length);
[obj performSelector:selector]; - 셀렉터를 사용하는 클래스에 해당 메소드가 있는지 여부 확인 : (BOOL)respondsToSelector:(SEL)aSelector
- 셀렉터를 사용하는 예시는 아래와 같다.

예시) 입력된 문자를 모두 대문자로 변경 - 프로퍼티
- 프로퍼티란? 점(.)을 이용해서 데이터에 접근할 수 있는 툴을 의미한다.
- 프로퍼티 사용 방법 : 클래스 선언부에 프로퍼티 선언을 해준다.
형태) @property ([프로퍼티 속성]) [타입] [변수명]; - 프로퍼티 속성
- 읽기/쓰기 제어
- readwrite : 읽기/쓰기 제어 (기본으로 생략 가능함)
예시) @property (readwrite) int width; - readonly : 읽기 전용
예시) @property (readonly) int width - 쓰레드 접근 제어
- atomic : 동시에 접근하는 쓰레드 제어(기본으로 생략가능)
예시) @property (atomic) int width; - nonatomic : 쓰레드 접근 제어 사용 안 함
예시) @property (nonatomic) int width; - 게터와 세터 메소드 이름
- getter = [게터 메소드 셀렉터]
- setter = [세터 메소드 셀렉터]
- 예시) @property (getter = getWidth, setter = setRactangleWidth:) int width; -> 보통 세터는 설정하지 않음
- 메모리 소유권 (추후에 다룸)
- 프로퍼티와 멤버변수
- 프로퍼티 선언 시에 언더바(_) + 프로퍼티 이름의 멤버 변수가 생성된다.
- 멤버 변수 선언과 프로퍼티 선언을 함께한 경우 이름이 같아도 두 멤버 변수가 선언된 상태가 된다.
주의 : width와 _width 가 선언된 상태로 (width는 선언된 멤버변수, _width는 프로퍼티에서 선언된 멤버변수) 값을 할당해줄 때 별도의 멤버 변수이므로 원하는데로 값이 할당되지 않을 수 있음프로퍼티와 멤버 변수 @interface Ractangle : NSObject {
int width;
}
@property int width;
@property int height;
@end - 프로퍼티의 멤버 변수와 선언된 멤버변수를 같이 사용하려면, "synthesize" 키워드로 프로퍼티의 멤버변수를 셀렉터로 선언된 멤버변수로 변경해준다.
형태)@synthesize [프로퍼티 이름]; / @synthesize [프로퍼티 이름] = [멤버 변수 이름]; - 2번에 대한 예시) @synthesize width; 를 구현부에 선언하면 "width" 하나로 사용 가능하다.
- 프로퍼티와 게터/세터 메소드
- 프로퍼티를 이용할 경우 단순히 값을 설정하고 설정된 값을 얻어오는 기본 행위만 정의된 함수가 정의가 되는데 추가적인 동작이 필요한 경우 게터와 세터 메소드를 별도로 작성 후 동작을 메소드에 추가한다.
- 프로퍼티로 선언된 게터와 세터의 기본명은 게터는 선언된 멤버변수명, 세터는 set + "선언된 멤버변수명(맨 처음글자만 대문자)"의 형태로 정의된 것과 동일하다.
- 별도의 작업이 필요한 경우에 구현부에 아래와 같이 넣어준다.

예시) 사각형의 가로 길이가 0보다 작은 경우 0으로 변환하고, 세로 길이가 0보다 작은 경우 0으로 값을 얻어온다.
Objectiive-C 동적 타입과 바인딩, 객체 생성 메소드
- 동적 타입 : 코드 작성 시 타입을 명시하지 않은 것을 의미한다.
- 변수나 메소드 정의 시 int, char 와 같은 정적 타입이 아닌 "id" 로 사용한다.
- 포인터 형으로 * 를 사용하지 않는다.
예시) id dynamiicTypeVar; -(id) dynamicTypeMethod1:(int)arg; -(void) dynamicTypeMethod2:(id)arg; - 정적 타입 : 코드 작성 시 타입을 명시하는 것으로 동적 타입과 반대되는 개념이다.
예시) BOOL boolVar; int intVar; NSString *strVar; - 바인딩(Binding) : 참조와 구현이 연결
- 포인터 변수가 객체와 연결
- 메소드 호출 코드와 메소드 구현부가 연결
- 정적 바인딩(Static binding) : 컴파일 시간에 결정
- 동적 바인딩(Dynamic binding) : 런타임(Runtime)에 결정되며, Objectiive-C에서 사용
- 객체 생성 메소드
- 객체 생성이란? 클래스를 사용하기 위해서 별도의 메모리 공간을 할당해주는 것을 의미한다.
- 객체 생성방법 : [[클래스_이름 alloc] init];
- alloc : 객체를 생성하는 메소드
- init : 객체를 초기화하는 메소드
- 객체 생성 메소드에서 동작해야하는 코드는 init 메소드를 재정의하는 것이다.
- 팩토리 메소드 : 객체 생성 디자인 패턴으로 객체를 생성하고 반환하는 코드로 클래스 메소드이다. 메소드의 이름은 클래스의 이름으로 시작한다.
피드 구독하기:
글 (Atom)


























