어렸을 때 비해서 프로그래밍 언어 학습이 더뎌진 것 같아서 이리저리 고민하며 나의 사고 패턴을 관찰 해 보니, 나의 사고 회로가 유연성이 떨어지고 굳어지고 있다는 생각이 강하게 들었다. 아직 사회 초년생이거나 20대 초반인 사람이 이 글을 읽게 된다면 내가 10년 후에 어떤 뇌를 가지게 될지 생각하는데 도움이 됐으면 하는 심정에서 이 글을 적는다.

일단 현상을 짚어보면 어떤 사건이나 복잡한 설명은 해당 하는 것의 세부 항목을 기억하기 보다는 추상화를 거친 단어로 기억하거나, 나 자신의 방식대로 해석한 최종 결론만 기억하는 경향이 있다. 이렇게 되면 기억 용량의 부하를 줄이게 되나 싶기도 하지만 세부 사항이 정확히 기억나지 않아 곤란한 경우도 종종 있다.

프로그래밍 하는 것을 생각해보면, 새로운 언어의 문법, API의 세부적인 것을 기억하는 능력은 발달하지 못하였다. 왜그런가 생각하니 나의 프로그래밍 행태와 관련이 큰 것 같다.

나는 보통 정교하게 설계 한 후 프로그래밍 하는 방식이 아니라, 큰 얼개와 방향을 머릿속에 그려 본 후 조금씩 구현해 나가면서 처음 생각을 고쳐나가는 방식으로 해왔었다. API를 많이 외우는 것보다 어떤게 있다는 정도만 ‘얕게’ 기억하고 문서를 자주 참조 하는 방식이었다. 알고리즘이나 패턴도 외우고 있기 보다는 어떤 문제에 직면 했을 때 어떤 것이 도움이 될지 찾아보는 패턴이었다.

그러다보니 세부적인 사항을 기억하는 회로는 발달이 덜 되고, 얼개나 방향을 생각하는 뇌의 회로가 만들어 진 것 같다. 뇌의 회로가 죽을 때 까지 바뀔 수 있다고 하지만 이미 만들어진 것을 바꾸려면, 혹은 새로 만들려면 그때까지 들어간 시간 혹은 그 이상의 노력이 필요하지 않을까 하는 생각이 든다.

이런 자각을 한지 얼마 되지 않는 것 같다. 아직 생명 에너지가 팔팔하다 못해 넘치는 10대, 20대 사람들은 앞으로 내 뇌가 어떤 기능을 가지면 좋을지 생각해보고 그렇게 뇌의 회로를 만들어 나가면 좋겠다.

우리나라가 절대 빈곤층과 소득 하위 분포 인구의 상대 소득이 꾸준히 늘고 있습니다.
이런 계층을 노동을 통해서 사회 생활을 건전하게 누릴 수 있도록 하려면
안정된 일자리가 늘어나고, 노동의 가치가 정당하게 인정되어야 합니다.

노동의 가치에 대한 판단은 기득권(자본) 세력이 좌우하고 있었으므로,
이런 전횡을 억제하고자 최저임금이 만들어졌고

노동의 정당한 가치가 얼마인지 정치를 통해 합의를 만들어 가고 있지요.
한편, 우리나라 자영업 수가 꾸준히 늘고 그 중 영세 자영업자 비중도 큽니다.

이런 현상은 양질의 일자리가 부족해서 어쩔 수 없이 생계를 위해 자영업을 하는 경우가 많다는 얘기일 것입니다.
그런 형편의 자영업자 입장에서는 최저 임금 올린다는 얘기는 감당하기 힘든 경우가 많을 것입니다.

한편 영세 자영업자의 노동자들은 그 사업이 영세하기 때문에 안좋은 환경일 경우가 많습니다.
이런 상황에서는 부당한 대우를 받을 확률도 커지지요.

물론 나쁜 사업자, 나쁜 노동자 둘 다 있을 수 있습니다.
그러나 이건 또 다른 해결해야 하는 문제기 때문에 제쳐놓고 생각해보겠습니다.

