아이폰어플개발정보2010. 6. 24. 14:22
iPhone SDK Tutorial 어플의 실행 순서

참 많이도 궁금했다. 실은 이런걸 먼저 습득한 후 개발에 들어가야 했었는데,

내가 알아낸건 앱이 최초 실행될 때의 과정에 대해서이다.

딜리게이트, XIB, 뷰, 뷰콘트롤러.. 그리고 이것들의 연결고리들.. 복잡해 보였기 때문에, 이 부분을 파는게 옳았다.

뷰에 관점을 두어야 한다.

뷰는 도화지다. 아니 화면이다. 사용자화면 말이다.

앱은 실행될 때 최초로 "화면에 뷰를 띄워야 한다" 는 것이다.

윈도우베이스로 프로젝트를 생성하고 실행시키게 되면 어떠한 뷰도 나타나지 않는다.

시뮬레이터에 보이는 것은 그냥 먹먹한 회색빛 화면이다.

따라서,

앱한테 최초에 어떤 뷰를 보여주어야 하는지 설정해줘야 한다. 이걸 어디서 하느냐면..

바로 딜리게이트에서 한다. 딜리게이트의 헤더에 뷰콘트롤러를 아웃렛으로 코딩해주고 구현부에서

해당 뷰콘트롤러가 가진 뷰를 윈도우의 뷰로 설정하라는 코드가 필요하다.

이하 헤더부

#import <UIKit/UIKit.h>

@interface SPWinBaseAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
UIViewController *viewContrller;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UIViewController *viewContrller;

@end

이하 구현부

#import "SPWinBaseAppDelegate.h"

@implementation SPWinBaseAppDelegate

@synthesize window;
@synthesize viewContrller;

- (void)applicationDidFinishLaunching:(UIApplication *)application {   

    // Override point for customization after application launch
[window addSubview:viewContrller.view];
    [window makeKeyAndVisible];
}


- (void)dealloc {
    [window release];
    [viewContrller release];
    [super dealloc];
}
@end

그리고 인터페이스 빌더에서 MainWindow.XIB 를 열고 라이브러리로부터 뷰콘트롤러를 드래그 하여 추가한다.

이제 위에서 코딩한 뷰콘트롤러 아웃렛이 바로 이녀석임을 설정!! (난 사실 이 부분이 너무 알고 싶었던 거다. 후후)


자, 이제 끝인가? 아니다.

뷰콘트롤러를 딜리게이트에 연결해줬고, 델리게이트의 런치피니쉬 메소드에서 메인윈도우의 뷰로 설정도 해줬지만

정작 뷰콘트롤러는 아무런 뷰도 가지고 있지 않다.

라이브러리를 통해서 뷰콘트롤러에 "뷰" 콘트롤을 추가해주고 실제 UI 작업은 그곳에서 해야 한다.

뷰를 올려놓으면 위 그림처럼 뷰콘트롤이 뷰콘트롤러의 하위 콘트롤로 생성이 되며, 그곳에 아무 라벨이나 올려놓고 실행해보자.




출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50081347132
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:22
iPhone SDK Tutorial 데이터 읽고 쓰기
파일을 읽고 쓰기...?
어떤 프로그래밍에서든 빠질 수 없는 부분이다.

예상대로 XML 형태의 데이터값들을 저장하고 읽는 방식으로 제공되고 있다.
바이너리라면 Base64 인코딩해서 XML 에 넣어야 할걸 ^^;;
일단 파일의 경로를 구하는 방법이다.
이걸 절대경로를 이용하는 방법은 절대 비추이다. 샌드박스의 절대경로를 알 수도 없을 것이다.
백북에서 시뮬레이터로 작업할 때 생기는 경로는 
/Users/nshc/Library/Application Support/iPhone Simulator/User/Applications 이다.

- (NSString *)dataFilepath {

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

return [documentsDirectory stringByAppendingPathComponent:@"data.plist"];

}


위 메소드를 통해서 파일 경로를 구하거나 지정하고 ^^;;; 아래 메소드는 읽는 부분이 되겠다.


