Dialer 와 같은 앱은 iPod Touch 에서는 동작하지 않고, iPhone 만은 지원하는데 ( facetime 을 지원한다면 얘기는 달라집니다만..)
이런경우 iPod Touch를 제외하고 싶은데 어떻게 해야 할까요?

Application Property List 의 'UIRequiredDeviceCapabilities'항목에 'telephony' 를 추가 해주면 됩니다.


 이렇게 하면 AppStore 상에서 아래와 같이 iPhone 만을 지원하게 됩니다  

 

 {#name}.png iPhone   iPhone 3GS or before
 {$name}@2x.png iPhone Retina   iPhone4 and iPhone4S and some iPod Touch 
 {$name}~ipad.png iPad   iPad 1 & iPad 2 
 {#name}@2x~ipad.png  iPad Retina   iPad 3 aka 'New iPad' or 'iPad HD' 


소스코드
[UIImage imageNamed:@"{#name}"];
위와 같이 작성하면, iOS 단에서 하드웨어에 맞는 이미지를 찾아 줍니다.
 

한국 연락처앱에선 없어서는 안될, '초성검색'을 
'erica sudan'이라는 분이 만든, ABContactHelper에 추가 구현해 보도록 하겠습니다.

ABContactHelper 프로젝트는 말그대로, iOS 의 AddressBook API 를 wrapping 해놓은것입니다.
AddressBook API 가 NS 쪽 이 아닌 CF 쪽 계열이다 보니, Memory 관리나 이런게 귀찮은 부분이 많은데, 그를 해소하고자 'Erica Sudan'이 Wrapping 해놓은 Library 입니다.

우선 코드를 다운 받고 아래와 같이 Test Case를 작성하였습니다.
#import "KoreanSearchTest.h"
#import "ABContactsHelper.h"

@interface KoreanSearchTest()
@property (nonatomic, retain) ABContact *contact;
@end

@implementation KoreanSearchTest
@synthesize contact = mContact;
- (void)setUp
{
    [super setUp];
    
    // Set-up code here.
    
    ABContact *contact = [ABContact contact];
    contact.firstname = @"긱보드";
    
    [ABContactsHelper addContact:contact withError:NULL];
    self.contact = contact;
}

- (void)tearDown
{
    // Tear-down code here.
    [self.contact removeSelfFromAddressBook:NULL];
    self.contact = nil;
    [super tearDown];
}

- (void)testExample
{
    NSArray *contacts = [ABContactsHelper contactsMatchingName:@"긱보드"];
    STAssertTrue([contacts count] > 0, @"");
    
    contacts = [ABContactsHelper contactsMatchingName:@"ㄱㅂㄷ"];
    STAssertTrue([contacts count] > 0, @"");
}
@end

* line 34 번의 Test 는 초성검색이 아닌 일반 검색으로 따로 코드를 수정하지 않아도 통과합니다.
* line 37 번의 Test가 초성검색을 확인하는 것으로 현재는 '당연히' 통과하지 않습니다.


Q. 초성검색을 어떻게 할것인가?

여러 지인들의 구현방법 + 인터넷 상의 얘기들을 보면, 보통 초성을 분리 해서 저장하는 하고,
초성으로 저장된 녀석을 검색하는 방법을 많이 씁니다.

초성 분리 코드는 'http://skyrack.tistory.com/118' 에서 소개된 코드를 사용하도록 하겠습니다.


1. 초성 property 선언
@property (nonatomic, readonly) NSString *contactName; // my friendly utility
@property (nonatomic, readonly) NSString *compositeName; // via AB
@property (nonatomic, retain) NSString *chosung; // Geekboard add

2. 초성 getter 구현
@synthesize chosung = mChosung;

- (NSString *)chosung {
    
    if(mChosung == nil) {
        NSString *contactName = [self contactName];
        const NSArray *chosung = [NSArray arrayWithObjects:@"ㄱ",@"ㄲ",@"ㄴ",@"ㄷ",@"ㄸ",@"ㄹ",@"ㅁ",@"ㅂ",@"ㅃ",@"ㅅ",@"ㅆ",@"ㅇ",@"ㅈ",@"ㅉ",@"ㅊ",@"ㅋ",@"ㅌ",@"ㅍ",@"ㅎ",nil];
        
        NSString *textResult = @"";
        for (int i=0;i<[contactName length];i++) {
            NSInteger code = [contactName characterAtIndex:i];
            if (code >= 44032 && code <= 55203) {				
                NSInteger uniCode = code - 44032;				
                NSInteger chosungIndex = uniCode / 21 / 28;		
                textResult = [textResult stringByAppendingFormat:[chosung objectAtIndex:chosungIndex]];
            }  
            else  {
                textResult = [textResult stringByAppendingFormat:@"%C", code];
            }
        }
        
        if([contactName isEqualToString:textResult] == YES) {
            mChosung = [[NSString alloc] initWithString:@""];
        }
        else {
            mChosung = [[NSString alloc] initWithString:textResult];
        }
    }
    return mChosung;
}

3. contactsMatchingName: method 수정
+ (NSArray *) contactsMatchingName: (NSString *) fname
{
	NSPredicate *pred;
	NSArray *contacts = [ABContactsHelper contacts];
    // Geekboard : 'chosung' key 도 검색하도록 수정
	pred = [NSPredicate predicateWithFormat:@"chosung contains[cd] %@ OR firstname contains[cd] %@ OR lastname contains[cd] %@ OR nickname contains[cd] %@ OR middlename contains[cd] %@ ", fname, fname, fname, fname,fname];
	return [contacts filteredArrayUsingPredicate:pred];
}

Q. 이게 끝일까요?
- (void)testExample
{
    contacts = [ABContactsHelper contactsMatchingName:@"긱ㅂㄷ"];
    STAssertTrue([contacts count] > 0, @"");
}
현재 상태로는 위의 Test 를 통과하지 못합니다. ( 초성 + 일반 글자 혼용 형태)

제가 작성한 소스는 아래의 링크로 공유되어 있으니,

https://github.com/Geekboard/ABContactHelper

한번 해결해보시는건 어떨까요? :) 

1. openUrl 을 이용하는 방법
 
- (void) callWithOpenURL:(NSString *)phoneNumber {
    NSURL *url = [NSURL URLWithString:[@"tel://" stringByAppendingString:phoneNumber]];
    [[UIApplication sharedApplication] openURL:url];
}

* 단점 : 전화가 끝나면, 현재 앱이 아닌, 전화앱으로 변경이 된다.

2. WebView를 이용하는 방법
- (void) callWithWebView:(NSString *)phoneNumber {
    NSURL *url = [NSURL URLWithString:[@"tel://" stringByAppendingString:phoneNumber]];
    // ! memory leak 
    UIWebView *callWebview = [[UIWebView alloc] init];
    [callWebview loadRequest:[NSURLRequest requestWithURL:url]];
}
* 장점 : 전화가 끝나면 현재앱으로 돌아온다.
* 단점 : 전화를 걸것인지에 대한 팝업이 한번더 뜬다 

 

GameCenter Matchmaking 을 위한 Checklist

@required

1. 현재 user 인증
2. MatchMaking User Interface
3. Handle invitation from other user

@optional
1. Programmatcially Match find 코드 삽입
2. Advanced Match Making 코드 삽입 

 
UIKIT_EXTERN NSString *NSStringFromCGPoint(CGPoint point);
UIKIT_EXTERN NSString *NSStringFromCGSize(CGSize size);
UIKIT_EXTERN NSString *NSStringFromCGRect(CGRect rect);
UIKIT_EXTERN NSString *NSStringFromCGAffineTransform(CGAffineTransform transform);
UIKIT_EXTERN NSString *NSStringFromUIEdgeInsets(UIEdgeInsets insets);
UIKIT_EXTERN NSString *NSStringFromUIOffset(UIOffset offset);

NSStringFromCGRect를 아십니까? 

NSLog로 CGPoint, CGRect를 찍어봐야 할일이 은근 많은데 보통 보면 아래와 같은 코드를 사용합니다.


 
    NSLog(@"%f,%f,%f,%f,",rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);

하지만 NSStringFromCGRect를 활용하면 %@ 한방에 찍을 수가 있습니다.
나온 결과는 아래와 같습니다.

2011-11-24 15:29:40.397 App[9981:f803] -[AppView layoutSubviews],33th - currenctRect = {{14, 20}, {768, 1024}}




XML을 파싱할 일이 생겨서,  이래저래 만져보다가 작업한 내용을 정리 합니다 :)

