SWIFT, OBJECTIVE-C 프로그래밍 언어 장단점 특징

아주 오랜만에 프로젝트 진행을 위해서 Objective-C 언어를 사용해서 유지보수를 했습니다. 간단한 작업이지만 너무 낯설어서 시간이 조금 걸렸습니다. 한 3년만에 만져본 것 같습니다. 그런데 그러면서 한 가지 깨닳은 사실이 있습니다. Objective-C 언어도 멋지다! 라는 생각입니다.

사실 이제는 Objective-C 코드를 잘 몰라도 아이폰이나 맥 프로그램을 개발하는데 큰 문제가 없습니다. 오히려 알면 독이 될 수도 있죠. 회사에서 관련없는 일을 더 시킬 수도 있으니까요. 또한 이 언어를 알게되면 최근 유행하는 함수형 프로그래밍이나 Reactive 프로그래밍을 사용하는데 있어서 방해가 될 수도 있습니다. 이름은 객체지향언어이지만 선언하는 과정과 구조는 절차지향의 느낌이 강합니다. 특히나 헤더가 있는 경우도 문제가 되죠. 복잡도가 스위프트에 비해서 매우 높아집니다.

저는 작년에 오브젝티브-C 로 되어 있는 프로젝트를 Swift로 변경한 일이 있습니다. 그 중에 몇 가지는 이전 방식을 따라갈 수밖에 없었습니다. 그 중 대표적인 2가지가 AES 암호화와, KeychainWrapper입니다. 그 이유로는 Swift에서 만든 키체인 값과 Objective-C 에서 만든 키체인 값이 달라서 입니다. 물론 이론적으로는 말이 안되는데 미묘하게 뭔가가 달라서 충돌이 나는 바람에 내키지는 않았지만 브릿지 헤더(bridge header)로 두 가지 패키지를 스위프트 프로젝트에 포함시키는 결정을 했습니다. 같이 프로젝트를 진행하는 사람이 반대를 하기도 했지만 시간상 어쩔 수 없는 결정이었습니다. 물론 단순히 암/복호화를 하고 키체인 값을 저장하는 것이라서 큰 문제가 될 일은 없다고 생각했고 제 생각대로 프로젝트에 옮기고 지금까지 아무런 문제가 없습니다.

다음은 스위프트에서 KeychianItemWrapper를 사용하는 예시입니다.

extension UserDefaultsManager {
    func saveAppleEmail(value: String) {
        let keychainWrapper = KeychainItemWrapper(identifier: "AppleLogin", accessGroup: nil)
        keychainWrapper?.setObject(value, forKey: kSecValueData) }
    
    func loadAppleEmail() -> String? {
        let keychainWrapper = KeychainItemWrapper(identifier: "AppleLogin", accessGroup: nil)
        return keychainWrapper?.object(forKey: kSecValueData) as? String
    }
}


그러다가 요즘 진행하는 프로젝트에서 다음과 같은 동일한 코드를 오브젝티브-C로 만들게 되었습니다.