- (void)viewDidLoad {

NSString *filePath = [self dataFilepath];

if ([[NSFileManagerdefaultManager] fileExistsAtPath:filePath]) {

NSArray *array = [[NSArrayalloc] initWithContentsOfFile:filePath];

//NSLog(@"파일값: %@", [array objectAtIndex:0]);

[array release];

} else {

//NSLog(@"파일없음 data.plist");

}

    [superviewDidLoad];

}


보면 알겠지만 array 를 이용하고 있는데 이 array 라는 녀석이 만능이다.

맥환경에서의 설정파일은 XML 형태를 이용하는 plist 파일이 일반적인데, 이 파일을 array 형태로 읽고 쓰기가 가능하다.

쓰기는 어떻게 할까?


- (void)saveData:(NSString *)pValue {

NSMutableArray *array = [[NSMutableArrayalloc] init];

[array addObject:pValue];

[array writeToFile:[self dataFilepath] atomically:YES];

[array release];

//NSLog(@"파일저장완료");

}


어때? 이 심플함이 매력이다. array 가 writeToFile 메소드를 제공하고 있다규~ 오예~!!

실은 이 파일의 내용은 어플이 마지막으로 실행된 정보를 저장하거나 읽기 위해 기록한 데이터인데..


마지막으로..

array 객체가 아닌 키-밸류 형태의 데이터 저장과 읽기 방법은 NSDictionary 객체를 이용하는데 방법은 아래와 같다.

- (void)readPlist
{
    NSString *filePath = @"/System/Library/CoreServices/SystemVersion.plist";
        NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];

        NSString *value;
        value = [plistDict objectForKey:@"ProductVersion"];
}

위에께 읽기 메소드고 쓰기는

- (void)writeToPlist
{
    NSString *filePath = @"/System/Library/CoreServices/SystemVersion.plist";
        NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];

        [plistDict setValue:@"1.1.1" forKey:@"ProductVersion"];
        [plistDict writeToFile:filePath atomically: YES];

}



출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50081533054
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:22
iPhone SDK 변수가 되는 메소드 (함수포인터)

Obj-C 를 한참 파고 있는 요즘.

내가 델파이로 자주 쓰던 패턴인 싱글톤과 약식옵저버를 구현할 수 있을까 고민했다. 싱글톤은 간단했다.

구현부에

static KNLocationManager *instance = nil;

@implementation KNLocationManager

+ (KNLocationManager *)sharedInstance {
 if (instance == nil) {
  instance = [[KNLocationManager alloc] init];
 }
 return instance;
}


참고로 아래껀 초기화 오버라이드

- (id)init {
    if ((self = [super init]) == nil)
        return nil;

    // 여기서 초기화하고..
    return self;
}


불러서 쓸때는 요렇게

