진짜 세상에 간단한 프로젝트는 없다...

카테고리 없음 2010. 10. 9. 06:08

전에 봤던 이 글이 오늘 뼈져리게 와 닿고 있습니다.


간단한 프로젝트라 함은 그 프로젝트에 대해 그 시점에서 전혀 모르고 있다는 이야기와 같다고 볼 수 있는 것 같습니다. 진짜 간단한 프로젝트라면 그건 프로젝트가 성립 되지도 않겠지요.

그런 프로젝트일수록 요구사항이 변경되는 타이밍도 괴랄스러운게, 일단 다 구현한 직후에 그 구현을 무효화 해야하는 변경사항이 옵니다. 
참나...그럴수밖에 없는 것이 구현되기 전에는 그게 뭔지도 몰랐기 때문이지요.

심지어 간혹가다 "이거 간단하지?" 하면 "그거 간단해요...별것 아니군요..." 라고 하는 개발자도 있는데, 그것은 역시 그 개발자가 그 방면에 경험이 없어서 (아니면 이미 다 구현해 놓은 라이브러리가 있거나 어디서 구할 수 있는지 알고 있을지도) 그러는 것으로 볼 수있을 것 같아요.

뭐든 디테일한 부분으로 들어가면 예기치 못한 어려움은 반드시 닥치더군요.

짜증나는 간단해 보이는 프로젝트의 유형 또 한가지는...

"기존에 있던 프로젝트에 이러이러한 신기능을 '한개만' 추가!"

이런 것인데 그게 말은 쉽지만, 이전에 있던 프로젝트가 매우 타이트하게(겨우겨우) 구현되어있어서(특히 오래된 프로젝트일수록) 뭔가 비집고 끼워넣을 틈을 찾아 덕지덕지 누더기같이 집어넣느니 아예 새로 하는 것이 빠르고 안전한 경우도 많다는 점(이 시점에서 이미 기존 프로젝트보다 크고 어려운 프로젝트로 돌변)...

더구나 기존 프로젝트를 하는 팀이 몰래 잠수함 패치를하면 내 프로젝트도 와장창 깨지곤 한다는 점...

뭐 그런데 어쩌겠어요...
앞으로는 그냥 마음을 비우고, 간단한 프로젝트란건 없다고 생각하고, 무조건 프로젝트 내용을 듣는 직후 제 머리속에 떠오른 개발 예상 시간의 3배는 걸릴 것이다...라고 생각 하기로 했습니다.
Posted by 타이가장관
,

LLVM 1.5에게 당하다...

Apple의 세계에서 삽질/Cocoa Touch로 삽질 2010. 9. 24. 13:09
릴리즈 날짜를 생각해서 iOS 4.2로 뭔가 데모를 개발하는 삽질을 했는데...
...클라이언트는 3.2라네...라는 말을 뒤늦게 듣고서 재빨리 다운그레이드를 하는데...

block은 target/action혹은 지연 콜(이건 원래 안되는 것인데, 그냥 귀찮아서)로 바꾸는 삽질을, GCD는 NSOperation으로 바꾸고...아무튼 그렇게 다 했는데 의문의 EXC_BAD_ACCESS...가 UIView 서브 클라스의 [super setFrame:(CGRect)fr] 에서 발생...

아무리 해도 원인을 찾을 수 없었는데...

알고봤더니...
LLVM 1.5의 버그, 혹은 호환성 문제였던 것 같군요.
LLVM + GCC 4.2로 바꾸니까 되살아나네요.

LLVM 1.6 (Xcode 베타 3.2.5 에 딸려온)에서는 무사히 작동...

뭐 한두달 후면 iOS4.2에 LLVM 1.6으로 작업을 해야 할테니 별 문제는 없겠지만, 가끔 이런 것에 걸려서 삽질하면 짜증이 많이 납니다.
Posted by 타이가장관
,

block에 대한 매우매우 기본적인 소개

Apple의 세계에서 삽질/Objective-C로 삽질 2010. 9. 18. 07:35

items = [1, 2, 3, 4, 5].freeze

items.each do |item|
	p item
end

5.times {
	|n| p n
}

루비를 써보셨다면 익히 보셨을 저런 짓들이 이제는 Objective C의 세계에서도 된다...뭐 그런거지요. 바로 실행 가능한 코드 뭉치(어찌보면 함수라고 할 수도 있고)를 다른 함수의 인자나 기타 등등으로 넣어버리는 것입니다. 사실은 함수 포인터 등등의 방법으로 가능하긴 한데, 그걸 언어 자체의 기능으로 넣어서 좀더 쓰기 편하고 안정적으로 하도록 한 것이라고 할까...물론 기타 다른 언어에서도 지원되던 기능이지요.

