> git clean -f 


디렉토리가 있는 경우에는 

> git clean -fd


git push #REMOTE --delete #BRANCH


> 덤으로 LOCAL branch 삭제는 아래와 같다.

git branch -d #BRANCH


iOS7 미만 버전 처리
 
        if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_6_1) {
            // ios6.1 이하 버전 
        }
iOS7 이상 버전 처리
 
        if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {
            // ios7 이상 버전 
        }

기존의 앱을 iPhone5 에서 실행 시키게 되면, 아래 와 같이 위아래 검은색으로 나오게 됩니다.

이를 통해서 따로 작업이 없더라도, 기존 앱들을 사용할 수 있게 해주는거지요.



그러나, 이래저래 만져보아도, 아이폰 5의 화면에 맞춰서 화면이 나오지 않는것입니다 ㅠ

처음에는 Window의 사이즈가 작게 설정 되어 있어서 그런가 했는데, 아니었습니다. 


바로 Launch Image의 유무에 따라, 화면 사이즈가 달라지는 것이었습니다 ( 이건 좀 .... )

뭐 구현 방식이 좀 맘에 들지 않지만 Launcher 이미지를 넣어 보도록 하겠습니다.

( 준비된 이미지가 없다면, New Project 를 하나 만드시면 검은색 이미지 Default로 있으니 사용하시면 됩니다. )




위와 같이 변경해주면 4인치 꽉 채워서 동작하게 됩니다.



What is a 'Raphael'?

Raphael 은 SVG 와 VML 에 기반한 Web 상에서 Vector Graphics을 지원하게 해주는 Javascript Library 입니다.

Rich Internet Applicatoin 을 개발할 일이 있어, 기술 조사 겸 해서 스터디 해볼려고 합니다.

언제나 그럿듯이 Hello World 를 한번 찍어 보도록 하겠습니다.


1. Download Raphael

http://raphaeljs.com/ 에서 다운로드 하시면 됩니다


2. Sample Page 작성 

3. javascript 작성


var paper = Raphael("hello",320,200);
var t = paper.text(50,50,"Hello Raphel");


hello 라는 div element 를 Raphael Paper 로 활용하게 되고,

그 Paper 에 text 를 그려 놓은 모습입니다. 




Raphel 로 Hello Raphael 을 출력한 모습입니다.

Elements 를 살펴 보면, svg tag 밑에 element 로 들어 가도록 변환이 되어서 나옵니다.

이것만 봐서는 뭐가 강력한지 모르겠지만, 차근 차근 알아 보도록 하겠습니다. 




1. Twitter API 찾기.

특정 Tweet을 Retweet 한사람을 조회 하는 API

https://dev.twitter.com/docs/api/1/get/statuses/%3Aid/retweeted_by

/statuses/:id/retweeted_by

* 주의 할점은 한번에 100명 까지만 조회 하기 때문에, parameter 중에 page 를 이용하여 추가 조회를 해야합니다.


2. Python 에서 Twitter API 호출하여, 20명 추출하기.

제가 분석할 tweet의 id 가 '194985314832490496' 임으로 호출 url 은 아래와 같이 됩니다. 

https://api.twitter.com/1/statuses/194985314832490496/retweeted_by.json

해당 json 은 Dictionary 의 array 로 되어 있습니다. 제가 필요 한건 리트윗 하신분의 id 임으로 'screen_name' 속성만 가져오면 될것 같습니다.

아래는 'Visual JSON'이라는 어플로 호출해본 결과 입니다.



# -*- coding:utf-8 -*-
import httplib
import urllib
import csv 
import codecs
import json
import random

tweet_id='194985314832490496'

def getJson(page):
    conn = httplib.HTTPConnection('api.twitter.com')
    conn.request("GET","/1/statuses/%s/retweeted_by.json?count=100&page=%s"%(tweet_id,page))
    response = conn.getresponse()
    data = response.read()
    encoding=response.getheader('content-type').split('charset=')[-1]
    conn.close()
    jsonData = json.loads(data)
    return jsonData

if __name__=='__main__':
    entries = []
    page=1
    while(1) :
        jsonData = getJson(page)

        for jsonItem in jsonData :
            entries.append(jsonItem['screen_name'])

        if len(jsonData) < 100:
            break

    random.shuffle(entries)
    winners = entries[0:20]
                                                                                                                                                                
    print winners

위의 코드는 해당 tweet의 screen_name 목록을 만들고 shuffle을 한후, 상위 20명만을 뽑아내는 코드 입니다.





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]];
}
* 장점 : 전화가 끝나면 현재앱으로 돌아온다.
* 단점 : 전화를 걸것인지에 대한 팝업이 한번더 뜬다 

 

+ Recent posts