if (value.email == nil) {
    KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"AppleLogin" accessGroup:nil];
    NSData *data = [keychain objectForKey:(id)kSecValueData];
    param1 = [[NSMutableString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    
} else {
    KeychainItemWrapper *keychain = [[KeychainItemWrapper alloc] initWithIdentifier:@"AppleLogin" accessGroup:nil];
    [keychain setObject:value.email forKey:(id)kSecValueData];
    param1 = [NSMutableString stringWithString:value.email];
}

위의 코드를 보면 기능적으로 동일하며 오브젝티브씨 코드를 알고 있다면 별로 다를게 없어보이겠지만 그렇지 않다면 많이 다르게 보일겁니다. 특히나 선언하는 부분도 alloc 이라는 메서드를 써주고 그 다음에 init이 나오는 구조도 이상하죠. [, ] 이런 괄호도 굉장히 이상해보입니다. 스위프트라면 특정 기능을 extention으로 분리할 수도 있고 코드를 다른 파일로 옮길 수도 있습니다. 확장성이 매우 높죠. 특히나 enum을 잘 사용하면 옛날언어의 상태머신 지옥에서 벋어날 수 있습니다.

위의 코드는 단순 비교를 위해서 올린 것 이지만 한 가지 들었던 생각은 Swift를 모르던 때에 Objective-C 코드를 작성하는 것과 알고 나서 Objective-C 코드를 작성하는데 차이가 있다는 것을 느꼈습니다. 예전에는 통신을 할때도 단순히 NSMutableRequest 객체를 만들고 이미지를 만들꺼면 폼데이터를 만들고 서버 API에 따라 get, post로 구분해서 사용했었는데 생각해보면 이 가변데이터 타입이 스위프트에는 없기 때문에 다시 보니까 조금 생소하더군요. 어쩔때는 NSString을 사용하고 어쩔때는 NSMutableString을 무심코 사용했었는데 지금 생각해보면 아주 세분화해서 나눠져 있다는 생각을 했습니다. 특히나 메서드를 작성할 때 파라미터가 하나 넘어가면 외부 파라미터명을 앞쪽에 써줘야 했는데 그때 당시에는 왜 도대체 이런 식으로 파라미터 명을 두개를 만들어야 하나 답답하기만 했습니다. 스위프트에도 그런 기능이 있죠.

특히나 선언하는 방식 때문에 자바나 다른 객체지향 언어에 비해서 비효율적이라고 생각했었습니다. 특히 iOS 개발 환경에서 작업을 하면 오토레이아웃을 거의 필수로 사용하게되는데 요즘과 같이 스위프트 UI 같은 형태의 작업이 가능하면 이런 문제가 덜하겠지만 Objective-C 코드로 레이아웃을 관리하려면 매우 복잡했습니다. 그래서 SnapKit과 같은 오픈소스를 사용하기도 하죠. 이런 특징 때문에 언어에 대한 불만이 아주 많았는데 이제와서 보니 딱히 그렇지 않다는 것입니다.

단지 그때는 제가 잘 몰라서 그랬던 것 같습니다. 물론 스위프트에 비해서 확장성도 떨어지고 복잡한 것은 맞지만 충분히 잘 사용할 수 있는 언어입니다. 특히나 예전에 Objective-C++ 을 사용할 때면 정말 미쳐버릴 정도로 답답했던 기억 때문에 Objective-C를 증오하게 된 것 같습니다. Windows에서 만든 C++ 클래스를 포팅하는 작업들을 했는데 데이터 타입이 잘 맞지 않아서 정말 고생을 많이 했죠. 하지만 지금 생각해보면 그 또한 그때 제가 부족해서 그랬던 것 같습니다.

스위프트를 처음 사용하는 사람들은 Objective-C 코드를 꼭 배워야 하냐고 많이 물어봅니다. 저는 필요없다고 생각했었는데 요즘 다르게 생각이 들었습니다. 분명 배워야 할 것 같습니다. 이상한 비유이긴 하지만 엘레베이터가 없는 건물은 있어도 계단이 없는 건물은 없습니다. 엘레베이터가 없으면 계단으로 가면 되지만 계단이 없다면 엘레베이터를 편하게 이용하다가도 정전이 된다거나 고장이나면 방법이 없습니다.

분명 스위프트를 잘 사용하다가도 이런 문제를 마주하게 되면 어쩔 수 없이 오브젝티브 C를 배워야 할 겁니다. 또한 구조를 이해하는데 분명 필요한 것 같기도 합니다. 예를들어 Objective-C는 배열이 Class 형이지만 스위프트는 Struct인것 처럼요.

요즘에는 거의 스크립트 언어의 모양새로 언어들이 생겨나고 있으며 언어에 다양한 것이 모두 뒤섞여서 짬뽕이 되고 있습니다. 제네릭이 없으면 못쓸 언어라고 생각하는 사람들도 많아져서 오래된 언어에도 탑재하는 추세이기도 하죠. 물론 이런 기능이나 패러다임이 나쁘다는 것은 아닙니다. 매우 편리하고 이전으로 돌아갈 수 없게되고 개선된 언어이니 그만큼 이점이 많죠. 하지만 교수님들이 왜 C언어에 집착하고 나이든 사람들이 Java를 집착하는 지 조금은 이해를 해줘야 할 것 같습니다. 그 나름 대로의 쓸모가 다 있으니까 말이죠.

댓글

Designed by JB FACTORY