Objective-C 기본 문법 복습 - 2

준우·2024년 7월 24일

Objective-C 이야기

목록 보기
14/19
post-thumbnail

Advanced Grammer

Class

  • Class 예제 h.file
// h.file
@interface Car : NSObject

@property NSString *name;
@property Boolean isOn;

-(void)turnEngineOn;

// init - override
- (instancetype) initWithState : (Boolean) starState;

@end
  • Class 예제 m.file
@implementation Car
- (void)turnEngineOn {
		_isOn = true;
}

- (instancetype) initWithState : (Boolean) starState {
		self = [super init];
		_isOn = starState;
		return self;
}

@end
  • Class 사용 예제
Car *jeep = [[Car alloc] init];
Car *corolla = [[Car alloc] initWithState: true];

Delegatation in Objective-C

  • Protocol 생성
@protocol sendingMessageProtocol <NSObject>

- (void) send: (NSString *)message;

@end
  • ViewController.h
#import "Protocol.h"

@interface ViewController : UIViewController <sendingMessageProtocol>

@end
  • ViewController.m
- (void) send: (NSString *)message {
		receiveMessageLabel.text = message;
}

GreenViewController 인스턴스.delegate = self;
  • 위임받은 ViewController.h

여기서는 GreenViewController → ViewController 로 데이터를 보내기 때문에, GreenViewController 가 위임받은 ViewController 입니다.

@property (nonatomic) id <sendingMessageProtocol> delegate;

// Swift
var delegate: sendingMessageDelegate
  • 위임받은 ViewController.m
[self.delegate send: textToSend];

Category

  • Category h.file
@interface NSString (Reverser)

-(NSString *)reverseIt;

@end
  • Category m.file
@implementation NSString (Reverser)

-(NSString *)reverseIt {
		NSMutableString *result = [NSMutableString new];
		NSInteger stringLength = [self length];
		
		while (stringLength > 0) {
				stringLength --;
				
				NSRange substringRange = NSMakeRange(stringLength, 1);
				NSString *prevChar = [self substringWithRange:substringRange];
				[result appendString: prevChar];
		}
		
		return result;
}
@end
  • Category 사용 예제
NSString* helloString = @"Hello World";
NSString *reverseString = [helloString reverseIt];

Atomic & nonAtomic

atomic과 nonatomic은 속성의 쓰레드 안전성에 관련된 키워드

  • atomic
    • 동기화된 접근: atomic 속성은 기본적으로 쓰레드 안전성을 보장합니다.
      즉, 여러 쓰레드에서 동시에 속성에 접근할 때 데이터의 일관성을 유지합니다.

    • 기본 설정: 별도로 지정하지 않으면, 속성은 atomic으로 설정됩니다.

    • 성능: atomic 속성은 동기화 오버헤드로 인해 nonatomic보다 느립니다.

    • 특징: atomic 속성은 '모든 쓰레드에서 속성을 읽거나 쓸 때 완전히 완료된 접근'을 보장합니다.
      이는 속성 접근 시 잠금(lock) 메커니즘을 사용하여 구현됩니다.

      @property (atomic, strong) NSString *atomicString;
  • nonatomic
    • 비동기화된 접근: nonatomic 속성은 쓰레드 안전성을 보장하지 않습니다.
      즉, 여러 쓰레드에서 동시에 속성에 접근할 때 데이터의 일관성이 깨질 수 있습니다.

    • 성능: nonatomic 속성은 동기화 오버헤드가 없기 때문에 atomic보다 빠릅니다.

    • 특징: nonatomic 속성은 주로 성능이 중요한 상황에서 사용됩니다.
      쓰레드 안전성을 개발자가 직접 관리해야 합니다.

      @property (nonatomic, strong) NSString *nonatomicString;

readOnly & readWrite

readOnly

readonly 키워드는 속성을 읽기 전용으로 만듭니다.
이 속성은 값이 설정된 후 변경할 수 없으며, 자동으로 setter 메서드가 생성되지 않습니다.

@property (nonatomic, readonly) NSString *readOnlyString;

readWrite

readwrite는 속성을 읽기/쓰기 가능하게 만듭니다.
이는 기본값이므로 명시적으로 지정하지 않아도 됩니다. setter와 getter 메서드가 자동으로 생성됩니다.

@property (nonatomic, readwrite) NSString *readWriteString;

Class Method

Objective-C 에는 Class Method 라는 것이 존재합니다. + 를 사용하여 메서드를 생성하는 것입니다.

기존에 - 를 사용하면 인스턴스 메서드라고 하는데, 이는 인스턴스에 접근하여 메서드를 사용합니다.

  • 는 Swift 의 static 과 유사합니다. 클래스에 접근하여 메서드를 사용하기 때문입니다.
  • Class h.file
@interface MyClass: NSObject {
+(void)doSomething;
@end
  • Class m.file
@implementation MyClass
+(void)doSomething {
	// 클래스 메서드 내부 구현
}
@end

Class Method 와 Instance Method 비교