1. XML Parsing

Android 에서 제공하는 XmlResourceParser 를 사용하기로 했습니다.

XMLResourceParser는 다른 Java XML Parser들에 비해 성능이 좋은게 특징입니다.
이유인 즉은, 다른 Android XML 파일들 처럼, pre compiled 해서 birnary에 들어 가서 처리 하기 때문입니다.
아래는 간단하게 XML 을 읽어 들이는 코드 입니다. 
public Problem parseXML(XmlResourceParser xmlParser)
			throws Exception {

		Problem problem = new Problem();
		String name = null;

		while (xmlParser.getEventType() != XmlPullParser.END_DOCUMENT) {

			if (xmlParser.getEventType() == XmlPullParser.START_TAG) {
				name = xmlParser.getName();
			} else if (xmlParser.getEventType() == XmlPullParser.TEXT) {
				if (name == null) {
					Log.d("ProblemDAO-parseXML", "name is null ? error ??");

				}
			} else if (xmlParser.getEventType() == XmlPullParser.END_TAG) {
				name = null;
			}
			xmlParser.next();
		}

		return problem;
	}

2. XML to Pojo



a. 첫 번째 시도 - if 지옥

자 읽어 들인 XML을 Java Plaiin Object 로 매핑할 차리 인데요.

제일 처음 작업한게 아래와 같은 코드 입니다.
if(name.equalsIgnoreCase("title") == true) {
}
위와 같은 코드의 문제점은 if/elseif/elseif 지옥이 나타난다는것이죠. :(
그리고,  xml 형식등의 변경이 있을때, pojo/xml 이외에 추가로 관리할 곳이 늘어 난다는 점입니다.

b. 두 번째 시도 - Reflection

그래서 생각해낸것이 Java의 Reflection 입니다.

xml element 이름을 pojo 의 setter와 연결시키도록 아래와 같이 코드를 작성하였습니다..

               char[] stringArray = name.toCharArray();
		stringArray[0] = Character.toUpperCase(stringArray[0]);
		String methodName = "set"+ new String(stringArray);	
                try {
			Method m = Problem.class.getMethod(methodName, String.class);
			m.invoke(problem, text);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
				Method m = Problem.class.getMethod(methodName,Integer.class);
				m.invoke(problem,Integer.valueOf(text));
		}

조금 신경 쓴부분이 바로 Setter의 자료형 부분입니다.
m.invoke 가 없는 메소드 인 경우에, NoSouchMethodException을 발생시키기 때문에 이를 캐치하여,
다른 형으로 시도 해보도록 코드를 작성하였습니다.

3. 더 해볼것

추후에, JacksonMapper 등에서 어떻게 json 을 pojo화 시키는지 좀 스터디해보고 좀 더  좋은 방법이 있나 생각해봐야겠습니다 :)