영세 업자와 그 노동자들은 안좋은 환경이니 계속 불만이 있을 수 밖에 없고, 둘의 사이 또한 좋을 수 없습니다.
결론은 그 환경이 좋아져야 합니다.
영세 업자가 더이상 영세하지 않아야 하며 그 직장이 소득이 괜찮은 직장이 되어야 합니다.
그런데 양극화 현상이 심화되면서 영세한 계층은 더더욱 영세해져 갑니다.

최저임금 1만원으로 올림에 따라 자영업자와 노동자들이 다투게 되는 이유가 여기에 있습니다.
결국 양극화가 해소되서 경제 분포의 하위에 존재하는 계층의 소득이 전체적으로 올라야 해결될 문제입니다.
최저임금만 올리면 소득 하위 분포 계층의 구성원끼리 싸우는 꼴밖에 안됩니다.

한편 현재 경제 상황으로 봤을 때 최저임금을 1만원 정도로 올리는 것도 타당해 보입니다.
그러나 다른 하위 경제 활동 계층의 재화는 그대로 있는 상태에서 그렇게 되면
영세 사업자는 망하게 될 확률이 크지요.

그정도 유지 못하면 망해야 한다는 얘기가 있는데, 그러면 그 사람들을 흡수 할 일자리도 필요합니다.
그러지 않은 상태에서 서로 간 주장을 해봐야 없는 사람들끼리 아귀다툼 하는 꼴 밖에 안됩니다.
지금은 이 상황에서 벗어나는게 중요하지 싸워야 할 때는 아니니까요.

그러니 현 상황에서 노동자, 사용자끼리 싸우는 프레임에서 벗어나서
양극화를 해소하고  양질의 일자리가 창출 될 수 있도록
사회 시스템을 개선하도록 노력하고, 정치권에 요구하는게 필요하지 않나 생각합니다.

Multithread

그림 1. iOS App’s Threads

모든 iOS Multithread 앱이며, 간단하면서도 유의해야 할 원칙들이 있다.

  1. 모든 UI 갱신에 관련된 작업은 main thread (그림 1의 Thread 1) 에서 수행되어야 한다.

  2. Thread-unsafe 변수는 서로다른 스레드에서 동시에 접근하면 위험하다.

여기에서는 2번째 경우에 관해 얘기를 하겠다. 이것이 중요한 이유는 이런 것들을 잘 지키지 않으면 프로그램이 죽기 때문이다. 왜 죽는지 디버깅 하기도 까다롭다.

이하 함수와 메소드는 모두 함수로 적겠습니다.

Mutable , Immutable

기본적으로 Immutable instance는 Thread-safe 하다. 여러 스레드에서 한번에 접근한다 해도 문제가 없다는 의미다. Mutable Instance 를 만약 읽기 용도로만 이용한다면 문제가 없을 수도 있다. 그러나, Mutable Instance 를 하나 이상의 스레드에서 변경 중일 때 다른 스레드가 접근하면 문제가 생길 것이다. Mutable Instance가 멤버 변수이거나, 함수들 사이에 전달 된다면 그때는 Lock을 고려 해야 한다.

프로그래밍을 하다 애매하다 싶은게 있으면 해당 클래스의 문서를 참고하면 Thread-safe, unsafe 에 대한 얘기들이 나오니 관련된 얘기가 나오면 꼭 숙지하고 있는 게 좋겠다.

Property Attribute

스레드와 관련된 Property Attirbute 는 atomic, nonatomic 이 있다. atomic 키워드는 해당 프로퍼티가 동시에 접근 할 수 없게한다. 따라서 Mutable 멤버 변수는 atomic 으로 하는게 나을 것이다. 다만 atomic 은 속도면에서 불리함 이있으니 Mutable Instance 라도 변경중에 절대 동시 접근 할 일이 없다면 nonatomic 으로 해도 될 것이다. 즉, 어떻게 설계하느냐에 따라 달라 질 수 있다.

Synchronized

함수를 실행 할 때 특정 구간에서 특정 자원을 접근 할 때 동시에 접근 하지 못하게 하고 싶을 때 해당 부분을 Lock 할 수 있다. 그러면 한 스레드에서 그 구간을 끝낼 때 까지 다른 스레드에서 접근 할 수 없게 된다. 이때, Deadlock 을 유의 할 것.