  • Class Method(+)
+ (void)classMethod {
    // 클래스 메소드 구현
}
  • Instance Method(-)
- (void)instanceMethod {
    // 인스턴스 메소드 구현
}
  • Class Method 와 Instance Method 사용 예제
// 클래스 메소드 호출
[MyClass sayHello];

// 인스턴스 생성 및 인스턴스 메소드 호출
MyClass *myInstance = [[MyClass alloc] init];
[myInstance greetWithName:@"Objective-C"];

Reference Count

Strong

기본 참조 방식으로, 객체에 대한 강한 참조를 나타냅니다. 객체의 참조 카운트를 증가시키며, 이 객체에 대한 모든 강한 참조가 해제될 때까지 객체가 메모리에서 해제되지 않습니다.

@property (nonatomic, strong) MyClass *myObject;

Weak

객체에 대한 약한 참조를 나타냅니다. 객체의 참조 카운트를 증가시키지 않으며, 객체가 메모리에서 해제되면 참조가 자동으로 nil로 설정됩니다. 주로 강한 참조 순환을 방지하기 위해 사용됩니다.

@property (nonatomic, weak) MyClass *myObject;

Retain

Objective-C의 MRC(Manual Reference Counting) 시절의 속성으로, 객체의 참조 카운트를 증가시킵니다. ARC(Automatic Reference Counting)를 사용하는 경우 strong으로 대체되었습니다.

@property (nonatomic, retain) MyClass *myObject;

Assign

객체에 대한 단순한 참조를 나타내며, 참조 카운트를 증가시키지 않습니다. 주로 기본 데이터 타입(예: intfloat)이나 weak를 사용할 수 없는 경우에 사용됩니다.

@property (nonatomic, assign) NSInteger myInteger;

Copy

객체의 복사본을 생성하여 소유합니다. 주로 NSStringNSArray와 같은 불변 객체에 사용됩니다. 객체의 상태가 변경될 위험이 있는 경우 안전하게 사용할 수 있습니다.

@property (nonatomic, copy) NSString *myString;

SEL - 셀렉터

Obj-C 에서의 SEL 은 Swift에서 addTarget@selector 랑 똑같음.

형태는 아래와 같음.

SEL btnSelector = @selector(testBtnClicked:);

SEL 는 어디에 사용이 될까??

방금 앞서 말했듯이, Swift 에서 addTarget 에 들어가는 @selector 과 동일하다고 했음.

그럼 먼저 함수를 만들어 보아야겠죠??

아래 함수는 반환 값이 없는 함수이며, senderUIButton 을 입력받는 함수임.

그리고 NSStringFromSelector(_cmd) 는 현재 실행하고 있는 함수의 이름을 가져오는 것이고, _cmd 는 현재 실행되고 있는 셀렉터의 이름을 가져오는 것임.

- (void)onTestBtnClicked:(UIButton *) sender {
    // NSStringFromSelector(_cmd) : 현재 실행하고 있는 함수 이름을 가져옴.
    NSLog(@"name: %@ , btnTitle: %@", NSStringFromSelector(_cmd),
          sender.titleLabel.text);
}

함수를 만들었으니, 함수를 버튼과 인식을 시켜봅시당

코드는 아래와 같음.

간략하게 설명을 드리면, 위에 만들어두었던 함수를 SEL로 만들기 위해서는 @selector(함수) 이런식으로 포장을 해주어야함.

SEL btnSelector = @selector(onTestBtnClicked:);

[_selectorTestButton addTarget:self action:btnSelector forControlEvents:UIControlEventTouchUpInside];

근데, 우리는 왜 위 코드처럼 귀찮게 SEL로 포장해서 사용을 해야할까??

그걸 이해하기 위해서는 addTarget 의 문장 구성을 이해해야함.

- (void)addTarget:(id)target 
           action:(SEL)action 
 forControlEvents:(UIControlEvents)controlEvents;

addTarget : (id)target 라고 되어 있는데, 여기에는 간단히 self 로 쓰면됨.

action : (SEL) action 으로 되어 있는게 보임? (SEL) 로 만들어줘야 정상적으로 빌드가 되기 때문에, 우리는 @selector 에 함수를 넣어서 SEL을 만들어줘야함.

forControlEvents:(UIControlEvents)controlEvents 는 Swift 에서와 마찬가지로 .touchupInside 와 똑같다고 생각하면됨.

ID

Objc-C 에서의 id클래스 객체 인스턴스 메모리 주소 반환, 즉 포인터임.

코드는 아래와 같음.

// 여기 id 가 어떤 클래스의 인스턴스를 뜻함.
+ (id)getAFriend{
    
    Friend *aFriend = [[Friend alloc] init];
    
    [aFriend setNickname:@"호호호호호호호"];
    
    // Friend 생성하여 메모리 반환.
    return [[Friend alloc] init];
}

// 위 함수와 아래 함수는 동일함.
+ (Friend *)getMyFriend {
    
    Friend *aFriend = [[Friend alloc] init];
    
    [aFriend setNickname:@"내 친구임."];
    
    return aFriend;
}

Friend * 는 Friend 메모리 주소 자체를 반환하는 것이기 때문에 id 를 반환하는 것과 동일함.

Getter / Setter

Objc-C 에도 getter / setter 라는 함수가 존재함.

getter / setter 는 함수이기 때문에 사용할 때 [] 를 써야함.

getter

Objc-C 에서 getter 는 @property nickname 이라는 변수가 있다고 가정할 때, 그 값을 조회하는 것임.

[aNewFriend setNickname]; // getter

setter

Objc-C 에서 setter 는 @property nickname 이라는 변수가 있다고 가정할 때, 그 값을 새로운 값을 삽입하는 것임.

그런데, getter 와는 달리 setter 는 nickname 이 아니라, setNickname 임.

이유는 setter 를 사용할 때는 변수 앞에 set변수명(변수명 맨 앞은 대문자)로 해줘야함.

[aNewFriend setNickname: @"호호호"]; // setter

0개의 댓글