iOS 개발일지
Objective-C에 대해 아주아주 간단히 알아보자 본문
Objective-C를 공부하게 될 줄은 몰랐는데, 해야만 하는 상황이 생겼다.
오래된 언어라서 그런지 마땅한 강의도 없고, 회사에 있는 10년도 더 된 책을 읽으며 공부하고 있다.
읽다가 이해가 가지 않는 개념은 구글링해서 여러 블로그도 참고하고, 그렇게 읽기만 하다가...
역시 코드는 쳐봐야 맛이지! 간단하게 일단 쳐봤다.
공부해본 언어라곤 Python 한스푼과 Swift밖에 없는 나에게 너무 생소한 생김새였다. 세미콜론부터가...
이름에서 유추할 수 있듯이 C 언어를 기반으로 만들어졌다고 하니, C 를 아는 사람에게는 이해가 더 수월할 수도 있겠다.
보다시피 objc 파일은 이렇게 h와 m으로 나누어진다.
선언과 구현을 한번에 하는 swift와는 다르게, objc는 선언을 헤더 파일에서 쫘르륵 하게 되어 있다.
그리고 import를 통해 헤더 파일과 소스 파일을 연결지어 사용한다.
ViewController와 UIKit의 import 방식이 조금 다른데, 차이점은 시스템에서 구현했느냐 아니냐 이다.
시스템에서 구현한 헤더 파일은 <> 를 통해, 개발자가 구현한 헤더 파일은 "" 를 통해 import 할 수 있다.
경우에 따라 한 소스 파일에 정말 많은 헤더 파일을 import 할 수 있는데, 주의점은 소스 파일은 import 하지 않는다는 것이다.
소스 파일에 작성되어있는 코드를 사용하려 할 땐 헤더 파일만을 import해 접근하면 된다.
아래는 Rectanglel 이라는 클래스를 선언한 것으로, 클래스를 만들고 싶을 땐 NSObject를 상속받으면 된다.
@interface 키워드와 @end 사이에 있는 것들이 Rectangle 클래스의 멤버이다.
int 타입의 width와 height는 그래도 눈에 읽히는데, 그 아래에 있는 것들은 뭘까?
우선 @property부터 설명하자면, 프로퍼티에 대한 getter와 setter를 자동으로 생성해주는 지시어이다.
objc에서는 별도로 getter와 setter메서드를 선언해줘야 하는데, @property를 사용하면 아주 간결하게 해결할 수 있다.
그 아래의 - (int) area 와 - (int) perimeter 는 메서드의 선언이다.
objc에서는 - 메서드와 + 메서드가 있는데, 각각 인스턴스 메서드와 클래스 메서드를 의미한다.
일반적으로는 우리에게 익숙한 인스턴스 메서드를 사용하며, 클래스 메서드는 타입 메서드와 유사하다.
그 뒤에 따라오는 int는 반환형으로, 메서드를 실행했을 때 int를 return 한다는 의미이다.
선언은 이것으로 끝났지만, 선언만 가지고서는 아무것도 할 수 없다.
실제로 동작하게 될 코드는 @implementation 아래에서 구현한다.
@synthesize는 @property와 한쌍이라고 생각하면 된다.
@property는 어디까지나 선언이기 때문에, 실제 getter와 setter는 @implementation에서 구현해야 한다.
다시 말해, @property를 사용하는 것은 컴파일러에게 getter와 setter의 구현을 기대하게 만드는 작업일 뿐인 것이다.
여기서 @synthesize를 사용하면 자동으로 getter와 setter를 구현해주기 때문에 매우 편리하다.
메서드의 구현 코드는 매우 직관적이라고 생각해 설명하지 않겠다.
자 마지막으로 실행 코드다.
코드가 잘 작성되었는지 확인만 하면 되므로, viewDidLoad에서 다 호출해봤다.
첫 줄부터 어지럽다...!
objc를 처음 보고 가장 당황했던 것이 저 뜬금없는 대괄호였다.
저 대괄호는 objc에서 멤버에 접근하는 방식이라고 생각하면 편하다.
rectangle.width와 [rectangle width] 는 같은 코드인데, 소스 코드를 보면 []를 더 많이 쓰는 것 같다.
이걸 알고 보면 대강은 읽을 수 있게 되는데, 문제는 클래스의 인스턴스를 생성하는 코드이다.
Rectangle *rectangle = [[Rectangle alloc] init];
자!! 우선 앞의 Retangle은 당연히 클래스를 의미한다.
objc에서는 이름보다 타입이 앞에 오게 되므로, " Rectangle 타입을 생성할 건데~ 이름은 rectangle이야~ " 정도가 되겠다.
중간에 붙은 *은 참조 타입을 의미한다.
스페이스가 저렇게 들어가 있어서 처음엔 *rectangle 로 읽었지만, Rectangle *로 보는 것이 더 옳을 것 같다.
[[Rectangle alloc] init] 은, 그냥 생성자를 호출하는 부분으로, 풀어서 쓰면 이렇게 된다.
Rectangle *rectangle = [Rectangle alloc];
rectangle = [rectangle init];
첫번째 줄 : alloc을 통해 Rectangle을 생성했지만, 사용하기에는 아직 초기화가 덜 된 상태
두번째 줄 : init을 통해 rectangle을 초기화시켜 사용할 수 있는 상태
[Rectangle init] 이 아닌 [rectangle init] 인 이유는... 간단하게 말해 위에서 생성한 객체를 초기화 해주는 것이다.
만약 [Rectangle init] 이라고 입력하면 우선 이런 에러가 발생한다.
생성하지도 않은 날것의 클래스를 init 하려고 했으니 에러가 난다고 이해하면 될 것 같다.
생긴건 어렵게 생겼지만 계속해서 쓰이기 때문에 눈에 익게 되므로, 그냥 그렇구나~ 하고 형태를 기억하는 것이 좋다.
인스턴스를 생성했으니 이제 프로퍼티에 접근해 width와 height를 설정해주는 코드를 살펴보자.
[rectangle setWidth: 10];
[rectangle setHeight: 30];
NSLog(@"width: %i", rectangle.width);
NSLog(@"height: %i", [rectangle height]);
objc가 자동으로 만들어준 getter는 프로퍼티의 이름으로만 접근하면 되지만, setter는 아래와 같이 set 키워드가 자동으로 붙는다.
NSLog는 print와 같은 기능을 하며, 큰따옴표 내부의 문자열은 String이 아닌 NSString 타입이기 때문에 앞에 @를 붙여줘야 한다.
%i 는 int 타입을 의미하며 (타입마다 %d, %f 등 여러가지가 있다), 넣어줄 실제 값은 콤마로 분리해 뒷쪽에 작성한다.
메서드는 프로퍼티보다 더 간단하다.
전달받는 인자가 없어서 그렇기도 하지만, 있어도 딱히 다르지 않을 것이다.
int area = rectangle.area;
int perimeter = rectangle.perimeter;
NSLog(@"area: %i", area);
NSLog(@"perimeter: %i", perimeter);
위에서 설정해준 width와 height을 통해 넓이와 둘레를 구하는 함수를 호출했다.
여기서 끝은 아니고, 매우 중요한 작업이 하나 남아있다.
swift는 ARC를 통해 메모리를 관리하지만 objc는 MRC를 통해 관리한다.
자동이 아닌 수동이라는 의미이다.
NSLog(@"retainCount: %lu", (unsigned long)rectangle.retainCount);
[rectangle release];
아까 참조 타입인 Rectangle을 alloc 및 init 해주었기 때문에, RC가 하나 늘었을 것이다.
수동 관리를 하기 때문에 retainCount (R이 Referance가 아닌 Retain 이다!) 를 직접 확인할 수도 있다.
아무튼, 이렇게 release를 통해 RC를 0으로 만들어 참조 해제를 해주었다.
MRC는 중요한 개념이라 여기서 한번에 설명하기는 힘들 것 같아, 기회가 된다면 따로 포스팅할 예정이다.
이제 생성해둔 모든 멤버에 접근하고, 사용해봤다.
로그는 예상되는대로, 이렇게 뜬다.
참고) 만약 이런 에러가 발생한다면...
TARGETS - Build Phases - Compile Sources 에서 에러가 발생하는 파일을 찾아
-fno-objc-arc
라고 입력해주면 정상적으로 빌드된다.
끝!!!!!!!!!!
Objc... 정말... 약간... 구닥다리 같긴 하지만... 보다보니 또 정드는 느낌이다ㅎ...
'iOS' 카테고리의 다른 글
[iOS] WKWebView의 현재 URL을 감지하고, 이벤트를 발생시키자! (0) | 2023.11.27 |
---|---|
(비공개) (0) | 2023.06.15 |
iOS 비동기/동시성 프로그래밍에 대해 알아보자! (1) | 2023.02.03 |
SDK, Framework, Library, API 용어 정리 (0) | 2023.01.30 |
iOS 14 이상 버전에서 IDFA 권한 요청하기 (1) | 2023.01.29 |