Deadlock - Wikipedia
_In concurrent computing, a deadlock is a state in which each member of a group of actions, is waiting for some other…_en.wikipedia.org

Objective-c 에서는 간단하게 아래와 같이 @synchonized 구문을 이용해서 Lock을 할 수 있다. Block 하는 방식은 프로그래밍에는 유용하나 성능 저하를 가져오니 프로그램의 성격에 맞춰 적용해야 할 것이다.

[code language=”objc”]

- (void)myMethod:(id)anObj { @synchronized(anObj) { // Everything between the braces is protected by the @synchronized directive. } }

[/code]

GDC

GDC는 동시성 프로그래밍을 위한 도구이다. Thread 프로그래밍과 비슷하지만 Thread 프로그래밍은 복잡하고 구현이 어렵기 때문에 Apple 에서는 좀 더 간단하면서 효율적인 것을 만들어냈다.

GDC 에서도 위에서 얘기한 것들을 숙지하며 사용 해야 한다.

in Swift

Swift 에서 다뤄볼만한 점은 structure 와 class 이다. structure 는 value type 이고 class 는 reference type 이다. value type 의 특징은 call by value 로 동작한다는 점이다. class는 call by reference 이고.

그래서 structure type 은 파라미터로 전달 될 때 thread safe 하다. structure type 이 성능면에서도 class 보다 낫다고 하니 설계 할 때 고려 사항이 될 만하다. class 는 Objective-C 와 동일하다.

생각해볼 점 : structure 가 멤버 변수일 경우

결론

Thread-unsafe 한 변수를 이용 한다면, 변경 중에 동시 접근하는 경우가 생기는지 확인해야 한다. 그러지 않으면 앱이 쥐도새도 모르게 죽는다. View, ViewController 의 Life-cycle , Event 에 관계된 함수에서는 특히 주의해야 한다.

참조

Synchronization
_Explains how to use threads in Cocoa applications._developer.apple.com

Dispatch Queues
_Explains how to implement concurrent code paths in an application._developer.apple.com

The Swift Programming Language (Swift 3.1): Classes and Structures
_The definitive guide to Swift, Apple’s new programming language for building iOS, macOS, watchOS, and tvOS apps._developer.apple.com

Objective-C Literals

Literals의 소개

리터럴은 소스코드상에 표시된 고정된 값이다. 숫자, 문자, 집합형(배열형, 사전형)이 있다. XCode 4.4 부터 새롭게 추가 되었다. OSX 10.8과 iOS 5.1 부터 지원한다. OSX 10.7 에서도 지원하려면 OSX 10.8 SDK로 컴파일 해주기만 하면 된다. XCode 4.5 에 포함된 최고 버전의 SDK를 이용한다면 OSX 10.6과 iOS 4 이상에서 이용 가능하다. 자세한 사항은 예제만 봐도 바로 알 수 있을 것이다. 그리고 최신 사양 지원 문제 때문에 되도록 Apple LLVM 을 이용하는 것을 권장한다.

숫자형

NSNumber *theLetterZ = @’Z’;          // equivalent to [NSNumber numberWithChar:’Z’]

// integral literals.

NSNumber *fortyTwo = @42;             // equivalent to [NSNumber numberWithInt:42]

NSNumber *fortyTwoUnsigned = @42U;    // equivalent to [NSNumber numberWithUnsignedInt:42U]

NSNumber *fortyTwoLong = @42L;        // equivalent to [NSNumber numberWithLong:42L]

NSNumber *fortyTwoLongLong = @42LL;   // equivalent to [NSNumber numberWithLongLong:42LL]

// floating point literals.

NSNumber *piFloat = @3.141592654F;    // equivalent to [NSNumber numberWithFloat:3.141592654F]

NSNumber *piDouble = @3.1415926535;   // equivalent to [NSNumber numberWithDouble:3.1415926535]

// BOOL literals.

NSNumber *yesNumber = @YES;           // equivalent to [NSNumber numberWithBool:YES]

NSNumber *noNumber = @NO;             // equivalent to [NSNumber numberWithBool:NO]

#ifdef __cplusplus

NSNumber *trueNumber = @true;         // equivalent to [NSNumber numberWithBool:(BOOL)true]

NSNumber *falseNumber = @false;       // equivalent to [NSNumber numberWithBool:(BOOL)false]

#Endif

주의사항

  1. 괄호 표현

#define INT_MAX   2147483647  /* max value for an int */

#define INT_MIN   (-2147483647-1) /* min value for an int */

위 예시에서 @INT_MIN 은 안된다. 왜냐하면 괄호로 되어 있기 때문이다. 괄호가 있는 것은 boxed expression 을 참조하라.

  1. Long double 형

NSNumber 는 long double 은 지원하지 않고 있다. 위에 나온 예시만 이용 할 것.

Boxed 표현형

괄호로 둘러싼 형태

// numbers.

NSNumber *smallestInt = @(-INT_MAX - 1);  // [NSNumber numberWithInt:(-INT_MAX - 1)]

NSNumber *piOverTwo = @(M_PI / 2);        // [NSNumber numberWithDouble:(M_PI / 2)]

// enumerated types.

typedef enum { Red, Green, Blue } Color;

NSNumber *favoriteColor = @(Green);       // [NSNumber numberWithInt:((int)Green)]

// strings.

NSString *path = @(getenv(“PATH”));       // [NSString stringWithUTF8String:(getenv(“PATH”))]

NSArray *pathComponents = [path componentsSeparatedByString:@”:”];

예제1)

enum {

AVAudioQualityMin = 0,

AVAudioQualityLow = 0x20,

AVAudioQualityMedium = 0x40,

AVAudioQualityHigh = 0x60,

AVAudioQualityMax = 0x7F

};

  • (AVAudioRecorder *)recordToFile:(NSURL *)fileURL {

NSDictionary *settings = @{ AVEncoderAudioQualityKey : @(AVAudioQualityMax) };

return [[AVAudioRecorder alloc] initWithURL:fileURL settings:settings error:NULL];

}

예제2)

