'Objective_C'에 해당되는 글 4건
- 2020.04.14 :: [Objective-C] 기초배우기 (4)
- 2020.04.14 :: [Objective-C] 기초배우기 (3)
- 2020.04.14 :: [Objective-C] 기초배우기 (2)
- 2020.04.13 :: [Obejective-C] 기초배우기 (1)
9.파운데이션 프레임워크
9-1.루트 클래스
NSObject는 Objective-C의 클래스가 가져야 할 가장 기본적인 기능(메모리 관리, 객체 식별 등)을 제공하며,모든 클래스는 NSObject를 직접 혹은 간접적으로 상속함으로써 그 기능들을 사용할 수 있게된다. 사용자가 직접 구현하는 클래스도 이를 위해 NSObject를 상속하는 것을 절대 잊지말아야한다.
9-2.문자열 관련 클래스
9-2-1.NSString
유니코드 방식으로 문자열을 다루는 기능을 제공하는 클래스,. 파운데이션 프레임워크에서 가장 많이 사용되는 클래스
-기본사용방법 : 문자열 앞에 항상 '@'를 붙여주어야한다. NSString *string = @"string test";
-포맷표현 방식 : 다른언어의 %s가 아니라 %@사용한다. 나머지 타입은 같다(%d,%f,%u)
NSString *string1 = [[NSString alloc]initWithFormat:@"%@",@"string"];
NSStirng *string2 =[NSString stringWithString:@"string"];
-생성 메소드 : 클래스 메소드는 alloc 또는 copy로 시작하는 이름을 갖지 않으므로 사용이 끝난 후 release할 필요없다.
인스턴스 메소드들은 alloc 메소드를 이용하여 생성되므로, 사용이 끝난 후에는 반드시 release를 호출해야한다.
//빈 문자열을 가지는 객체를 생성하여 반환
+(id)string
//주어진 문자열을 가지는 객체를 생성하여 반환
+(id)stringWithFormat:(NSString *)format, …
+(id)stringWithString:(NSString *)aString;
//위 메소드들의 인스턴스 메소드 형태, 기능은 동일
-(id)initWithFormat:(NSString *)format …
-(id)initWithString:(NSString *)aString
//사용예
NSString *string1 = [NSString string];
NSString *string2 = [NSString stringWithFormat:@"String: %@", @"Test"];
NSString *string3 = [NSString stringWithString:@"String"];
NSString *string4 = [[NSString alloc] initWithFormat:@"String : %@",@"Test"];
NSString *string5 = [[NSString alloc] initWithString:@"String"];
-결합메소드
//현재 문자열과 주어진 문자열을 결합하여 반환
-(NSString *)stringByAppendingFormat:(NSSting *)format …
-(NSString *)stringByAppendingString:(NSString *)aString
//사용예
NSString *string1 = @"Hello"
NSString *string2 = [stirng1 stringByAppendingFormat:@"%@",@"World"];
NSString *string3 = [stirng1 stringByAppendingString:@" World"];
-분리 메소드
//현재 문자열을 검사하여 주어진 문자열이 나타낼 때마다 문자열 분리
-(NSArray *)componentsSeparatedByString:(NSString *)separator
//현재 문자열의 주어진 위치 이후 문자열 반환
-(NSString *)substringFromIndex:(NSUInteger)anIndex
//현재 문자열의 주어진 위치까지의 문자열 반환
-(NSString *)substringToIndex:(NSUInteger)anIndex
//사용예
NSString *string1 = @"String1, String2, String3";
NSArray *iterms =[string1 componentsSeparatedByString:@". "];
//ite는 :{@"String1", @"String2", @"String2"}
NSString *string2 =@"String";
NSString *string3 =[string2 substringFromIndex:3];
NSString *string4 =[string2 substringToIndex:3];
//string 2: @"ing" string 4:@"str"
-값 변환 메소드
//현재 문자열에 해당하는 정수값 반환
-(int)intValue
//현재 문자열에 해당하는 실수값 반환
-(float)floatValue
-(double)doubleValue
//사용예
NSString *string1 =@"5";
int intValue =[string1 intValue]; //intValue : 5
NSString *string2 =@"2.34";
float floatValue = [string2 floatValue]; //2.34
double double Value = [string2 doubleValue]; //2.34
-비교 메소드
//현재 문자열이 주어진 문자열로 시작하는지 검사
-(BOOL)hasPrefix:(NSString *)aString
//현재 문자열이 주어진 문자열로 끝나는지 검사
-(BOOL)hasSuffix:(NSString *)aString
//현재의 문자열이 주어진 문자열과 동일하지 검사
-(BOOL)isEqualToString:(NSString *)aString
//사용예
NSString *string1 = @"Hello World!";
BOOL value1 = [string1 hasPrefix:@"Hel"];
BOOL value2 = [string1 hasSuffix:@"orld"]; //value1,value2 :YES
BOOL value3 = [string1 isEaualToString:@"Hello World!"]; //value3 :YES
-기타 메소드
//문자열의 길이를 반환
-(NSUInteger)length
//문자열읮 ㅜ어진 위치에 해당하는 문자를 반환
-(unichar)characterAtIndexLNSUInteger)index
//사용예
NSString *string = @"String";
int length = [string length]; //length :6
unichar value = [string characterAtIndex:3]; //value : i
9-2-2.NSMutableString
NSString 클래스를 상속하는 자식 클래스, 문자열을 한번 할당하면 변경할 수 없는 NSString과는 달리 수정할 수 있다는 것이 장점, 참고로 파운데이션 프레임워크 클래스 중에서 이름에 Nutable이 포함된 클래스 (NSMutableArray, NSMutableDictionary 등)는 값을 수정할 수 있는 클래스다,.
//주어진 문자열을 현재의 문자열과 결합
-(void)appendFormat:(NSString *)format ..
-(void)appendFormat:(NSString *)aString
//주어진 문자열을 현재 문자열의 주어진 위치에 사입
-(void)insertString:(NSString *)aString atIndex:(NSUInteger)anIndex;
//현재의 문자열을 주어진 문자열로 대체
-(void)setString:(NSString *)aString
//사용예
NSMutableString *string. = [NSmutableString stringWithString:@"Hello"]; //String :@"Hello"
[string appendFormat:@"%@",@"Wor"]; //String :@"Hellowor"
[string appendString:@"ld!"] //string: @"Helloworld!"
[string insertString:@" " atIndex:5]; //string: @"Hello world!"
[string setString:@"Bye World!"]; //string: @"Bye World!"
9-3.객체 집합 관련 클래스
NSArray : 순서가 있는 객체 리스트를 관리
NSDictionary : 키 – 값 형태의 객체 리스트를 관리
NSSet : 순서가 없는 객체 리스트를 관리
위는 할당된 내용을 수정할 수 없는 클래스지만. 이들 클래스 이름에 Mutable이 들어간 MSMutableArray, NSMutableDictionary, NSMutableSet는 수정할수 있는 클래스이다.
9-3-1.NSArray
-생성메소드
//사용예
NSDate *aDate = [NSDate distantFuture];
NSValue *aValue = [NSNumber numberWithInt:5];
NSString *aString = @"a string";
// +(id)arrayWithObjects : 주어진 객체들을 포함하는 객체를 생성하여 반환
NSArray *array1 = [NSArray arrayWithObjects:aData, avalue, aString, nil]; //마지막은 반드시 nil을 전달
// -(id)initWithObjects : arrayWithObjects의 인스턴스 메소드 형태, 기능은 동일
NSArray *array2 = [[NSArray alloc]initWithObjects:aData, aValue, aString, nil]; //마지막은 반드시 nil을 전달
//+(id)arrayWithArray: 주어진 배열 내의 인자들을 포함하는 객체를 생성하여 반환
NSArray *array3 = [NSArray arrayWithArray: array1];
//-(id) initWithArray : +arrayWithArray의 인스턴스 메소드 형태 기능은 동일
NSArray *array4 = [[NSArray alloc] initWithArray: array1];
주요메소드
NSString *item1 = @"1", *item2 = @"2", *item3=@"3";
NSArray *array = [NSArray arrayWithObjects: item1, item2, item3, nil]; //array :{item1, item2, item3}
//주어진 배열 내의 인자의 수를 반환
int cout : [array count]; //count :3
//주어진 인덱스의 객체를 반환
NSString *string = [array objectAtIndex:1]; //string :@"2"
//주어진 객체의 배열 내의 인덱스를 반환
NSUInteger index = [array indexOfbject :item3]; //index:2
9-3-2.NSMutabelArray
NSString *item1 = @"1", *item2 = @"2", *item3=@"3", *item4=@"4";
NSMutableArray *array =[NSMutableArray arrayWithObjects: item1, item2, item3, nil]; //array :{item1, item2, item3}
//주어진 인자를 지정된 위치에 삽입한다.
[array insertObject:item4 atIndex:2]; ////array :{item1, item2,item4, item3}
//지정된 위치의 인자를 삭제한다.
[array removeObjectAtIndex:3]; ////array :{item1, item2,item4}
//주어진 인자를 배열 끝에 추가한다.
[array addObject:item3]; // array :{item1, item2,item4,item3}
//마지막 인자를 삭제한다.
[array removeLastObject]; // array :{item1, item2,item4}
//현재 배열의 지정된 위치의 객체를 주어진 객체로 대체한다.
[array replaceObjectAtIndex:2, withObject:item3]; // array :{item1, item2,item3}
9-3-3.NSDictionary –stl의 map
-생성메소드
//+(id) dictionaryWithObjectsAndKeys: 주어진 객체, 키 값으로부터 객체를 생성반환
NSDictionary *dict1 = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2",nil];
//-(id) initWithdictionaryWithObjectsAndKeys:+(id) dictionaryWithObjectsAndKeys의 인스턴스 메소드 형태
NSDictionary *dict2 = [[NSDictionary alloc] initWithdictionaryWithObjectsAndKeys:@"value1", @"key1", @"value2", @"key2",nil];
-주요메소드
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"Chris", @"name", @"programmer", @"job",nil]; //dirct :{@"job" : @"programmer", @"name :@"Chris"}
//dictionary에 있는 객체의 수를 반환
NSUInteger count = [dict count]; //count :2;
//dictionary에 있는 모든 키 값들을 반환
NSArray *keys= [dict allKeys]; //Keys:{@"job",@"name"};
//dictionary에 있는 모든 객체들을 반환
NSArray *values = [dict allValues]; values :{@"programmer",@"Chris"}
//주어진 키 값을 갖는 객체를 반환
NSString *string = [dict objectForKey:@"name"]; //string : @"Chris"
9-3-4.NSMutableDictionary
NSMutableDictionary *dict =[NSMutableDictionary dictionary]; //Dict: { }
//주어진 객체와 키 조합을 추가한다.
[dict setObject:@"Chris" forKey:@"name"]; //dict:{@name: @"chris"}
[dict setObject:@"programmer" forKey:@"job"]; //dict: {@"job": @"programmer", @"name" : @"Chris"}
//주어진 객체와 키 조합을 삭제
[dict removeObjectForKey:@"name"]; //dict : {@"job" : "programmer"};
//모든 객체-키 조합 삭제
[dict removeAllObjects];//dict:{ }
9-3-5.NSSet –NSArray와 달리 순서가 없다.
-생성메소드
NSDate *aDate = [NSDate distantFuture];
NSValue *aValue = [NSNumber numberWithInt:5];
NSString *aString = @"a string";
//주어진 객체들을 포함하는 객체를 생성하여 반환
NSSet "mySet =[NSSet setWithObjects:aDate, aValue, aString, nil];
// NSSet "mySet =[[NSSet alloc]initWithObjects:aDate, aValue, aString, nil];
-주요메소드
NSDate *aDate = [NSDate distantFuture];
NSValue *aValue = [NSNumber numberWithInt:5];
NSString *name = @"Chris";
NSSet *mySet =[NSSet setWithObjects: date, value, name, nil]; //mySet :{value, name, date}
//NSSet 에 들어있는 오브젝트 객체 개수
NSUInteger count =[mySet count]; //count :3
//NSSet에 들어있는 모든 오브젝트 객체 반환
NSArray *array1 = [mySet allObjects]; // array1 : {value, name, date;
//NSSet 내에 주어진 객체가 존재하는지 검사하여 결과 반환
BOOL result = [mySet containsObject:@"Chris"]; //result :YES
9-3-6 NSMutableSet
NSDate *aDate = [NSDate distantFuture];
NSValue *aValue = [NSNumber numberWithInt:5];
NSString *name = @"Chris", *job = @"programmer";
NSMutableSet *mySet =[NSMutableSet setWithObjects: date, value, name, nil]; //mySet :{value, name, date}
//set에 주어진 객체를 추가
[mySet addObject:job]; //mySet :{job, value, name, date}
//set에 주어진 객체 삭제
[mySet removeObject:@"Chris"]; //mySet :{job, date,value}
//set의 모든 객체 삭제
[mySet removeAllObjects]; //mySet: {}
9-3-7 객체 탐색
-객체를 탐색하는 예
NSArray *array = [NSArray arrayWithObjects:@"One",@"Two", @"Three", @"Four", nil];
NSString *item = nil;
for( item in array){
if([item isEqualToString:@"Three"]){
break;
}
}
-NSEnumerator를 사용하는 방법
NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", @Three", @"Four", @nil];
NSString *item = nil;
NSEnumerator *enumerator = [array objectEnumerator];
while(item = [enumerator nextObject]){
if( [item isEqualToString:@"Three"]){
break;
}
}
NSEnumerator 사용하면 좋은예
NSArray의 경우 reverseEnumerator 메소드를 이용하여 객체를 역순으로 탐색 할수 있다.
objectEnumerator 대신에 reverseEnumerator 메소드를 호출하면 된다.
NSDictionary의 경우 NSEnumerator를 이용하면 키 값뿐 아니라 객체도 탐색할 수 있다. 키 값을 탐색할때는 KeyEnumerator 메소드, 객체 값을 탐색할때는 objectEnumerator를 이용하면 된다
9-4. 값(정수 및 실수)표현 관련 클래스
9-4-1.NSNumber
NSValue 클래스를 상속하는 자식 클래스, BOOL, char, int, float와 double 등 각종 값을 설정하고 반환하는 기능을 수행한다.
NSNumber *boolNumber = [NSNumber numberWithBool:YES];
NSNumber *intNumber = [NSNumber numberWithInt:23];
NSNumber *doubleNumber = [NSNumber numberWithDouble:23.46];
BOOL value1 = [boolNumber boolValue];
int value2 = [intNumber intValue];
double value3 = [doubleNumber doubleValue];
//값비교
NSNumber *intNumber = [NSNumber numberWithInt:23];
NSNumber *floatNumber = [NSNumber numberWithFloat:3.45];
NSString *string1 = [intNumber stringValue]; //string1 : 23
if(NSOrderedAscending == [intNumber compare:floatNumber]{
…
}
BOOL equality = [intNumber isEqualToNumber:floatNumber];
//compare:메소드는 kemdarhk 같은 반환값을 가지게된다.
NSOrderedAscending :현재 값보다 주어진 값이 클경우
NSOrderedDescending :현재 값보다 주어진 값이 작은경우
NSOrderedSame :현재 값과 주어진 값이 같은
'Objective_C' 카테고리의 다른 글
[Objective-C] 기초배우기 (3) (0) | 2020.04.14 |
---|---|
[Objective-C] 기초배우기 (2) (0) | 2020.04.14 |
[Obejective-C] 기초배우기 (1) (0) | 2020.04.13 |
7.프로토콜
특정 객체에 변화가 일어나면 혹은 어떤 특별한 의미를 가지는 시점에 도달하면 해당 객체로부터 이에 대한 알림 서비스를 받고 싶을경우 '프로토콜'를 사용한다.
프로토콜을 사용하면 객체로부터 콜백 메소드의 형태로 알림 서비스를 받을 수 있다.
1.프로토콜을 선언하는 brush 클래스가 구현되는 방식
//헤더파일
@protocol 프로토콜 이름; //(1) 프로토콜을 선언하는 부분
@interface 클래스 이름: 부모 클래스 이름{
id<프로토콜 이름> delegate; //(2)프로토콜을 사용하고자 하는 클래스 인스턴스의 포인터
…
}
@property (nonatomic, retain) id<프로토콜 이름> delegate;
//프로토콜을 사용하는 메소드 //(3) 프로토콜을 사용하는 메소드를 선언한다.
@end
@protocol 프로토콜 이름 <타 프로토콜 이름> //(4)@protocol에서 @end까지 프로토콜을 정의하는 부분
@required //(5)required에는 반드시 정의해야하는 메소드(기본)
메소드 선언 리스트
@optional //(5)optional에는 반드시 정의할 필요는 없는 메소드를 선언
메소드 선언 리스트
@end
//소스파일
#import "헤더 파일"
@implementation
@synthesize delegate;
...
프로토콜에서 선언된 메소드를 호출하는 메소드 정의 //(6) 프로토콜에서 선언된 메소드를 정의한다.
…
@end
(2)프로토콜을 사용하고자 하는 클래스 인스턴스의 포인터를 저장하는 부분, 이 값을 정의하지 않으면 프로토콜 메소드를 호출할 방법이 없으므로 프로토콜을 사용하는 클래스 인스턴스에서 반드시 설정해야한다.
(3) 프로토콜을 사용하는 메소드를 선언한다. 당연한 이야기지만 어느 메소드가 프로토콜 내의 어느 메소드를 호출해야 한다는 내용은 정해져 있지 않다. 인터페이스 내의 어떠한 메소드라도 프로토콜 내에 선언되어 있는 메소드를 호출할 수 있다. 즉, 적절한 메소드에서 필요한 시점에 호출해주면되는 것이다.
(4)@protocol에서 @end까지 프로토콜을 정의하는 부분.'<타 프로토콜 이름>'을 지정하게 되면 해당 프로토콜의 내용을 가져와 현재 프로토콜에 포함한다.
ex)프로토콜을 선언하는 brush 클래스가 구현되는 방식
//Brush.h
#import <Foundation/Foundation.h>
@protocol BrushDelegate; //(1)
@interface Brush : NSObject {
id<BrushDelegate> deleage; //(2)
}
@property (nonatomic, retain) id<BrushDelegate> delegate;
-(void)changeColor; //(3)
@end
@protocol BrushDelegate<NSObject> //(4)
@optional //(5)
-(void)brush(Brush *)brush WillStartChangingColor:(UIColor *)color;
-(void)brush(Brush *)brush didStartChangingColor:(UIColor *)color;
-(void)brush(Brush *)brush willFinishChangingColor:(UIColor *)color;
-(void)brush(Brush *)brush didFinishChangingColor:(UIColor *)color;
@end
//Brush.m
#import "Brush.h"
@implementation Brush
@synthesize delegate;
-(void)ChangeColor { //(6)
UIColor *color = [UIColor blackColor];
if([self.delegate respondsToSelector:@selector(brush:willStartChangingColor;)]) {
[self.delegate brush:self WillStartChangingColor:color];
}
…..
}
@end
respondsToSelector 는 메소드를 호출하는 것에 주목하자. 이 메소드는 NSObject에 선언된 것인데, 호출하고 있는 객체 내에 어떠한 메소드가 정의되어 있는지 검사한다.
2. 프로토콜(BrushDelegate )을 사용하고자 하는 클래스의 구조
//헤더 파일
#import "프로토콜을 선언한 헤더파일" //(1)프로토콜을 선언한 헤더 파일을 추가
…
@interface 클래스이름 : 부모클래스이름 <사용하려고하는 프로토콜이름>{ //(2) 사용하려는 프로토콜이름 명시
프로토콜을 선언하고 있는 클래스 타입 인스턴스 변수 //(3)프로토콜클래스의 인스턴스변수 선언
}
…
@end
//소스파일
#import "헤더 파일"
@implementation
@synthesize (3)에서 선언된 인스턴스 변수
….
인스턴스 변수(3)에게 프로토콜을 사용하고자 하는 현재 클래스 인스턴스의 주소값을 넘겨줌 //(4)
프로토콜 내에 선언된 메소드 정의 //(5)
…
@end
(4)현재 클래스 인스턴스의 주소값을 넘겨줌(5)에서 정의하고 있는 메소드가 정상적으로 호출되도록 한다.
(5) 프로토콜을 선언하여 정의하고 있는 클래스에서는 메소드를 선언만 하고 있을 뿐 구현은 하지 않고 있다. 이는 전적으로 프로토콜을 사용하는 클래스의 몫으로 남겨져 있다. 그러므로 해당 메소드에 대한 구현 부분이 반드시 이곳을 존배해야한다.
ex)BrushDelegate를 사용한 Rectangle 클래스
//Rectangle.h
#import <Foundation/Foundation.h>
#import "Shape.h"
#import "Brush.h"
@class Circle;
@interface Rectangle : shape <BrushDelegate> {
@protected
Brush *brush;
NSString *name;
NSInteget width;
NSInteget height;
}
@property (nonatomic, retain)Brush *brush;
@property (nonatomic, retain)NSString *name;
@property (nonatomic, retain)NSInteger width;
@property (nonatomic, retain)NSInteger height;;
-(id) initWithWidth:(NSInteger)myWidth height:(NSInteger)myHeight;
-(NSString *)description;
-(void)draw;
@end
//Rectangle.m
@import "Rectangle.h"
@implementation Rectangle
@synthesize brush;
@synthesize name;
@synthesize width;
@synthesize height;
-(id)init{
return [self initWithWidth:10 height:20];
}
-(id) initWihWidth:(NSInteger)myWidth height:(NSInteger)myHeight{
if(self =[super init]){
brush =[[Brush alloc] init];
brush.delegate = self;
name = nil;
width = myWidth;
height = myHeight;
}
return self;
}
-(void)brush(Brush *)brush WillStartChangingColor:(UIColor *)color
{…}
-(void)brush(Brush *)brush didStartChangingColor:(UIColor *)color
{…}
-(void)brush(Brush *)brush willFinishChangingColor:(UIColor *)color
{…}
-(void)brush(Brush *)brush didFinishChangingColor:(UIColor *)color
{…}
-(NSString *)description{
NSString *text =nil;
Text = [[NSString alloc] initWithString:@"Test";
[text autorelease];
return text;
}
-(void)draw{
[super draw];
}
-(void)dealloc{
[name release];
[super dealloc];
}
@end
프로토콜 내에는 하나 또는 그 이상의 메소드를 선언할 수 있으며, 이들은 이후 이 프로토콜을 사용하고자 하는 클래스의 소스파일에서 정의한다. 그리고 이 프로토콜을 이용하는 클래스가 있어야한다. 당연한 이야기이겠지만 프로토콜을 이용하는 클래스의 수와 종류에는 제한이 없다. 어느 클래스라도 프로토콜을 선언하고 있는 클래스를 자신의 멤버 변수로 포함하고 이용하면 되는 것이다.
실제로 파운데이션 프레임워크 내의 많은 클래스도 이처럼 프로토콜을 이용할 수 있도록 구현되어 있다.
다양한 프로토콜 메소드를 이용하는 대표적인 예로 테이블뷰(UITableView)를 들수 있다.
8.카테고리와 클래스 확장
카테고리는 특정 클래스의 소스를 가지고 있지 않더라도 해당 클래스에 새로운 메소드를 추가하는 것을 상속 없이 가능케한다.
8-1클래스에 메소드 추가하기
//헤더파일
#import "클래스 이름" //(1)카테고리를 이용해서 메소드를 추가하고자 하는 클래스의 헤더 파일을 추가한다.
@interface 클래스 이름 (카테고리 이름) //(2)클래스 이름 괄호안에 카테고리 이름을 지정
//메소드 선언 //(3)클래스에 추가하는 메소드를 선언 인스턴스변수는 추가할 수 없다.
@end
//소스 파일
#import "헤더 파일" //(4)헤더 파일을 추가한다. 일반적으로 파일의 이름은"클래스이름+카테고리이름'으로 지정
@implementation 클래스 이름 (카테고리 이름)
//메소드 정의 //(5) 클래스에 추가 선언한 메소드를 정의한다.
@end
ex)카테고리 예
//Rectangle+Display.h
#import <Foundation/Foundation.h>
#import "Rectangle.h"
@interface Rectangle (Display)
-(void)displayDetail;
@end
//Rectangle+Display.m
#import "Rectangle+Display.h"
@implementation Rectangle(Display)
-(void)displayDetail{
…
}
@end
8-2 카테고리의 장점과 단점
-장점
*유사한 메소드를 한곳으로 모아 관리할수 있다.
*여러 개발자가 동시에 하나의 큰 클래스를 설계하고 구현할 때 카테고리로 나눠 작업 할 수 있다.
*큰 클래스를 여러 카테고리로 분리해놓으면 컴파일 할 때 전체를 빌드하지 않고 일부만 컴파일 할수 있다.
-단점
*부모 클래스의 메소드를 재정의(오버라이딩)하고 있는 클래스 메소드를 카테고리에서 또다시 재정의하면 문제가 발생한다. 카테고리에서 부모 클래스의 메소드는 super 지시어를 이용하여 접근할 수 있으나, 클래스에서 이전에 재정의한 메소드는 호출할 방법이 없기 때문이다.
*클래스의 메소드는 둘 이상의 카테고리에서 재정의하면 문제가 발생한다. 두 메소드중 어느 것이 우선권을 가지는지 알수 없기때문이다.
*기존 메소드를 재정의 하는 것 이외에도 문제가 생길 수 있다.
8-3.루트 클래스의 카테고리
루트 클래스인 NSObject에 카테고리를 이용하여 메소드를 추가하면 프로젝트의 모든 코드에서 이를 사용할 수 있게 되므로 매우 위험하다. 또한 루트 클래스에는 부모 클래스가 없으므로 루트 클래스에 메소드를 추가할 때 super지시어를 사용해서는 안된다.
그리고 루트 클래스는 다른 클래스와 달리 클래스 객체(인스턴스 변수가 아닌 클래스 이름 자체를 사용하는 경우)에서도 클래스 메소드 뿐 아니라 인스턴스 메소드를 호출할 수 있다는 사실을 기억해두자
8-4.클래스 확장
클래스 확장은 카테고리와 거의 유사하다. 다른 점은 카테고리 이름을 사용하지 않으며, 메소드를 구현하는 부분이 확장하려는 클래스의 구현 부분에 반드시 존재해야한다는 것이다.
ex)
//Rectangle.h
#import <Foundation/Foundation.h>
#import "Shape.h"
#import "Brush.h"
@class Circle;
@interface Rectangle :Shape <BrushDelegate>{
@protected
Brush *brush;
NSString *name;
NSInteger width;
NSInteger height;
}
@property (nonatomic, retain) Brush *brush;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSInteger width;
@property (nonatomic, retain) NSInteger height;
-(id) initWithWidth:(NSInteger)myWidth height:(NSInteger)myHeight;
-(NSString *)description;
-(void)draw;
@end
@interface Rectangle()
-(void)displayDetailEx;
@end
//Rectangle.m
#import "Rectangle.h"
@implementation Rectangle
@synthesize brush;
@synthesize name;
@synthesize width;
@synthesize height;
…..
-(void)displayDetailEx{
..
}
…
@end
'Objective_C' 카테고리의 다른 글
[Objective-C] 기초배우기 (4) (0) | 2020.04.14 |
---|---|
[Objective-C] 기초배우기 (2) (0) | 2020.04.14 |
[Obejective-C] 기초배우기 (1) (0) | 2020.04.13 |
5. 객체의 새성, 사용 그리고 소멸
5-1. 객체 생성하기(메모리 할당과 초기화
Objective-C 에서는 클래스의 인스턴스를 생성할 때 메모리를 할당하고 초기화를 해야 한다. 아래에 보인 예처럼 메모리 할당과 초기화를 한줄로 처리하는 것이 보통이다.
id anObject = [[Rectangle alloc] init]; //Rectangle 생성(alloc)이후 init 함수를 호출해 초기화한다.
메모리를 할당하는데 NSObject 클래스의 alloc과 allocWithZone 메소드가 사용되며, 인스턴스 변수들은 모두0으로 초기화된다.
모든 클래스는 이름이 init으로 시작하는 초기화 메소드를 제공해야한다.(직접 정의하거나 다른 클래스를 상속하여 init 메소드를 제공해야 한다). 이때 특별한 인자가 필요하지 않으면 init이라는 이름을 그대로 사용하며, 인자가 필요하면 init 뒤에 적절한 이름을 붙여 사용한다.
예를 들면, 파운데이션 프레임워크의 NSView 클래스는 initWithframe: 메소드를 NSString 클래스는 initWithFormat: 메소드를 가지고 있다. NSObject 클래스도 init 메소드를 제공하는데 이것은 단순히 자기 자신, 즉 self를 돌려주는 역할을 한다.
실제로 프로그램을 작성할 때 파운데이션 프레임워크 내의 수많은 클래스를 가져다 쓰게 되는데, 클래스마다 초기화 메소드의 이름이 다른 경우가 많으므로 관련 문서에서 그 이름 및 사용 방법을 정확히 숙지한 후 사용하는 것이 좋다. 메모리 할당과 초기화를 동시에 수행하는 메소드도 많다.
5-1-1 . 초기화 메소드 구현하기
초기화 메소드를 구현하는 방법 및 제약 사항은 다음과 같다.
*이름은 init으로 시작한다. -> initWithFormat: initWithObjects: initWithFrame;
*리턴 타입으로 id를 사용한다.
–이것은 해당 클래스를 상속한 자식 클래스도 초기화 메소드를 사용하기 때문이다. 클래스에 따라 리턴 타입이 달라져야 하므로 모든 타입을 다룰 수 있는 id 타입을 사용해야 한다.
*반드시 부모 클래스의 초기화 메소드를 직접 또는 간접으로 호출해야한다.
클래스의 초기화 메소드는 그 부모 클래스의 초기화 메소드를 호출하고, 다시 부모 클래스의 부모 클래스의 초기화 메소드를 호출하고 이런식으로 결국에는 루트 클래스인 NSObject의 초기화 메소드까지 모두 호출되게 된다.
*부모 클래스의 초기화 메소드가 반환하는 값을 self에 할당한다.
클래스 인스턴스의 변수는 크게 '상속을 통해 생성된 인스턴스 변수'와 현재 클래스에서 생성한 인스턴스 변수'로 나뉜다. '상속을 통해 생성된 인스턴스 변수'는 이 과정을 통해 초기화된다.
ex) self = [super initWithFrame:frame]; //부모(super)의 초기화 함수 initWithFrame에 frame인자를 넘겨주며 생성된 객체를 자신이(self)가 받는다.
*인스턴스 변수에 값을 설정할 때 해당 변수에 값을 설정하는 메소드를 호출하는 것보다는 직접 값을 넣는 것이 좋다. 메소드가 실행되는 도중에 예상치 못한 오류가 발생할 수도 있기 때문이다.
*초기화 메소드를 종료할 때 반드시 self를 반환한다.
-초기화 메소드를 구현한 예이다.
@implementation Rectangle
-(id)init{
return [self initWithWidth:10 height:20];
}
-(id)initWithWidth:(NSInteger)myWidth height:(NSInteger)myHeight{
if(self = [super init])
{
name = nil
width = myWidth;
height = myHeight;
}
Return self;
}
…
@end
우선 부모 클래스의 초기화 메소드를 호출하고 반환값을 self에 할당한다. 그리고 인스턴스 변수를 별도의 메소드를 사용하지 않고 직접 값을 대입하여 초기화한다. 마지막으로 초기화된 self를 반환한다.
위 예의 클래스는 NSObject를 상속하고 있기 때문에 init 메소드를 호출하고 있는데, 다른 경우에는 부모 클래스의 초기화 메소드 이름을 알아내서 호출해야 할 수도 있다.
initWithWidth:height: 메소드에서 부모 클래스의 초기화 메소드가 돌려주는 반환값을 검사하는 것은 해당 메소드가 실패하여 nil을 반환하는 경우를 처리하기 위해서다. 일반적으로 조건문을 사용하여 그 반환값이 유효한 경우에만 다음 작업을 수행하도록 한다.
5-1-2.메모리 할당과 초기화의 결합
파운데이션 프레임워크의 많은 클래스는 메모리 할당과 초기화를 동시에 수행하는 메소드를 제공한다.
즉, 메모리 할당 메소드와 초기화 메소드를 별도로 호출하지 않고 하나의 메소드로 처리하는 것이다. 이러한 클래스 메소드들은 일반적으로 다음과 같이 클래스 이름으로 시작되는 이름을 가진다.
*NSString
+(id)stringWithCString:(const char *)cString encoding:(NSStringEncoding)enc;
+(id)stringWithFormat:(NSString *)format, ….;
*NSArray
+(id)array;
+(id)arrayWithObject:(id)anObject;
+(id)arrayWithObjects:(id)firstObj, …;
이 메소드들의 반환 타입이 id인 이유는 초기화 메소드가 반환 타입으로 id를 사용하는 것과 같다.
5-2.객체 사용하기 (메모리 관리)
모든 클래스 인스턴스들은 자신이 사용되고 있는 횟수를 알려주는 레퍼런스 카운트(참조 카운트)를 내부에 가지고있다. 이 값은 처음 생성될 때 1이 되고, 쓰이는 곳이 늘어나고 줄어들 때마다 그 값이 증가하고 감소한다. 만약 레퍼러스 카운트가 0이 되면 해당 객체는 메모리에서 해제된다.
객체의 레퍼런스 카운트를 변화시키는 메소드들은 다음과 같다. 메소드 앞에 _가 있으면 클래스 메소드, -이면 인스턴스 메소드다.
메소드
동작
+alloc
인스턴스를 생성 하고
레퍼런스 카운트를 1로 만든다.
-copy
-retain
레퍼런스 카운트를 1 증가시킨다.
-release
레퍼런스 카운트를 1 감소시킨다.
-dealloc
객체를 지운다. 레퍼런스 카운트가 00이 되는 순간 자동으로 호출된다.
+alloc과 –copy메소드는 새로운 인스턴스를 생성한다. 따라서 새로 생성된 인스턴스의 레퍼런스 카운트는 1이된다.
-retain 메소드는 이미 생성되어 있는 클래스 인스턴스를 사용한다. 따라서 해당 인스턴스의 레퍼런스 카운트가 1증가한다.
-release 메소드는 사용중인 인스턴스를 제거한다. 따라서 해당 인스턴스의 레퍼런스 카운트가 1감소한다.
-dealloc 메소드는 변수가 사용하던 메모리를 해제한다.모든 객체가 공통으로 가지고 있는 메소드이다. 이 메소드는 직접 호출되는 것이 아니라 인스턴스의 레퍼런스 카운트가 0이 될대 자동으로 호출된다.
ex) Rectangle 클래스의 인스턴스 anObject의 레퍼런스 카운트 변화를 살펴보자
Rectangle *anObject = [[Rectangle alloc] init]; //+alloc메소스 호출에 인스턴스가 생성, 레퍼런스 카운트 1이됨
[anObject retain]; //(2)-retain메소드가 호출되어 레퍼런스 카운트가 증가하여 2가 됨
[anObject release]; //(3)-release 메솓드가 호출되어 레퍼런스 카운트가 감소하여 1이 됨
[anObject release]; //(4)-release메소드가 호출되어 레퍼런스 카운트가 감소하여 0이 됨.
//이때 카운트가 0이므로 –dealloc 메소드가 자동으로 호출됨
ex-2) 실제 상황에 가까운 예
Rectangle *anObject1 = [[Rectangle alloc] init]; //+alloc메소스 호출에 인스턴스가 생성, 레퍼런스 카운트 1이됨
Rectangle *anObject2 = [anObject1 retain]; //anObject1의 retain메소드가 호출되어 레퍼런스 카운트가 증가하여
//2가 되며, 그 메모리 주소가 반환되어 anObject2는 anObject1와 같은
//인스턴스를 가리키게된다. 그러므로 레퍼런스 카운트는 그대로 2를 유지
[anObject2 relese]; //anObject1과 anObject2는 같은 주소값의 레퍼런스 카운트를 가지게되어 1이 된다.
[anObject1 release]; // anObject1과 anObject2는 같은 주소값의 레퍼런스 카운트를 가지게되어 0이 되며
// 두다이때 카운트가 0이므로 –dealloc 메소드가 자동으로 호출됨
[anObject1 setWidth:20 height:40]; //이미 제거되어 유효하지 않으므로 런타임 에러 발생
5-3 객체 제거하기 (메모리 해제)
5-3-1. 지역 변수의 메모리 해제
-(void)testMethod {
Rectangle *anObject1 = [[Rectangle alloc] init]; //메모리할당
….
[anObject1 release]; //메소드를 빠져나오기전에 메모리 해제
}
5-3-2 인스턴스 변수의 메모리 해제
인스턴스 변수는 일반적으로 클래스 인스턴스가 생성될 때 메모리를 할당하고, 해당 인스턴스가 소멸할 때 메모리를 해제한다.(모두 경우에는 그러한 것은 아니다)
소멸자는 아래와 같이 구현하는데 순서를 절대 바뀌지 않도록 주의
@implementation Rectangle
….
-(void)dealloc
{
[name release]; //자신의 맴버에 할당한 메모리 해제 NSString * name
[super dealloc]; //부모객체 의 dealloc 호출. 순서는 꼭 지켜야한다.
}
-소멸자에 의하지 않고 다른 메소드에서 메모리 해제가 일어나는 경우는 드물지 않다.
@implementation Rectangle
….
-(void)setName:(NSString *)myName{
if(name !=myName){
[name release]; //(인스턴스 변수에 할당되어 있는 메모리를 해제한다.)
Name = [myName retain]; //인자로 넘어온 객체를 retain하여 레퍼런스카운트 하나 증가시키고
//그 메모리 값을 인스턴스 변수에 넣는다.
}
}
5-3-3.자동으로 메모리 해제하기
메모리해제하는 적절한 시점이 애메할 때
autorelease 메소드를 사용하면 미래의 어느 시점에 메모리를 해제한다.
@implementation Rectangle
….
-(NSString *)description{
NSString *text = nil;
text = [[NSString alloc] initWithString:@"Text"];
[text autorelease];//[text release];로하면 바로 메모리가 해제된다.
return text;
}
…
@end
일반적으로 autorelease 메소드를 별도의 메모리 해제 과정이 필요하지 않다. 사용은 새로 생성한 객체를 반환할 때 주로 사용한다.
라이브러리 같은 곳에서 autorelease 인지아닌지 확인하는 방법은 규칙을 지키고 있다.
규칙-1. apthem 이름이 alloc 또는 copy로 시작하는 경우 메모리 해제 작업을 실행해야한다.
NSString *text = [[NSString alloc]initWithString:@"Test"];
[text release];
규칙-2. 메소드 이름이 alloc 또는 copy로 시작하지 않는 경우 autorelease되므로 별도의 메모리해제작업이 필요없다.
NSString *text = [NSString stringWithString:@"Test"];
autorelease 로 해제되는 시점은?
int main(int argc, char *argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //(1)Autorelease Pool생성
int retVal = UIApplicationMain(argc, argv, nil,nil);
[pool release]; //(2)Pool에 저장되어 있던 메모리해제작업
return retVal;
}
(1). Autorelease Pool 생성 한다. 이 이후 autorelease를 호출하는 모든 객체는 이 Pool에 저장된다.
(2). 이때 Pool에 저장되어 있던 객체에 대해 메모리 해제 작업이 실행된다.
6. 프로퍼티 선언과 구현
6-1.프로퍼티 선언하기
일반적으로 클래스에서 인스턴스 변수를 사용하려면 두개의 메소드(이 둘을 묶어서 '접근메소드'라고 부르기도한다') 두 메소드는 하나는 값을 설정하는 메소드 또하나는 값을 읽어오는 메소드다.
-프로퍼티 선언 .h
#import <Foundation/Foundation.h>
#import "Shape.h"
@class Circle;
@interface Rectangle : Shape {
@protected
NSString *name;
NSInteger width;
NSInteger height;
}
@property NSString *name;
@property NSInteger width;
@property NSInteger height;
…..
@end;
@property (속성) 타입 이름;
즉 @property 지시어를 사용하면 젭근 메소드가 자동으로 선언된다. 값을 읽어오는 메소드의 이름은 앞에 get이 붙지 않고 인스턴스 변수와 같은 이름을 사용하게 되며, 값을 설정하는 메소드의 이름은 앞에 set이 붙고 변수 이름의 첫 문자가 소문자에서 대문자로 바뀌게 된다.
6-2.프로퍼티속성
6-2-1.접근 프로퍼티 메소드 이름 변경
접근 메소드의 이름을 변경하는 프로퍼티 속성은 다음의 두 가지 중 하나이다.
getter=메소드이름 값을 읽어오는 메소드의 이름을 변경한다.
setter=메소드이름 값을 설정하는 메소드의 이름을 변경한다.
@property (getter=getName) NSString *name;
6-2-2.읽기/쓰기 권한
접근 메소드의 사용 권한을 조정하는 속성은 다음과 같다.
readwrite 값을 읽어오는 메소드와 값을 설정하는 메소드를 모두 사용할 수 있게한다.
readonly 값을 설정하는 메소드는 사용할 수 없게 만든다.
@property (readonly)NSString *name;
6-2-3. 값을 설정하는 메소드의 특성
assign 전달받은 인자에 대해 assign 기능을 수행하고 그 반환값을 인스턴스 변수에 설정 (기본값)
retain 전달받은 인자에 대해 retain 기능을 수행하고 그반호나값을 인스턴스변수에 설정
인스턴스의 레퍼런스 카운트가 1증가한다.
copy 전달받은 인자에 대해 copy 기능을 수행하고 그 반환값을 인스턴스 변수에 설정
@property (retain)NSString *name;
6-2-4. 스레드 안전성
멀티 스레드 한경을 고려할것인지 아닌지 결정하는 속성
atomic 접근 메소드를 호출할 때 멀티 스레드 환경을 고려한다. 기본값
nonatomic 접근 메소드를 호출할 때 멀티 스레드 환경을 고려하지 않는다. (성능은 좋다)
@property (retain, nonatomic) NSString *name;
6-3. 프로퍼티 구현하기(.m에 구현)
@synthesize 변수; : 헤더 파일에서 property 지시어로 선언한 인스턴스변수다. 사용자 해당 프로퍼티에 대한 접근 메소드를 제공하지 않으면 컴파일러가 자동으로 메소드를 생성한다. ex) @synthesize name;
@dynamic 변수; : 이것은 프로퍼티에 대한 접근 메소드를 사용자가 직접 구현하거나 프로그램이 실행될 때 동적으로 로드해서 사용하겠다고 컴파일러에게 알리는 효과가 있다. ex) @dynamic name;
주의할점은 헤더파일의 @property 지시어와 소스파일의 @synthesize 지시어가 항상 쌍으로 존재해야한다.
@import "Rectangle.h"
@implementation Rectangle
@synthesize name;
@synthesize width;
@synthesize height;
요약
@property type c; //선언
@synthesize c = a; //연결 변수 a를 프로퍼티 c에 연결
6-4. .을 사용하여 접근 메소드 호출하기
두 방식은 완벽하게 같은 작업을 하는 코드 (width는 프로퍼티 이름)
oldWidth = myRectangle.width;
myRectangle.width = 10
oldWidth = [myRectangle width];
[myRectangle setWidth:10]
'Objective_C' 카테고리의 다른 글
[Objective-C] 기초배우기 (4) (0) | 2020.04.14 |
---|---|
[Objective-C] 기초배우기 (3) (0) | 2020.04.14 |
[Obejective-C] 기초배우기 (1) (0) | 2020.04.13 |
1.메시지 문법
C++ : Reveiver.MessageWithOptionAandOptionB(23,23,23);
Objective-C : [Reveiver Message:23 withOptionA:23 WithOptionB:23]; //이름을 중간에 띄어서 처처리한다 생각하면될 듯
2. nil값을 가지는 클래스 인스턴스의 메소드 호출하지
Rectangle *anObject = nil;
[anObject description];
nil는 다른 언어의 'NULL' 과 동일한 개념
위 예제는 nil 값을 가지는 anObject 인스턴스의 description 메소드를 호출한다. 다른 언어에서는 당연히 런타임 에러가 발생하지만 Objective-C는 에러로 처리하지 않고 정상적 동작으로 인식하고 처리한다. 이값은 경우 메소드 호출 결과로 nil을 돌려준다
3. Objective-C의 데이터 타입
3-1. id 타입
id anObject;
id 는 Objective-C의 기본 데이터 타입이다. 이건 모든 종류의 객체들을 다룰수 있다.
참고로 일반적으로 id의 형태로 사용되고 id* 와 같은 형태로는 잘 사용되지 않는다.
3-2. BOOL 데이터타입
BOOL flag = YES;
if(flag ==YES){
flag = NO;
}
3-3. 함수 포인터 데이터 타입
Objective-C 는 C의 함수 포인터와 유사한 개념으로 'SEL' 이라는 데이터 타입을 지원한다. 이것은 @selector 지시어와 임의의 메소드 이름을 사용하여 값을 설정한다.
이때 메소드 이름에 콜론도 포함되는 것을 일지 말아야한다.
//함수 선언
-(void)setWidth:(NSInteger)myWidth height:(NSInteger)myHeight;
-(void)setCallback:(SEL)callback;
//함수 호출
SEL anObject = @selector(seWidth:height:);
[self setCallback:anObject];
[self setCallback:@selector(setWidth:height:)];
3-4 Objective-C의 클래스
3-4-1 클래스의 상속
-단일 클래스로부터의 상속 기능만 지원,
3-4-2 NSObject 클래스
-부모 클래스가 없는 루트 클래스인 NSObject는 Objective-C의 객체들을 위한 기본 프레임워크로, 객체 사이의 상호 작용을 정의한다.
그래서 이를 상속하는 클래스가 객체로 동작하게 하고, 런타임 시스템과 상호동작할수 있도록 해준다.
다른 클래스와 특별한 연관관계가 없는 클래스도 그것을 생성할 때는 반드시 NSObject를 상속해야한다.
클래스의 인스턴스들이 실행될 때 최소한 Objective-C의 객체로서 동작할 수 있어야 하기 때문에 클래스를 새로 설계할 떄 NSObject를 기본적으로 상속해야 함을 절대로 잊지말자. 만일 아무런 클래스도 상속하지 않는 독자적인 클래스를 만들게 되면 이 클래스는 Objective-C의 객체가 가져야 하는 기본적인 성질들을 가질 수 없게 된다.
3-4-3. 인스턴스 변수의 상속
한 클래스로부터 인스턴스를 만들면 , 그 인스턴스에는 해당 클래스에 정의되어 있는 인스턴스 변수는 물론 그 부모 클래스의 인스턴스 변수 그리고 또 부모의 부모 클래스의 인스턴스 변수까지, 최종적으로 루트 클래스의 인스턴스 변수까지 모두 포함된다.
3-4-4. 메소드의 상속
부모 클래스를 상속하는 자식 클래스는 부모 클래스뿐 아니라 최종적으로 루트 클래스에 이르기까지 상위에 있는 모든 클래스의 메소드들을 상속받아 사용할 수 있다. 즉 파운데이션 프레임워크 내의 한 클래스를 상속하면 해당 클래스 및 그 상위 클래스들이 가지고 있는 메소드들을 모두 사용할 수 있으며, 추가로 필요한 메소드만 선언하면된다.
3-4-5. 메소드 오버라이딩
메소드 오버라이딩(Overriding)이란 자식 클래스에서 부모 클래스의 메소드를 재정의해서 사용하는 것이다. (다른언어와 동일) 이를 통해 메소드의 동작을 완전히 재정의하거나 새로운 기능을 추가할수 있다.
아래의 코드는 자식 클래스에서 부모 클래스의 메소드(draw)를 오버라이딩하는 전형적인 예를 보여준다. 우선 부모 클래스의 메소드를 호출하여 원래 이메소드에 구현되어 있던 동작을 수행하고 이어서 새로운 기능을 수행하는 방식이다. 부모 클래스의 메소드를 호출할 때 super 지시어를 사용해야 한다는 점을 유의하자,.
-(void)draw{ //1.부모 클래스의 해당 메소드를 호출한다.
[super draw]; //2.새로운 기능을 추가한다.
}
단, Objective-C에서는 메소드 오버로딩(Overloading)은 지원하지 않음을 기억해두자
(오버로딩은 메소드의 이름은 같지만 입출력 값의 타입은 다르게 선언하는 것을 말한다.
3-4-6. 클래스의 생성
id myRectangle = [[Rectangle alloc] init];
alloc 메소드는 Rectangle 클래스의 인스턴스 변수들에 메모리를 할당하고 이를 리턴하게 된다.
그런데 이때 인스턴수들의 변수들을 모두 0의 값을 가지게 되므로 init 메소드를 호출하여 초기화를 수행해야함
실제로 모든 클래스는 메모리를 할당하고 초기화 하는 메소드를 적어도 하나 이상 가지고 있다. 파운데이션 프레임워크의 클래스들을 살펴보면 주로 사용하는 초기화 메소드의 이름 및 인자의 개수 등은 조금씩 다르지만 일반적으로 init으로 시작하는 이름의 초기화 메소드가 있음을 알수 있다.
3-4-7 클래스 타입
Rectangle *myRectangle = [[Rectangle alloc] init];
id idRectangle = myRectangle; // id 타입 변수에 저장가능
id는 Objective-C의 기본 데이터 타입이며, 어떠한 클래스도 이와 같은 방식으로 사용할 수 있다. 실제 프로그래밍에서 여러 클래스의 인스턴스를 사용하는 경우 이처럼 id 타입의 변수를 이용하는 것이 유용한 경우가 많다.
만약 Rectangle 의 부모가 Shape 라면 아래처럼도 가능한다.
Shape *myGraphic = myRectangle;
3-4-8. 타입 검사
-isKindOfclass & isMemberOfClass 는 NSObject 클래스를 상속하는 모든 클래스에서 이용할수 있다.
//딱 그 특정클래스의 인스턴스인지 알아내는 기능
if([anObject isMemberOfClass:[Shape class]]{ …}
//특정클래스 또는 그 하위에 속한 클래스인지 알아내는 기능
if([anObject isKindOfclass:[Shape class]]){…}
3-4-9. 동일성 검사
//두 인스턴스가 실제로 같은 메모리 주소를 가리키는 동일 인스턴스인지를 검사 같은 경우 참
if(anobject1 ==anObject2){ ..}
//메모리주소가 아닌 실제 두 객체가 가지고 있는 인스턴스 내의 값들이 같은지 검사하고 같은 경우 참
if([anObject1 isEaual:anObject2]){..}
3-4-10.메소드 검사
respondsToSelector : 메소드는 (NSObject에서 사용 가능) 인자로 받는 메소드가 자신을 호출하고 있는 객체내에서 정의되어 있는지 여부를 검사하는 역할을 수행
id anObject =nil;
…
if([anObject respondsToSelector:@selector(draw)])
{..}
anObject 인스턴스 안에 draw 메소드를 가지고 있는지 파악
4.클래스 선언 및 정의하기
4-1.헤더 파일과 소스파일 분리
.h 파일: 헤더파일
.m 파일: 소스파일
.mm 파일: C++소스를 포함하거나 참조하고 있는 파일
4-2.헤더 파일
#import<Foundation/Foundation.h>
#import "Shape.h" //(1)
@class Circle; //(2)
@interface Rectangle : Shape { //(3)
NSString *name; //(4)
NSInteger width;
NSInteger height;
}
-(NSString *)description; //(5)
-(void)setName:(NSString*)myName;
-(void)setWidth:(NSInteger)myWidth height:(NSInteger)myHeight;
-(void)draw;
'Objective_C' 카테고리의 다른 글
[Objective-C] 기초배우기 (4) (0) | 2020.04.14 |
---|---|
[Objective-C] 기초배우기 (3) (0) | 2020.04.14 |
[Objective-C] 기초배우기 (2) (0) | 2020.04.14 |