iPhone 개발 중 Network Indicator(이하 NI)를 사용하다 보면 다음과 같은 경우가 있습니다.

1. thread1에서 network 사용 (NI 켬)
2. thread2에서 network 사용 (NI 켬)
3. thread1이 통신을 마침 (NI 끔)
4. thread2가 통신을 마침 (NI 끔)

이러한 시나리오를 거쳤을 때 UIApplication의 setNetworkActivitryIndicatorVisible값을 변경하는 것 만으로는 문제가 있습니다. 위의 예에서는 3번에서 NI를 껐을 때 thread1은 network를 사용중임에도 불구하고 NI는 꺼져 있는 것으로 나타납니다.

이러한 현상을 해결하기 위해 작성한 singleton class입니다. (singleton class 제작 방법: http://b4you.net/blog/210)

// NetworkActivityManager.h
#import <Foundation/Foundation.h>

@interface NetworkActivityManager : NSObject
{
    volatile NSUInteger _visibleCount;
}

+ (NetworkActivityManager *)sharedNetworkActivityManager;
- (void)setNetworkActivityIndicatorVisible:(BOOL)visible;

@property(readwrite) volatile NSUInteger _visibleCount;

@end


//  NetworkActivityManager.m
#import "NetworkActivityManager.h"

@implementation NetworkActivityManager

@synthesize _visibleCount;

+ (NetworkActivityManager *)sharedNetworkActivityManager
{
    static NetworkActivityManager *networkActivityClass = nil;
    
    if(networkActivityClass == nil)
    {
        @synchronized(self)
        {
            if(networkActivityClass == nil)
            {
                networkActivityClass = [[self alloc] init];
                networkActivityClass._visibleCount = 0;
                [self autorelease];
            }
        }
    }
    
    return networkActivityClass;
}

- (void)setNetworkActivityIndicatorVisible:(BOOL)visible
{
    @synchronized(self)
    {
        if(visible == YES)
        {
            _visibleCount++;
            
            [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
        }
        else if(visible == NO)
        {
            if(_visibleCount <= 1)
            {
                // 모든 곳에서 NO로 했다면
                [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
                _visibleCount = 0;
            }
            else
            {
                // YES로 한 곳이 남아있다면
                _visibleCount--;
            }
        }
    }
}

@end


사용 방법은 다음과 같이~

[[NetworkActivityManager sharedNetworkActivityManager] setNetworkActivityIndicatorVisible:NO];

크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 장현준

2009/05/21 18:25 2009/05/21 18:25
, ,
Response
No Trackback , a comment
RSS :
http://b4you.net/blog/rss/response/225

iPhone 개발을 하다보니, device에 올려서 NSLog를 출력하면 속도가 급격히 떨어지는 현상을 종종 겪고는 합니다.
실제로 올려서 테스트 하는 경우도 있지만 보통은 simulator에서 열심히 디버깅을 하고 device에 올려서 최종 테스트를 하고.. 이런 과정을 거쳐서 개발을 하는데요, 이럴때 device에 올렸을때만 로그가 안찍히게 할 수 있는 방법을 소개해드립니다.

iPhone simulator에서 동작을 할 때에는 "TARGET_IPHONE_SIMULATOR" 값이 자동으로 define됩니다.
이 define된 것을 이용하여 조건부 컴파일을 하여 simulators 일때만 로그를 남길 수 있게 할 수 있습니다. 예를 들면 다음과 같이 말이죠.

#define USE_CONDITIONAL_LOG

#ifdef USE_CONDITIONAL_LOG
	#if TARGET_IPHONE_SIMULATOR
		#define ConditionalNSLog			NSLog
	#else
		#define ConditionalNSLog			(void)
#else
	#define ConditionalNSLog				NSLog
#endif

위와 같이 선언한 뒤 실제 코드에는 다음과 같이 이용합니다.

ConditionalNSLog(@"hello~");
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 장현준

2009/05/21 09:26 2009/05/21 09:26
,
Response
No Trackback , No Comment
RSS :
http://b4you.net/blog/rss/response/224

iPhone 개발을 하며 NSAutoreleasePool 클래스를 보게 되는데..
이 클래스의 역할은 autorelease가 설정되어 있는 객체들을 pool이 release될 때 덩달아 release해줍니다.
NSAutoreleasePool은 다음 기회에 c++이나 Java로 비슷하게 만들어 보기로 하고..-ㅁ-

여기서는 이 NSAutoreleasePool 때문에 깔끔하지 못한 코드가 나오는 것을 보겠습니다.
예)
문자열을 리턴해야 되는 메서드가 있습니다. 이 문자열을 어떻게 리턴 해주어야 할까요?

기존의 C 방식에서는 다음과 같이 합니다. (예제를 간단하게 만드느라 유니코드는 생략합니다)

void getChars(char *p, int len)
{
	strncpy(p, "hello~!", len);
}

int main()
{
	char *a;
	a = (char *)malloc(sizeof(char) * 100);
	getChars(a, 100);
	printf("%s", a);
	return 0;
}

메모리 할당 후 return해줘도 되지만... 보통은 위와 같이 하죠.
이걸 Objective-C의 NS* 시리즈로 autorelease를 이용해서 구현 한다면?

- (NSString *)getChars
{
	return [NSString stringWithFormat:"hello~!"];
}


와 비슷하게 됩니다. (당.연.히 위의 C코드와는 다릅니다)
중요한건 이게 언젠간 autorelease pool에 의해 release가 되는데.. pool이 release 될 때까지 기다려야 된다는 것 입니다.
그러면 pool이 release 되기 전까지는 계속~~~~ 메모리를 차지 하고 있는데...
(이 부분이 background에서 알아서 release 해주는 garbage collector와 다른점이 되겠습니다)
이걸 개발자가 수동으로 release 하게끔 짜놓으면 만사 OK지만... 문제는 기존에 autorelease로 짜놓은 코드들이 너무 많다는 것 입니다.
즉 autorelease를 남발해댄(NSString의 stringWithFormat와 같은) 소스를 쓰면 릭 아닌 릭(?)이 발생한다 이거죠.

이런걸 해결하려면 일정 구간을 또 다른 NSAutoreleasePool로 묶을 수 있습니다. 다음과 같이 말이죠

// 1차 autorelease pool
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

for(int i = 0; i < 100000; i++)
{
	// pool이 담당하는 autorelease 구간
	// autorelease #1
	[NSString stringWithFormat:@"autorelease test"];
}

sleep(5);

// 2차 autorelease pool
NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];

for(int i = 0; i < 100000; i++)
{
	// pool2가 담당하는 autorelease 구간
	// autorelease #2
	[NSString stringWithFormat:@"autorelease test"];
}

// autorelease #2 영역의 데이터 정리
[pool2 release];

sleep(5);

[pool release];


이렇게 nested(?) autorelease pool을 사용하면 다음과 같이 할당 됩니다.

사용자 삽입 이미지


초반에 열심히 할당하고 5초 지난 후 또다시 열심히 할당하고 그다음에 반으로 깎이는 것을 보실 수 있습니다.

이렇게 사용할 수 있지만.. 잘못 사용하면 독이 된다는거~!!
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 장현준

2009/03/26 17:02 2009/03/26 17:02
, ,
Response
No Trackback , No Comment
RSS :
http://b4you.net/blog/rss/response/208

NSMutableDictionary 사용하기

1. 초기화
NSMutableDictionary *dic;
dic = [[NSMutableDictionary alloc] init];

2. 데이터 삽입
[dic setObject:@"v1" forKey:@"k1"];
[dic setObject:@"v2" forKey:@"k2"];
[dic setObject:@"v3" forKey:@"k3"];

3. 데이터 갯수 구하기
NSLog("%d", [dic count]);
;

4. 값 얻어오기
NSString *str = [dic objectForKey:@"k1"];
NSLog(@"%@", str);
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by 장현준

2009/03/19 11:51 2009/03/19 11:51
,
Response
No Trackback , No Comment
RSS :
http://b4you.net/blog/rss/response/205


블로그 이미지

빗소리를 먹는 사람.

- 장현준

Notices

Archives

Authors

  1. 장현준

Recent Trackbacks

Calendar

«   2017/11   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    

Site Stats

Total hits:
1973434
Today:
5258
Yesterday:
5236