- (void)viewDidLoad {
 KNLocationManager *knLocationManager = [KNLocationManager sharedInstance];

음.. 그래 싱글톤이야 뭐.. 그런데 메소드를 등록해놓고 나중에 특별한 이벤트가 발생했을 때 이 녀석을 실행시켜달라고 할 수는..?

콜백함수를 등록시키는 방법을 구현하고 싶었다.


Obj-C 에서는 메소드형을 SEL 이라는 지시자를 이용한다. 그러니까


@interface MyClass : NSObject {

id callBackTarget;

SEL callBackMethod;


이런식으로 선언할 수 있다는거다.

id 는 어떤 객체라도 받을 수 있는 객체형 와일드카드다 ^^;;

그리고 이 클래스를 사용하는 쪽에서 콜백함수를 등록시킬 수 있는 채널을 제공해야지?

MyClass에서 아래와 같은 메소드를 제공한다고 치자.


-(void)startPlus:(id)pCallBackTarget selector:(SEL)pCallBackMethod {

callBackTarget = pCallBackTarget;

callBackMethod = pCallBackMethod;


인자로 들어온 값들을 미리 선언해두었던 변수에 각각 저장해둔다.

왜냐하면 언젠가 특별한 일(?)이 생길때 저걸 이용해서 온파이어~ 를 해줘야 하니까.


자, 이제 MyClass에 온파이어를 하는 함수를 만들어보면..


- (void)fire {

IMP funcp;

funcp = [callBackTargetmethodForSelector:callBackMethod];

(*funcp)(callBackTarget, callBackMethod, 5);

}


5 는 뭘까? 파라메터 값을 테스트해본거다. MyClass 에 등록할 콜백함수의 원형을 보면


- (void)testCallback:(NSInteger)pParam1 {

NSLog(@"Callback function exected! %d", pParam1);

}


MyClass 로부터 값을 받고 있다. 파라메터값으로 말이지,

마지막으로 콜백함수를 등록하는 부분을 보고 끝내자


MyClass *myobj = [MyClasssharedInstance];

[myobj startPlus:selfselector:@selector(testCallback:)];


여기서 중요한 부분이 @selector 의 인자로 들어가는 콜러의 콜백함수 뒤에 콜론이다. ^^;;;

즉, 파라메터가 1개 있다는 뜻이다.



출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50081655391
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:22
iPhone NSURLConnection 을 이용한 파일 다운로드
NSURLConnection 을 이용하면 웹에 있는 파일을 쉽게 다운로드 할 수 있다.
그래. 쉽다. 그런데 이걸 알기까지는 결코 쉽지 않았다. 에휴..

NSURLConnection 을 쓰기 편하도록 KNURLDownloader 를 만들었다.
사용법은 간단하다.

- (void)start {

NSLog(@"Start Test drived development");

KNURLDownloader*knDownloader = [KNURLDownloadersharedInstance];

[knDownloaderdownload:@"http://211.115.217.70/down/ServicePort.plist"

callbackTarget:self

onComplete:@selector(onDownloadComplete:) 

onError:@selector(onError)];

}


정말 쉽지? 두개의 콜백메서드를 할당해줘야 한다. 한가지는 파일 다운로드가 완료되었을 때 동작할 메소드

다른 한가지는 에러가 발생했을때 동작할 메소드다.


그러니까. 이걸 사용하는 콜러에서는 두개의 메소드가 아래처럼 있음직하다.


- (void)onDownloadComplete:(NSMutableData *)pRcvData {

NSLog(@"onFire downloadcomplete callback function");

KNURLDownloader*knDownloader = [KNURLDownloadersharedInstance];

[knDownloader saveToFile:pRcvData pFileName:@"ServicePort.plist"];

}


- (void)onDownloadError {

NSLog(@"onFire downloaderror callback function");

}


다운로드가 완료되었을 때는 saveToFile 메소드를 이용해서 파일을 저장할 수 있다.

나중에 이 클래스를 계속 업그레이드 하면서 파일저장 메소드가 꽤나 많이 생길 것 같은데..




출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50082266140
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:22
iPhone NSDictionary 객체로 Plist (XML) 파일 읽기
너무 단순한가?
여기서 중요한 부분은 샌드박스 내의 경로를 읽어오는 것이다.

- (NSDictionary *)readPlistFile:(NSString *)pFilepath {

    NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(
                                                              NSDocumentDirectory,
                                                              NSUserDomainMask,
                                                              YES);
    NSString *docDir = [arrayPaths objectAtIndex:0];   
    NSString *filePath = [[NSString alloc] initWithFormat:@"%@/%@", docDir, pFilepath];   
    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:filePath];

    return dic;
}



근데, 이걸 작업하던 중에 재밌는 현상을 발견했는데, 아직 풀진 못했다.
A 라는 클래스에서 멤버변수로 NSDictionary 객체가 있다. 그리고 특정 메소드에서 위 녀석을 실행하게 되는데
그 메소드의 영역을 벗어나게 되면 멤버변수로 있던 딕셔너리객체가 다시 nil 이 되는거다. ㅡㅡ;;;
아니, 정확히 말해서 nil 인지 아닌지는 모르겠으나, 객체의 사용이 불가능해지는 걸로 보아 메모리 바이올레이션 오류를 내는듯 하다.

이걸 확인해봐야겠다.



출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50082356335
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:21
iPhone KNLocationManager 사용자의 위치정보 파악하기
"주의"
프로젝트에 프레임웍을 추가할때는 반드시!! 카피하지 말아야 한다. 단순히 레퍼런스만 추가되도록 하자.
만약 카피했다가는 아래와 같은 링킹오류를 맛보게 될 것이다.
.objc_class_name_CLLocationManager", referenced from: > collect2

책이 많이들 나와 있으며, 인터넷을 뒤져봐도 쉽게 파악할 수 있는 내용이다.
내가 만든건 위치가 국내인지 국외인지를 메서드로 추가한 정도이고, 델리게이트 부분을 함수포인터로 대체하였다.
나는 왜 델리게이트보다 함수포인터가 더 좋은걸까 ㅡㅡ;;;

우선 사용하는 쪽의 코드다. 콜러쪽
- (IBAction)pressButton:(id)sender {
       
    KNLocationManager *knTdd = [KNLocationManager sharedInstance];
    [knTdd findLocation:self onFind:@selector(onFind:) onError:@selector(onError)];
}

물론 싱글톤이다. 난 싱글톤도 대게 조아해 병적으루다가
보면 onFind 와 onError 에 대한 함수를 건네주도록 되어 있다.

즉, 아래 코드도 같이 있어야 한다는거다.
- (void)onError {
    // 오류난거다. 알아서 처리해 어플을 종료시키던지 아이폰을 폭팔시키던지 후~
}

파인드일때는 국내외를 확인하도록 하였다. CLLocation 형의 인자가 들어온다는걸 잊지말도록

- (void)onFind:(CLLocation *)pLocation {
    KNLocationManager *knTdd = [KNLocationManager sharedInstance];
    if ([knTdd isInKorea:pLocation]) {
        NSLog(@"한국 내에서 사용중");
    } else {
        NSLog(@"한국 외에서 사용중");
    }
}




출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50082379294
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:21
iPhone NSDictionary 와 Array 와 Plist(XML) 파일의 구조
키-밸류 코딩이라 하여 "Key=Value" 형태의 자료구조를 이용하는 개발방식인데,
델파이에서 TStringlist 정도의 편리함을 생각하면 되겠다.

그런데 이게 XML 파일과도 연계가 되어서 사용이 된다. 음.. 잠깐, 그런데 "Key=Value" 형태라고 하면
1대1 대칭자료형 아니냐? 그런데 1대N 형태의 자료구조도 가능하다는 얘기를 하고 싶은거다.

Key 는 보통 String 형으로 많이 사용한다. Value 역시 마찬가지지, 주로 프로퍼티 파일을 읽거나 쓸때 자주 쓰는데,
Value 를 단순 String 값이 아니라  String 들의 배열로 다룰 수가 있다. 아래 두가지 XML 파일이 있다. 이건 Plist 라는 iPhone 개발시에
주로 Property 파일로 활용되는 파일이다.

우선 1:1 방식인 경우

봐봐, 그냥 <key> 와 <string> 이다. 이런 경우에 값을 읽기 위해서는

iPhone 의 Document 폴더 밑에 있는 특정 "plist" 파일을 NSDictionary 로 읽어서 반환하는 메소드다.
- (NSDictionary *)readPlistFile:(NSString *)pFilepath {
    NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(
                                                              NSDocumentDirectory,
                                                              NSUserDomainMask,
                                                              YES);
    NSString *docDir = [arrayPaths objectAtIndex:0];   
    NSString *filePath = [[NSString alloc] initWithFormat:@"%@/%@", docDir, pFilepath];   
    NSDictionary *dic = [NSDictionary dictionaryWithContentsOfFile:filePath];
    return dic;
}

바이너리의 번들형태로 배포된 plist 파일을 읽을때는 이렇게 한다.

NSBundle* bundle = [NSBundlemainBundle];

NSString* plistPath = [bundle pathForResource:@"coordinates"ofType:@"plist"];

NSDictionary *dict = [NSDictionarydictionaryWithContentsOfFile:plistPath];


추가로 NSDictionary 로부터 모든 키들을 NSArray 로 뽑을때 정렬된 상태로 읽으려면

NSArray *array = [[dict allKeys] sortedArrayUsingSelector:@selector(compare:)];


가져온 NSDictionary 로부터 1:1 매칭의 자료를 쓰는건 매우 쉽다.
NSString *strKey = [[dict allKeys] objectAtIndex:index];
해당 index 에 존재하는 Key 를 가져온다. 그럼 그 key 에 해당하는 value 를 가져오려면
NSString *strValue = [dict objectForKey:"key"];

자, 이젠 1:1 이 아닌 1:N 인 경우를 보자. plist 파일의 구조는 아래와 같다.

이건 똑같다. 똑같다는게 무슨 말이냐면, value 를 받을때 array 로 받는다고 생각하면 끝 ㅡㅡ;;
코드 예는 이렇다.
NSArray *array = [dict objectForKey:@"A"];



출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50082987469
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:21
iPhone View Switching 을 위한 모달뷰(ModalView) 사용법
A 라는 뷰콘트롤러에서 B 라는 뷰콘트롤러의 뷰를 모달로 띄우고 싶을 때

방법1.
A 에서의 코드
- (IBAction)showModalview {
    ModalVWController *modalView = [[ModalVWController alloc] initWithNibName:nil bundle:nil];
    [self presentModalViewController:modalView animated:YES];

우후.. 쉽다.
닫을때는? 그건 B 에서 처리해줘야 한다. 이렇게
-(IBAction)closeView {
    [[self parentViewController] dismissModalViewControllerAnimated:YES];

음.. view 의 메서드를 이용하는 두번째 방법을 소개하면
방법2.
A에서의 코드
[[self view] addSubview:modalView.view];
그리고 닫을 때의 코드는
[[self view] removeFromSuperview];
이다.



출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50083064864
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:21
iPhone Tutorial - nib 에서 불러온 뷰를 특정위치에 모달로 띄우는 방법
- (void)showmodal:(UIView*)pParentView {

    UIView* modalView = [self view];
    
    CGPoint middleCenter = modalView.center;
    CGSize offSize = [UIScreen mainScreen].bounds.size;
    CGPoint offScreenCenter = CGPointMake(offSize.width / 2.0, -300);
    
    modalView.center = offScreenCenter; // we start off-screen
    [pParentView addSubview:modalView];
    
    // Show it with a transition effect
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:0.9]; // animation duration in seconds
    modalView.center = middleCenter;
    [UIView commitAnimations];
}

- (IBAction)hideModal
{    
    CGSize offSize = [UIScreen mainScreen].bounds.size;
    CGPoint offScreenCenter = CGPointMake(offSize.width / 2.0, -300);
    [UIView beginAnimations:nil context:[self view]];
    [UIView setAnimationDuration:0.9];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(hideModalEnded:finished:context:)];
    [self view].center = offScreenCenter;
    [UIView commitAnimations];
}
                                          
- (void) hideModalEnded:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{    
    UIView* modalView = (UIView *)context;
    [modalView release];



출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50084523871
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 6. 24. 14:21
iPhone Tutorial - 투명한 뷰 띄우기
뷰를 띄우는 쪽에서는 이런식으로. 중요부분은 백그라운드칼라를 재지정하는 것이다.
   
SeconViewController *viewctrl = [[SeconViewController alloc] initWithNibName:nil bundle:nil];
[viewctrl view].backgroundColor = [UIColor clearColor];
[self.view addSubview: viewctrl.view];

뷰를 닫는쪽은 띄워진 뷰다.
[[self view] removeFromSuperview];

근데, 이걸 알아내는데 고생을 한 배경이
뷰를 띄울때
[self presentModalViewController:viewctrl animated:YES];
이런 식으로 띄우면 절대 통하지 않는다는거다.



출처 : http://blog.naver.com/PostView.nhn?blogId=suny4rang&logNo=50084528217
Posted by 오늘마감

댓글을 달아 주세요