typedef enum : unsigned char { Red, Green, Blue } Color;

NSNumber *red = @(Red), *green = @(Green), *blue = @(Blue); // => [NSNumber numberWithUnsignedChar:]

예제3)

typedef enum : unsigned char { Red, Green, Blue } Color;

Color col = Red;

NSNumber *nsCol = @(col); // => [NSNumber numberWithUnsignedChar:]

예제4) C String

int main(int argc, char *argv[])

{

NSMutableArray *args = [NSMutableArray new];

NSMutableDictionary *options = [NSMutableDictionary new];

while (–argc) {

const char *arg = *++argv;

if (strncmp(arg, “–”, 2) == 0) {

options[@(arg + 2)] = @(*++argv);   // –key value

} else {

[args addObject:@(arg)];            // positional argument

}

}

}

컨테이너 리터럴

컨터이너 리터럴은 기본적으로 변경 할 수 없는 객체(immutable)이다.

NSDictionary *dictionary = @{

@”name” : NSUserName(),

@”date” : [NSDate date],

@”processInfo” : [NSProcessInfo processInfo]

};

이런식으로 하면 변경 가능한 객체를 간단히 생성 가능하다. (단점은 자동 완성이 잘 지원되지 않는다.)

NSMutableArray *food = [@[@“김치”,@“라면”,@“밥”] mutableCopy];

Subscripting Method

객체 치환 방식이다. 배열형과 사전형이 있다. 기존에는 replaceObjectAtIndex:withObject: 나 setObject:forKey: 같은 것을 호출해야 했다.

배열형

NSUInteger idx = …;

NSMutableArray* object = [NSMutableArray new];

id value = object[idx];

object[idx] = @“abc”;

사전형

id key = …;

id value = object[key];

object[key] = newValue;

현재는 정수형과 Objective-C 타입 객체에만 적용 된다.(C++ 안됨)

참조

http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/FoundationTypesandCollections/FoundationTypesandCollections.html

http://clang.llvm.org/docs/ObjectiveCLiterals.html

http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/ObjCAvailabilityIndex/_index.html