facebook sdk 의 github 소개페이지


최근에 github 에 프로젝트를 하나 올렸는데,
제 프로젝트는 소개페이지가 허접한 TXT 파일인데, facebook 의 이렇게 wiki 처럼 포맷팅이된 것임을 확인했습니다 ;ㅂ;

이게 뭐야 하고 찾아보니, markdown 이라는 문법을 github에서 지원하는것이더군요.

마크다운 문법 페이지 링크

 그런데, 이건 로컬에서 작성하고, 서버에 올려서 계속 확인하자니, 여간 귀찮은게 아니더군요 ;ㅂ;

그래서 로컬에서 사용할 수 있는 Reader를 찾아보니, 역시나 있습니다 ^
Readown , MarkdownLive 라는 프로젝트가 있었고, 결론적으로 MarkdownLive를 계속 사용하기로 하여,
MarkdownLive를 소개합니다.

프로젝트 페이지 바로 가기 (https://github.com/rentzsch/markdownlive) 

 
위와 같이, 우측에 Preview, 좌측에 원본 파일이 나타나서, 에디팅하기 쉽게 되어 있습니다 ^^

github 를 사용하는 개발자라면, must have item 이 아닌가 생각합니다 :) 




제가 최근에 진행한 프로젝트에 작성한 소스코드중 재사용할 만한것들을 골라서, github에 올려보려고 합니다.

이걸 해보는 이유

1. git에 대한 사용법 공부
2. 제대로된 Open Source Project 운영에 대한 첫걸음

SimpleImagePickerhttps://github.com/Geekboard/SimpleImagePicker )

오늘 공개할 Project는 Simple ImagePicker 입니다.

UIImagePickerController를 사용할때, 카메라가 없는 장비(iPad1, and old iPod Touches) 를 서포트 하기 위해서,
SourceType을 체크해주어야합니다.

SourceType을 사용하는곳마다 해야하니, 여간 귀찮은게 아니더군요 ;ㅂ;
그래서 만들게 되었고 이렇게 공유합니다 ^^
 


Simulator에서도 스크린샷을 저장할 수 있는지 아셨나요? ;ㅂ;

단축키로도 쉽게 저장하 실수 있습니다.

+ Recent posts