block의 기본은
^
입니다. 문법적으로는 대강 아래와 같이 쓰이는데...뭐 자세한 것은 Help Document에서 Blocks Programming Topics를 참고하시는 것이 좋을 듯 합니다.


// ^ 로 시작, 다음에 오는 것은 return value type, 그리고 ()안에 인자, {}안에 실행 코드
^BOOL(id item){ return [item length] > 0; }

// 만일 return value이 void라면 생략하고 다음과 같이 가능
^(id item){ NSLog(@"%@", [item description]); }

// 만일 return value와 인자가 모두 void라면 생략하고 다음과 같이 가능
^{ NSLog(@"어쩌라구?"); }

// 혹은 아예 block을 변수로 선언하려면
int (^myBlock)(int) = ^(int n) { return n * 100; };

// 그리고 부를 때는
NSLog(@"%d", myBlock(5));

그 외에 block자체는 Objective C 객체로 처리되기 때문에 retain/release등을 사용 가능합니다. 근데 자주 사용하게 되지는 않는 것 같네요.

중요한 점

// WWDC 2010 Session 102에서
int multiplier = 7;
int (^myBlock)(int) = ^(int num) { return num * multiplier; };
multiplier = 13;

printf("%d\n", myBlock(3));

다음의 결과는 뭘까요? 13 * 3이니 39?
답은 21입니다.

block안에서 접근하는 외부의 로컬 변수나 기타 등등의 것들은, block이 선언되는 시점의 값이 상수로 복사가 됩니다. Obj-C 객체들은 자동을 retain하고 들어간 뒤에 끝날 때 release되구요.

그렇다면 block은 외부와의 단절을 뜻하나...?

물론, block내부에서 외부로 연락을 취할 방법이 없다면 사용 용도가 지극히 제한될테니, 다음과 같은 녀석이 나타납니다.

__block storage class

H군이 또 질문을 했습니다. block구문을 처음 써서 indexset안에 있는 값을 다 더한 값을 얻고 싶다. 뭐 그런것이었습니다. 근데 아무리 해도 값이 안더해지고 0이 나오더라...뭐 이런 질문을...
	// indexes는 NSIndexSet
	NSUInteger total = 0;
	
	[idxSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
		total += idx;
	}];
	
	NSLog(@"Total = %d", total);
무려 WWDC 2010에 '직접' 갔다온 말이 많은 T라는 녀석도 아..이거 뭔가 방법이 있을텐데...이러고 있습니다. 뭐하러 갔나?

이친구들아 문서를 좀 보게나. 아니면 WWDC세션 비디오라도...

라고 하고 싶기도 했지만 그냥 멋지게 단 7자를 더 쳐서 문제를 해결해서 폼을 잡아보기로 했습니다(block을 사용한 enumeration은 다음 기회에 이야기 하고 싶은데, 여기서 잠깐 맛뵈기로...). 

	// indexes는 NSIndexSet
	__block NSUInteger total = 0;
	
	[idxSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
		total += idx;
	}];
	
	NSLog(@"Total = %d", total);

문제 해결... 참 쉽죠? 예 쉽습니다. __block이라는 녀석은 해당 변수를 스택이 아닌 힙에 만들어서 block안에서도 변경가능하게 만들어 주는 마법(?)을 부립니다. 일반적으로 block은 스택에 만들어지고, 해당 변수들도 몽땅 원본이 아닌 '사본'이 스택에 올라가기 때문에 그렇죠.

그럼 Objective C 객체들은 어떠한가? 별다른 처리가 필요하지는 않습니다.
그러니까 이런식으로 쓸 수 있다는 것입니다...
	NSArray *a = [NSArray arrayWithObjects:@"A", @"B", @"C", nil];
	
	NSMutableString *str = [NSMutableString string];

	[a enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
		[str appendFormat:@"(%d:%@)", idx, obj];	
	}];

	NSLog(@"%@", str); // (0:A)(1:B)(2:C)

물론 반환값을 block내에서 만들어내겠다...이런다면 __block으로 해야겠지요. 근데 이런 경우가 딱히 많지는 않을 듯 싶군요. 대부분은 return value로서 받으면 되니까.
 
기본적으로는 block이 선언되면 block안에서 접근하는 객체들은 block실행도중에 죽어버리는 것을 막기 위해서 자동 retain, release가 되는데 __block으로 선언하면 그걸 꺼버린답니다(당연히 개발자가 어떤 행동을 원하는지 알 길이 없기에 그러는 것이지요).

다른 사용예는 다음 기회에. enumeration과 GCD등에서 편리하게 쓰이거든요.
Posted by 타이가장관
,