UINavigationController Customization Tutorial

In this tutorial I’ll go through various tasks that are usually performed with a navigation controller. Feel free to jump into a particular section if you’re looking for something specific, or leave a comment if you feel like something is missing.

Creating a UINavigationController programmatically

Creating a UINavigationController programmatically is trivial. Assuming that you’ve already created a class called RootViewController that subclasses UIViewController, you would use something like this, typically in your AppDelegate file:

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {        
  2.   
  3.     // rootViewController can't be an instance of UITabBarController  
  4.     // remember to include RootViewController in your class!  
  5.     RootViewController * rootViewController = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil];  
  6.   
  7.     UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];  
  8.   
  9.     [self.window addSubview:navigationController.view];  
  10.   
  11.     // Don't bother releasing navigationController as it needs to be around all the time  
  12.   
  13.     [self.window makeKeyAndVisible];  
  14.   
  15.     return YES;  
  16. }  

Basically, we just create an instance of root controller and then we use it to create the navigation controller. Finally, we need to add the navigation controller’s view to the main window.

Adding a title to a navigation controller

Actually you don’t add a title directly to the navigation controller, instead you add it to the view controller that’s being displayed:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5. }  

Hiding the Navigation Bar

Either in your view controller or where you initiated your navigation controller:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.     // hide the navigation bar  
  6.     // use setNavigationBarHidden:animated: if you need animation  
  7.     self.navigationController.navigationBarHidden = YES;  
  8. }  

Showing the navigation toolbar

Either in your view controller or where you initiated your navigation controller:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.     // hide the navigation bar  
  6.     // use setToolbarHidden:animated: if you need animation  
  7.     self.navigationController.toolbarHidden = NO;  
  8. }  

Changing the Navigation Bar background color

Either in your view controller or where you initiated your navigation controller:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.   
  6.     self.navigationController.navigationBar.tintColor = [UIColor   
  7.         colorWithRed:102.0/255   
  8.         green:52.0/255   
  9.         blue:133.0/255   
  10.         alpha:1];  
  11. }  

Changing the Navigation Bar style

Default style is UIBarStyleDefault, but you can use UIBarStyleBlack and eventually set the translucent propriety to YES.

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.   
  6.     self.navigationController.navigationBar.barStyle = UIBarStyleBlack;  
  7. }  

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.   
  6.     self.navigationController.navigationBar.barStyle = UIBarStyleBlack;  
  7.     self.navigationController.navigationBar.translucent = YES;  
  8. }  

Using a Navigation Bar background image

To use a background image for you navigation bar, you need to subclass UINavigationBar and declare your own drawRect method. You can add this code on its own file or at the top of your application delegate (after the import declarations):

  1. @implementation UINavigationBar (UINavigationBarCategory)  
  2.   
  3. - (void)drawRect:(CGRect)rect  
  4. {  
  5.     UIImage *image = [UIImage imageNamed:@"bg.png"];  
  6.   
  7.     [image drawInRect:rect];  
  8. }  
  9.   
  10. @end  

Changing Navigation Bar back button text

Here’s how to change the text of the back button:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.   
  6.     self.navigationController.navigationBar.backItem.title = @"Custom";  
  7. }  

Adding items to the right of your Navigation Bar

In your view controller:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.   
  6.     UIBarButtonItem *item = [[UIBarButtonItem alloc]   
  7.                              initWithBarButtonSystemItem:UIBarButtonSystemItemAdd   
  8.                              target:self   
  9.                              action:@selector(doSomething)];  
  10.     self.navigationItem.rightBarButtonItem = item;  
  11.   
  12.     [item release];  
  13. }  

Adding items to the Navigation Toolbar

To add items to your toolbar:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.   
  6.     // Show toolbar  
  7.     self.navigationController.toolbarHidden = NO;  
  8.   
  9.     UIBarButtonItem *item1 = [[UIBarButtonItem alloc]   
  10.                               initWithBarButtonSystemItem:UIBarButtonSystemItemAdd   
  11.                               target:self   
  12.                               action:nil];  
  13.   
  14.     UIBarButtonItem *item2 = [[UIBarButtonItem alloc]   
  15.                               initWithBarButtonSystemItem:UIBarButtonSystemItemEdit  
  16.                               target:self   
  17.                               action:nil];  
  18.   
  19.   
  20.     UIBarButtonItem *item3 = [[UIBarButtonItem alloc]   
  21.                               initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize  
  22.                               target:self   
  23.                               action:nil];  
  24.   
  25.     NSArray *items = [NSArray arrayWithObjects:item1, item2, item3, nil];  
  26.   
  27.     self.toolbarItems = items;  
  28.   
  29.     [item1 release];  
  30.     [item2 release];  
  31.     [item3 release];  
  32. }  

Note that the items are not properly aligned. To align them, use flexible space:

  1. - (void)viewDidLoad {  
  2.     [super viewDidLoad];  
  3.   
  4.     self.title = @"My View Controller";  
  5.   
  6.     // Show toolbar  
  7.     self.navigationController.toolbarHidden = NO;  
  8.   
  9.     UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]   
  10.                                       initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace   
  11.                                       target:nil   
  12.                                       action:nil];  
  13.   
  14.     UIBarButtonItem *item1 = [[UIBarButtonItem alloc]   
  15.                               initWithBarButtonSystemItem:UIBarButtonSystemItemAdd   
  16.                               target:self   
  17.                               action:nil];  
  18.   
  19.     UIBarButtonItem *item2 = [[UIBarButtonItem alloc]   
  20.                               initWithBarButtonSystemItem:UIBarButtonSystemItemEdit  
  21.                               target:self   
  22.                               action:nil];  
  23.   
  24.   
  25.     UIBarButtonItem *item3 = [[UIBarButtonItem alloc]   
  26.                               initWithBarButtonSystemItem:UIBarButtonSystemItemOrganize  
  27.                               target:self   
  28.                               action:nil];  
  29.   
  30.     NSArray *items = [NSArray arrayWithObjects:item1, flexibleSpace, item2, flexibleSpace, item3, nil];  
  31.   
  32.     self.toolbarItems = items;  
  33.   
  34.     [item1 release];  
  35.     [item2 release];  
  36.     [item3 release];  
  37. }  




      
Posted by k_ben

ios 버전 체크

컴퓨터/아이폰 : 2011. 7. 17. 15:18


float version = 0;
version = [[[UIDevice currentDevice] systemVersion] floatValue];

if(version >= 3.0 && version < 3.999)
{
// 3.0 인경우.;
}
else if(version >= 3.999 && version < 4.0999)
{
// 4.0 인경우.;
}
else if(version >= 4.0999 && version < 4.1999)
{
// 4.1 인경우.;
}
else if(version >= 4.1999 && version < 4.2999)
{
// 4.2 인경우.;
}
else {
}

      
Posted by k_ben


 

KT앱 대회 준비하면서 모은 자료들을 정리해서 올립니다.
거의 맥부기 카페 자료들이 대부분인데 한곳에 모아서 찾아보기 쉬우라고 올려봅니다.


-푸쉬  서버  개발  관련 자료-
이지 APNS 오픈 소스 라이브러리
http://www.easyapns.com/
구글 코드 APNS 오픈 소스
http://code.google.com/p/apns-php/
서버 튜토리얼
http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/


-label이나 textView에 현재 시간을 표시하고 싶습니다-
NSDate *t = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSString *timeStr = [formatter setDateFormat:@"HH:mm:ss"];
myLabel.text = timeStr;
...
[textView scrollRangeToVisible:NSMakeRange([textView.text length]-1, 1)];


-시뮬레이터 포토 라이브러리 자신의 이미지 추가 방법-
UIImage * sShot = [UIImage imageNamed:@"imageName.jpg"];
UIImageWriteToSavedPhotosAlbum(sShot, nil, nil, nil);


-네이게이션바 스타일 바꾸기-
http://cafe.naver.com/mcbugi/1241


-이미지 자르기 함수를 소개합니다. (UIImage)-

- (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)rect
{
CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], rect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return cropped;
}
http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/


-HTTP 라이브러리-
http://allseeing-i.com/ASIHTTPRequest/How-to-use


-json 관련-
라이브러리 http://code.google.com/p/json-framework/
json 투토리얼 http://iphonedevelopertips.com/networking/iphone-json-flickr-tutorial-part-1.html


-알럿 템플렛-
self.myAlertView = [ [UIAlertViewalloc]
initWithTitle:@"알림"
message:@"이메일을입력해주세요"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"확인", nil];
self.myAlertView.delegate = self;
[self.myAlertViewshow];


-푸쉬서버 구현을 위한 서버 인증서 pem 만들기-
애플 개발자 센터 apps ID 추가 (이때 와일드카드(*)는 사용하면 안됨)

키체인에서 개인 인증서 하나 만들어 애플 개발 센터에 등록

애플 개발센터에서 cert파일을 다운받아서 키체인으로 추가

키체인에서 내보내기로 p12파일로 저장

커맨드에서  p12파일을 pem파일로 변환
openssl pkcs12 -in quizers_dev_cert.p12 -out quizers_dev_cert.pem -nodes -clcerts


-전역변수를 사용해 보자...-
http://cafe.naver.com/mcbugi/55643


-JSON 2중 뎁스 이상 키 접근하기-
NSDictionary*feed =[self downloadPublicJaikuFeed];
// get the array of "stream" from the feed and cast to NSArrayNSArray*streams =(NSArray*)[feed valueForKey:@"stream"];
// loop over all the stream objects and print their titlesint ndx;
NSDictionary*stream;
for(ndx =0; ndx &lt; stream.count; ndx++){
        NSDictionary*stream =(NSDictionary*)[streams objectAtIndex:ndx];
        NSLog(@"This is the title of a stream: %@", [stream valueForKey:@"title"]); 
}


-배열 NSArray-
초기 데이터로 생성
NSArray *array = [[NSArray alloc] initWithobjects:추가할 객체들.. , nil];
 스트링으로 생성
NSArray *joins =(NSArray*)[result objectForKey:@"joins"];
길이 구하기
NSLog(@"Array size : %d " , sizeof(BUILDING_DATA) / sizeof(BUILDING_DATA[0]));


-NSString 클래스를 이용하여 문자을 넣자니 유니코드를 받아 초기화-
-(NSUInteger) UnicharLength:(const unichar*)str
{
unichar* pStr = (unichar*)str;
for( ; pStr[0] != nil ; pStr++ );
return (NSUInteger)(pStr - str);
}
[[NSString alloc] initWithCharacters:(원본문자열) length:[self UnicharLength:(원본문자열)]];


-랜덤 출력-
srandom(time(NULL));
value = random() % 100;
위처럼 하시면 0~99사이의 한수를 리턴합니다.
srandom(time(NULL)); 는 첨에 한번만 해주시면 됩니다.


-Code Sign error: Provisioning profile이 맞지 않을 때 변경 방법-
여러 장비에서 작업을 하거나 여러 프로젝트를 진행 중에 변경된 Provisioning profile이 적용되지 않아 Debug를 할 때 ”Code Sign error: Provisioning profile ‘3E6AA725-6534-46F8-B9CE-D19AC9FD854B’ can’t be found” 이런 오류가 발생하는 경우가 있는데요. 이럴 때 현재 사용중인 Provisioning Profiles로 프로젝트 세팅을 변경해주는 방법을 소개한 글(원문)이 있어서 공유합니다.

1. 실행중인 Xcode Project를 닫습니다.
2. Finder에서 프로젝트 폴더로 이동합니다.
3. 프로젝트 .xcodeproj 파일 선택하고 마우스 오르쪽 키를 눌러 '패키지 내용 보기'를 선택합니다.
4. 패키지 내용 보기를 통해 패키지 안에 있는 project.pbxproj 파일을 Xcode로 불러옵니다.
5. 검색을 통해 PROVISIONING_PROFILE 부분을 찾아 변경된 Provisioning profile 로 변경해줍니다.
6. 현재 Provisioning profile을 확인하려면 Organizer 창을 열어보면 알 수 있습니다.
7. Window > Organizer로 Organizer 창을 열고 왼쪽에 IPHONE DEVELOPMENT > Provisioning Profiles로 이동합니다.
8. 오른쪽에 있는 Profile Identifier를 복사해서 변경해주면됩니다.
9. 변경이 끝나면 project.pbxproj 저장하고 프로젝트를 열어 테스트합니다.


-아이폰 웹개발에서 디바이스 아이디 가져올수있나요?-
[[UIDevice currentDevice] uniqueIdentifier];



-Accessing Objects in a NSArray-
To access an object in an NSArray, you use the -objectAtIndex: method, as in the following example:NSArray *numbers;
NSString *string;

numbers = [NSArray arrayWithObjects: @"One", @"Two", @"Three", 
                                     nil];
string = [numbers objectAtIndex: 2];   // @"Three"

Of course, you have to be careful not to ask for an object at an index which is negative or bigger than the size of the array; if you do, an NSRangeException is raised (we'll learn more about exceptions in another tutorial).
To get the length of an array, you use the method -count, as in:
NSArray *numbers;
int i;

numbers = [NSArray arrayWithObjects: @"One", @"Two", @"Three", 
                                     nil];
i = [numbers count];   // 3


-상태바 제어-
안 보이게
[UIApplication sharedApplication].statusBarHidden = NO;

스타일
UIApplication *myApp = [UIApplication sharedApplication];
[myApp setStatusBarStyle:UIStatusBarStyleBlackOpaque];


-메모리 오버되어서 어플이 죽는 경우에 호출되는 이벤트??-

뷰컨트롤러 베이스로 작업을 한다면

- (void)didReceiveMemoryWarning

함수로 메모리가 위험할시에 위 함수를 핸들링하니 내부에 관련 대응할 처리를 구현해주면 됩니다.



-D-Day 구하기-
NSDate* date  = [NSDatedateWithNaturalLanguageString:@"2010-06-30"];
NSDate* d_day = [NSDatedateWithNaturalLanguageString:@"2010-12-31"];

NSDateComponents *dcom = [[NSCalendar currentCalendar]components: NSDayCalendarUnit
fromDate:date  
  toDate:d_day  
  options:0];

NSLog(@"day=%d",   [dcom day]);   // 184


-라디오 버튼이나 체크박스등을 찾지를 못하고  있는데-
Interface Builder 에서 library를 보시면 segmented control, switch가 보일겁니다.
말씀하시는 라디오버튼이나 체크박스는 없지만  
라디오버튼은 segmented control로 대체, 체크박스는 switch 로 대체하셔서 사용하시면 될듯합니다.


-책장 넘기기 효과-
UIView 를 하나 만들고 그 안에 UIImageView 를 만들었습니다.
이제 이미지뷰어의 내용을 채울때 책장을 넘기듯이 넘기는 방법입니다.

[UIView baginAnimations:@"stalker" context:nil]; <- stalker 는 UIView 의 이름입니다
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:stalker cache:YES];
[UIView setAnimationDuration:1.0];
imageView.image = [UIImage imageNAmed:이미지파일명];
[UIView commitAnimations];

이 걸 터치 이벤트나 이런곳에 삽입하면
책장을 넘기듯이 이미지의 전환이 일어납니다. 


-image를 fade out 효과-
[UIView beginAnimations:nil context:NULL];
[imageView setAlpha:0.0];
[UIView commitAnimations]; 


-UIView Animation 중복방지-
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveLinear]; 
....
[UIView setAnimationDelegate:self]; 
[UIView setAnimationDidStopSelector:@selector(animationFinished:finished:context:)];
        [UIView commitAnimations];

이런 식으로 에니메이션을 만들었는데 간단하게 UIImageView를 한점에서 다른 한점으로 이동시킵니다.
근데 그래서 에니매이션이 끝나면 다시 또다른 다른 두 좌표로 해서 위의 코드가 실행되서 계속해서 UIImageView를 움직이게 하고 있습니다.

근데 질문은 1. setAnimationDidStopSelector 에서 에니매이션이 끝난것을 알기전에 강제로 에니메이션을 멈출수 있나요?
2. 제 경우에는 어떤 경우에 위 코드가 setAnimationDidStopSelector 가 호출되었을때 만 실행되는 것이 아니라 다른 부분에서도 호출하기도 합니다.  근데 문제는 동시에 위 코드가 중복되어서 호출되면 이상하게 작동해요.  그래서 꼭 위 코드를 실행(에니매이션을 commit 하기전에는 반드시 에니메이션을 강제로 멈추던지 아니면 다른 체크를 해야 할것 같은데.....  

혹시 방법이 있으면 부탁드립니다.

꾸벅~

답글 : 
[UIView setAnimationsEnabled:NO];
// 에니메이션을 종료 합니다. 


-일정시간 딜레이 후 함수 호출-
[self performSelector:@selector(playerStop) withObject:nil afterDelay :1.0f];

-(void) playerStop 
{
}


-개발 완료, 베타 테스팅용 Ad Hoc 배포-
http://cafe.naver.com/mcbugi/9042


-테이블뷰에 원격이미지를 넣을경우 스크롤이 느려지는 현상-
LazyTableImages 샘플 http://developer.apple.com/iphone/library/samplecode/LazyTableImages/Introduction/Intro.html#//apple_ref/doc/uid/DTS40009394
AsyncImageView 클래스 http://www.markj.net/iphone-asynchronous-table-image/


-테이블 뷰 섹션별로 이름 주기-
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
if( section == 0 ) {
return@"발행한퀴즈";
} elseif( section == 1 ) {
return@"참여한퀴즈";
} else {
return@"진행중인퀴즈";
}
}


-정사각형으로 사진을 CROP 하고, 썸네일 크기에 맞게 리사이즈-
먼저, 출처는 다음 기사입니다.
http://tharindufit.wordpress.com/2010/04/19/how-to-create-iphone-photos-like-thumbs-in-an-iphone-app/ 
 
iPhone 사진앨범의 특징은 가로나 세로가 긴 이미지라 할지라도,
정사각형으로 사진을 CROP 하고, 썸네일 크기에 맞게 리사이즈 시킵니다.
 
위의 기사의 내용을 나름대로 보기 편하게(?) 수정을 했습니다.
 
함수명 - makeThumbnailImage
파라미터 - 원본 이미지, 리사이즈없이 CROP만 할지 여부, 리사이즈할 정사각형 한변의 길이
리턴값 - CROP 및 리사이즈된 이미지
 
- (UIImage*) makeThumbnailImage:(UIImage*)image onlyCrop:(BOOL)bOnlyCrop Size:(float)size
{
 CGRect rcCrop;
 if (image.size.width == image.size.height)
 {
  rcCrop = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
 }
 else if (image.size.width > image.size.height)
 {
  int xGap = (image.size.width - image.size.height)/2;
  rcCrop = CGRectMake(xGap, 0.0, image.size.height, image.size.height);
 }
 else
 {
  int yGap = (image.size.height - image.size.width)/2;
  rcCrop = CGRectMake(0.0, yGap, image.size.width, image.size.width);
 }
 
 CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], rcCrop);
 UIImage* cropImage = [UIImage imageWithCGImage:imageRef];
 CGImageRelease(imageRef);
 if (bOnlyCrop) return cropImage;
 
 NSData* dataCrop = UIImagePNGRepresentation(cropImage);
 UIImage* imgResize = [[UIImage alloc] initWithData:dataCrop];
 
 UIGraphicsBeginImageContext(CGSizeMake(size,size));
 [imgResize drawInRect:CGRectMake(0.0f, 0.0f, size, size)];
 UIImage* imgThumb = UIGraphicsGetImageFromCurrentImageContext();
 UIGraphicsEndImageContext();
 [imgResize release];
 return imgThumb;
}

위 소스를 참고하시면, 이미지를 CROP 하는 방법이나, 이미지를 RESIZE 하는 방법을 참고하실수 있을겁니다.
 
사족을 붙이자면, 왜 Resize 할지 여부를 따로 분리 시킨 이유는 실제로 사용을 해보면 Resize 루틴에서
많은 CPU 부하가 걸립니다. 그래서 UIImageView 에  contentMode를 UIViewContentModeScaleAspectFit 로 설정해서
자체적으로 리사이즈를 하게 하는 방법이 비동기적으로 괜찮습니다. (물론.. 실제 Resize된 이미지가 아니므로 메모리적인 소비는 있습니다.)
 
많은 도움 되셨으면 좋겠네요 ^^


-사진찍을때  아래에서  올라오는  메뉴 UIActionSheet-
http://ykyuen.wordpress.com/2010/04/14/iphone-uiactionsheet-example/


-uibutton disable-
http://www.iphonedevsdk.com/forum/iphone-sdk-development/2499-uibutton-disable.html


-이미지  슬라이드  샘플-
http://lievendekeyser.net/index.php?module=messagebox&action=message&msg_id=1351


-커버플로우  라이브러리-
http://apparentlogic.com/openflow/


-Xcode3.2.3과 SDK4로 업그레이드 후, 기존 앱 업그레이드 하는 법-
XCode3.2.3 과 SDK4로 버전업한 후, 기존 앱을 업그레이드 할 때 간단한 Tip 입니다.
1. XCode3.2.3과 SDK4로 업그레이드 한다. 별도로 기존 XCode 3.1 버전을 따로 보관할 필요가 없습니다.
2. 기존 앱을 새 XCode3.2.3에서 연다.
3.Group & Files를 right click -> Get Info 후
  3-1.General Tab 에서
Project Format 을 Xcode 3.2-compatible 로 바꾼다.
 3-2.Build Tab 에서
 Base SDK를 iPhone Device 4.0(배포시), 혹은 iPhone Simulator 4.0(테스트시) 로 바꾼다
 iPhone OS Deployment Target 을 iPhone OS 3.0 (즉 지원하고자 하는 하위버전으로) 로 바꾼다.
이렇게 하시면 됩니다.


-객체 타입 비교-
if ( [a isKindOfClass:b] )


-문자열 비교-
NSString *strText = idField.text;
if([srText isEqualToString:@"mihr01"])
....
else if([srText isEqualToString:@"mihr02"])
....
else
...
이렇게 하셔도 되고요 완전 같은 스트링이 아니라
 
포함된것을 찾으려면
if([strText rangeOfString:@"mihr01"].length) 


-탭뷰에 스타일시트를 붙일때-
UIActionSheet *popupQuery = [[UIActionSheetalloc]
initWithTitle:nildelegate:self
cancelButtonTitle:@"취소"
destructiveButtonTitle:nil
otherButtonTitles:@"사진찍기", @"기존의사진선택", nil];
popupQuery.actionSheetStyle = UIActionSheetStyleBlackOpaque;
QuizersAppDelegate *appDelegate = (QuizersAppDelegate *)[[UIApplicationsharedApplication] delegate];
[popupQuery showInView:appDelegate.window];


-스크롤  밀어서  데이터  리플래쉬  하기-
소스코드
http://github.com/facebook/three20/tree/master/samples/TTTwitter/
설명
http://www.drobnik.com/touch/2009/12/how-to-make-a-pull-to-reload-tableview-just-like-tweetie-2/


-테이블뷰 위에 검색창 붙이는 방법-
테이블뷰 위에 검색창 넣으신 후에, viewDidLoad 메서드 부분에 [table setContentOffset:CGPointMake(0.0, 44.0) animated:NO];해주시면 처음 보여질 때는 검색창이 안 보이다가 밑으로 땡기면 나타나게 됩니다.


-네트워크  연결  됐는지  확인 Reachability-
http://www.raddonline.com/blogs/geek-journal/iphone-sdk-testing-network-reachability/
http://theeye.pe.kr/entry/how-to-check-network-connection-on-iphone-sdk



-아이폰 강제종료 버튼 이벤트-
아래 메소드가 어플이 종료될 때 수행되는 함수입니다.
종료될 때에 각종 리소스들을 Free시킬 경우에 사용됩니다.
참고하시면 될 듯 합니다~
 - (void)applicationWillTerminate:(UIApplication  *)application



-크랙 방지 클래스-
http://cafe.naver.com/mcbugi/11661



-어플을 강제 종료하는 API 는 아이폰에서 제공하지 않는다?-
http://cafe.naver.com/mcbugi/11803



-탭바 클릭시 바로 UISearchBar 클릭되도록 할려면 어떻게 해야 하나요?-
UISearchBar가 first responder가 되게 하면 됩니다.
[searchBarObj becomeFirstResponder];



-UITextField 입력값 체크하기 : 문자열 길이, 숫자여부 체크-

헤더(.h)에 UITextFieldDelegate 선언

@interface 클 래스명 : UIViewController <UITextFieldDelegate>



구현부(.m)에 다음 메쏘드를 구현하면 됨

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { 

//return NO하면 입력이 취소됨
//return YES하면 입력이 허락됨
//textField 이용해서 어느 텍스트필드인지 구분 가능

//최대길이

int maxLength = 128;

NSString *candidateString;

NSNumber *candidateNumber;


//입력 들어온 값을 담아둔다

candidateString = [textField.text stringByReplacingCharactersInRange:rangewithString:string];


if(textField == IDField) {
maxLength = 8;
} else if(textField == AgeField) {
//숫자여부 점검

//length가 0보다 클 경우만 체크
//0인 경우는 백스페이스의 경우이므로 체크하지 않아야 한다

if ([string length] > 0) {

//numberFormatter는 자주 사용할 예정이므로 아래 코드를 이용해서 생성해둬야함

//numberFormatter = [[NSNumberFormatter allocinit];

//[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];


//numberFormatter 를 이용해서 NSNumber로 변환

candidateNumber = [numberFormatter numberFromString:candidateString];


//nil이면 숫자가 아니므로 NO 리턴해서 입력취소

if(candidateNumber == nil) {

return NO;

}


//원 래 문자열과 숫자로 변환한 후의 값이 문자열 비교시 다르면

//숫자가 아닌 부분이 섞여있다는 의미임

if ([[candidateNumber stringValuecompare:candidateString] != NSOrderedSame) {

return NO;

}


maxLength = 2;

}

}

//길이 초과 점검

if ([candidateString length] > maxLength) {

return NO;

}


return YES;

}

http://cafe.naver.com/mcbugi/37651



-How to split string into substrings on iPhone?-
http://stackoverflow.com/questions/594076/how-to-split-string-into-substrings-on-iphone



-메모리 누수-
http://cafe.naver.com/mcbugi/64257


-디바이스 가로 세로 상태-
UIDeviceOrientationIsLandscape([UIDevicecurrentDevice].orientation) ?


-UITextField 에 자동 포커스 주기-
키보드 올리면서 커서를 넣을때는 아래방법을 이용하시면 됩니다.
[textField becomeFirstResponder]; 
참고로 이건 커서를 빼면서 키보드를 내리실때 사용하시면 되구요...
[textField resignFirstResponder]; 


-홈버튼이 눌렸을 때도 텍스트뷰 내용을 저장하려면 어떻게 해야할까요?-
- (void)applicationWillTerminate:(UIApplication *)application / Application Delegate 메서드 부분에 구현하시면 되지않을가요? 


-3.2 4.0  동영상  플레이-
http://iphonedevelopertips.com/video/getting-mpmovieplayercontroller-to-cooperate-with-ios4-3-2-ipad-and-earlier-versions-of-iphone-sdk.html


-한글완성형(EUC-KR)을 iPhone/Mac에서 사용할 수 있는 언어셋으로 변환하기-
http://blog.backpackholic.tv/160


-인터페이스 함수들을 편하게 가져오는 방법-
http://code.google.com/p/xcode-auto-assistant/


-#pragma mark로 코드 쉽게 구분하기-
http://cafe.naver.com/mcbugi/64408


-os4에서 applicationWillTerminate가 안먹어서 알게된것-
os4에서 applicationWillTerminate: 가 안먹어서 삽질하다가 알아낸 결과입니다.
뒷북 인지는 모르지만 혹시 모르시는 분을 위해서 적어봅니다.
os3.x 에서는 홈버튼을 한번만 누르면 applicationWillTerminate 가 아주 잘 호출됩니다.
하지만 os4 에서는 홈버튼을 한번만 누르면 
applicationDidEnterBackground 가 호출됩니다.
os4 에서 멀티태스킹을 위해서 좀 바뀌었습니다.
os4에서도 홈버튼 한번 누를때 applicationWillTerminate 가 호출되게 하려면
info.plist 에서 'Application does not run in background' 이 속성을 추가해주면 됩니다.
위 속성이 없으면 기본적으로 멀티태스킹이 되는걸로 간주합니다. (진짜 멀티태스킹은 아니지만)
위 속성이 없을때 호출되는 메소드를 실험해 봤습니다.
-----------------------------------------------------------------
처음 어플을 실행시키면
     didFinishLaunchingWithOptions, 
applicationDidBecomeActive 
이 호출되고
홈버 튼을 한번 만 누르면
applicationWillResignActive, 
applicationDidEnterBackground
호출되면서 어플이 종료되고
이상태에서 다시 어플을 실행시키면
applicationWillEnterForeground, 
applicationDidBecomeActive 
호출됩니다.
홈버튼을 두번 누르면
applicationWillResignActive
이 호출됩니다.
----------------------------------------------------------------
'Application does not run in background' 을 체크하면
홈버 튼을 한번만 누르면 applicationWillTerminate 를 호출합니다.
'근데 속성 체크 안했을때 applicationWillTerminate 는 호출이 안되는건지 궁금하네요.
아시는 분 좀 알려주세요.

답글 : 
Applicationwillterminate함수 대신에 applicationDidENterBAckground 사용하라고하네여 이곳에서 공유자원해제나 사용자데이타 저장,타이머 무효화,어플상태정보등 저장을 하라고 합니다. http://cafe.naver.com/mcbugi/65497


-COCOS2D 번개 효과-
http://www.cocos2d-iphone.org/forum/topic/370


-iPhone 4.0 호환 키보드에 버튼 or 뷰 붙이기-
기존꺼에 비해 약간 수정되 었을뿐입니다....
하지만 -_-이거 찾느라 ㅠㅠ;; 

3.1.x에서는 windows 서브뷰에 항상 키보드 뷰가 있었지만 ...
4.0 부터는 windows 에 항상 있는게 아니고, 키보드를 불렀을때 -_- 붙어서 오더라고요.. 그래서

Done 버튼 붙이는 예제 입니다. (Number 패드에)

아래 액션을 Text필드의 BeginTouched 에 연결 시킵니다.
 // 키보드가 나왔을때랑 사라질때의 이벤트를 잡아냅니다.
//3.1.X 에서는 UIKeyboardWillShowNotification 으로 잡지만
// 4.0 때문에 --; DidShow로 잡아줬습니다.
//그래야 윈도우에 키보드가 있더라고요 ;;;
-(IBAction)FieldTouched{
    
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardDidShowNotification
                                               object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillHide:) 
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];
    
    
}

// 키보드가 나왔을때 Done 버튼 붙여주기 
- (void)keyboardWillShow:(NSNotification *)note {  
    
    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    doneButton.frame = CGRectMake(0, 163, 106, 53);
    doneButton.adjustsImageWhenHighlighted = NO;
    [doneButton setImage:[UIImage imageNamed:@"DoneUp.png"] forState:UIControlStateNormal];
    [doneButton setImage:[UIImage imageNamed:@"DoneDown.png"] forState:UIControlStateHighlighted];
    [doneButton addTarget:self action:@selector(backgroundTap:) forControlEvents:UIControlEventTouchUpInside];

    //3.1.x 와 4.0 호환 키보드 붙이기
    for( UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows] ){
        for( UIView *keyboard in [keyboardWindow subviews] ){
            NSString *desc = [keyboard description];
            if( [desc hasPrefix:@"<UIKeyboard"]==YES ||
               [desc hasPrefix:@"<UIPeripheralHostView"] == YES ||
               [desc hasPrefix:@"<UISnap"] == YES )
            {
                [keyboard addSubview:doneButton];
            }
        }
    }
    
}

// 키보드가 없어질때 Done 버튼을 삭제 합니다.
- (void)keyboardWillHide:(NSNotification *)note {  
    
    for( UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows] ){
        for( UIView *keyboard in [keyboardWindow subviews] ){
            NSString *desc = [keyboard description];
            if( [desc hasPrefix:@"<UIKeyboard"]==YES ||
               [desc hasPrefix:@"<UIPeripheralHostView"] == YES ||
               [desc hasPrefix:@"<UISnap"] == YES )
            {
                for(UIView *subview in [keyboard subviews])
                {
                    [subview removeFromSuperview];
                }
                
            }
        }
    }
}

도 움 되시길 바랍니다 ;)
http://cafe.naver.com/mcbugi/62349


-배열내 숫자 값 비교해서 정렬하기-
만약에 객체내의 인스턴스를 키로 정렬할 경우에는 NSSortDescriptor 를
쓰시면 됩니다.
아래는 name으로 정렬한 예입니다.

@interface Test :
NSObject {
NSString *name;
double distance;
}
@property
(nonatomic, retain) NSString *name;
@property double
distance;
@end

@implementation Test
@synthesize name, distance;
@end


아 래는 사용방법입니다.
       Test *t1 = [[Test alloc] init];
Test *t2 = [[Test alloc] init];
Test *t3 = [[Test alloc] init];
[t1 setName:@"마바사"];
[t2 setName:@"아자차"];
[t3 setName:@"가나다"];
[t1 setDistance:1.2];
[t2 setDistance:2.5];
[t3 setDistance:0.5];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:t1];
[array addObject:t2];
[array addObject:t3];
[t1 release];
[t2 release];
[t3 release];
// 이름순으로 정렬
NSSortDescriptor *nameSort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCompare:)];
[array sortUsingDescriptors:[NSArray arrayWithObjects:nameSort, nil]];
[nameSort release];
for(Test *t in array) {
NSLog(@"%@ %f", [t name], [t distance]);
}
[array removeAllObjects];


------[결 과]------
2010-07-12 17:46:13.117 Sort[5070:20b] 가나다 0.500000
2010-07-12 17:46:13.125 Sort[5070:20b] 마바사 1.200000
2010-07-12 17:46:13.130 Sort[5070:20b] 아자차 2.500000


p.s. distance로 정렬하고자 한다면 
NSSortDescriptor *distanceSort = [[NSSortDescriptor alloc] initWithKey:@"distance" ascending:YES];
nameSort 대신 distanceSort를 넣으시면 됩니다.
http://cafe.naver.com/mcbugi/65873


-[TIP] 시뮬레이터 사진앨범에 사진넣기-
1) 시뮬레이터를 실행시킵니다.

2) 맥에서 포토라이브러리에 넣을 사진을 시뮬레이터로 Drag&Drop 합니다.

3) 그러면, 사파리가 열리면서 Drag한 이미지가 표시가 될겁니다.

4) 그 표시된 이미지를 마우스로 꾸~~~~~~욱 눌러줍니다.

5) 그러면, 메뉴가 뜨면서 이미지를 저장할건지 복사할건지를 묻습니다.

6) 이미지 저장을 누릅니다.

7) 이제 시뮬레이터의 사진앨범에 가 보시면 아까 저장한 사진이 들어가있을겁니다.

'컴퓨터 > 아이폰' 카테고리의 다른 글

UINavigateionController을 잘 정리해놓은 자료  (0) 2011.08.03
ios 버전 체크  (0) 2011.07.17
아이폰 다음버전 출시설..ㅋ  (0) 2011.06.24
UIWebView와 Application(App) 간의 통신  (0) 2011.06.24
push notification  (0) 2011.06.24
      
Posted by k_ben


요즘들어 참 기사들이 많이 나오네..
삼성뿐만 아니라 여러 회사에서 신기종들이 쏟아져나오기땜시..
애플에서도 더 이상 두고 볼수만은 없을터이고..
분명 9월에 뭔가 나오긴 할터인데..ㅋㅋ

과연 뭐가 나올것인가..
아이폰4s가 나올것인가..아님 정말 아이폰5가 나올것인가..

뭐가 됐든 빨리 나왔음 좋겠네..
개발하는데 개발기기가 없으니..이거 원...ㅜ_ㅜ
지금 가지고 있는 폰도 벌써 3년째...헐;;
9월달에 4s가 됐든 5가 됐든 나오면 바로 산다..ㅋㅋ
근데 기왕이면 5가 나왔음 하는데...오늘부터 기도나 해볼까나..쩝;

빨리 잡스형이 뭔가 발표를 해줘야 하는데...
한 8월쯤에는 루머가 아닌 뭔가 제대로된 기사들이 나오겠지..
어여 나와라...
그리고 가격은 비싸지 않게 나와라...ㅋㅋㅋ 

어여 폰 바꾸고 싶다...ㅜ_ㅜ 

'컴퓨터 > 아이폰' 카테고리의 다른 글

ios 버전 체크  (0) 2011.07.17
아이폰 OS 개발 자료 총정리  (0) 2011.06.29
UIWebView와 Application(App) 간의 통신  (0) 2011.06.24
push notification  (0) 2011.06.24
DES암호화  (0) 2011.06.24
      
Posted by k_ben




'컴퓨터 > 아이폰' 카테고리의 다른 글

아이폰 OS 개발 자료 총정리  (0) 2011.06.29
아이폰 다음버전 출시설..ㅋ  (0) 2011.06.24
push notification  (0) 2011.06.24
DES암호화  (0) 2011.06.24
나침반 소스  (0) 2011.06.24
      
Posted by k_ben

push notification

컴퓨터/아이폰 : 2011. 6. 24. 14:15


 

 

 

오늘은 푸시서버를 구현해보도록 할께요

카카오톡이나 많은 SNS서비스를 제공하는 앱들이 해당 기능을 활용하여 통신을 하고 있죠?

 

간단할 것 같지만, 막상 해보면 어디서 시작해서 어떤 방식으로 구현을 해야하는지 막막할 수 있어요

저 또한 그랬고 그래서 많은 서핑들을 하게 되는데, 

 

항상 뭔가 아쉽더라구요.

너무 쉬워서 생략해놓은 곳도 있고 기본이라고 생각하고 그냥 언급하지 않은 내용들 때문에

하나 성공하고 나면 결국 다른걸로 막혀서 또 검색하고,,,  그걸 반복하면. 반나절이 지나가더라구요

 

저 처럼 헤매실 분들을 위하여 정리해보아요~

 

 

 

"렘군와 함께하는 푸시서버 만들기"

 

자~ 한 시간만 따라하면 아이폰으로 "Hello World" 메세지가 뜰 수 있어요~

대신 엄청 집중하셔야 되요~

 

깔끔하게 Action위주로 정리해서 알려드릴께요

(참고로 APNS는 시뮬레이터에서는 테스트 불가능,개발자라이센스 보유하여야 아이폰장비에서 테스트가능)

 

 

 

  가정1 : Provisioning Portal 에서 Certificates, Devices  등록되어 있다는 가정

            만약 안되어 있다면 ->  http://artyst.egloos.com/2650529 참고 (보노님 블로그)

 

  <가정1 요약>

   1. App IDs 등록

   일단, APNS 테스트를 위해서 App등록부터 해야되요. 아직 프로젝트 진행은 아니고 테스트단계니까

   일단 편하게 이름짓자구요. 저는 APNS로 일단 등록했어요

   어디서 하는지 알죠?

   developer.apple.com 사이트 > member center > provision Portal 접속 > App IDs

 

   2. Provisioning 생성

   프로비저닝 명 정해주고, 인증서 선택하고, 1번에서 만든 App ID 선택하고 Devices 선택해주면되죠

 

 

 

 

 

  가정2 : APNS SSL Certificate 발급 받고 xCode 프로젝트속성에 설정 잡았다는 가정

          만약 안되어 있다면 -> http://artyst.egloos.com/2652130 참고 (보노님 블로그)

 

  <가정2 요약>

   1. 푸시 가능 SSL Certificate 를 받아야되요 <- 이게 제일 중요~!! 어플 여러개 개발해봤지만, 여기 숨어있으리라곤 생각못했어요

      App IDs 로 가셔서 APNS 앱 오른쪽에  Configure 클릭 > Enable for Apple Push Notification Service 선택 > Done 버튼 클릭

      -> 이때, 패스워드 설정하실 꺼에요 나중에 서버구현시 필요하니까. 꼭 적어놓으세요

 

   2. Download 해서 SSL Certificate 를 내려받기 (푸시기능이 되는 프로비져닝이죠)

 

   3. xCode 새 프로젝트 생성 > 프로젝트속성에서 code sign 프로비져닝 선택하기

 

   4. 운영서버 구현

       1) APNS 보안통신할 때 사용할 인증서 추출해서 웹서버 특정 폴더에 밑에 복사하기  <- 아주 중요

           (복사방법은 위에 보노님블로그에 기설명됨)

       2) 톰캣 서버 구성 (프로젝트 생성 및 코딩)

 

   5. 클라이언트 구현

 

 

 

1,2,3번까지는 대부분 순조롭게 진행되실꺼구요

4 번 5번은 좀더 구체적으로 들어가볼게요~

 

 

 

4. 운영서버 구현

 

 

<사전준비물>

 

1) 자바 jdk 1.6 설치 : http://www.oracle.com/technetwork/java/javase/downloads/index.html

2) 이클립스 설치 : http://eclipse.org/downloads/

3) 톰캣 설치 : http://tomcat.apache.org/ (6버전)

4) 이클립스 톰캣 플러그인 설치(option) : http://www.eclipsetotale.com/tomcatPlugin.html

 

이클립스 톰캣 설정 방법은 검색을 통해 진행하세요

http://blog.naver.com/ssari93/130086724100 (소토로님 블로그)

http://blog.naver.com/ssari93/130086768842 (소토로님 블로그)

 

 

 

 

 

<프로젝트 생성>

 

1) APNS 라는 이름으로 톰캣 프로젝트 생성하구요, 경로는 이클립스 workspace 밑에 둡니다.

  2) 톰캣 실행시 해당 경로를 홈으로 잡혀야겠죠?

      톰캣이 설치되어 있는 폴더 주소(기본)를 아래와 같이 따라가보시면 아무것도 없을 수 있는데요

      C:\Tomcat 6.0\conf\Catalina\localhost

      여기에 아래의 내용을 담아 프로젝트명.xml 파일을 만들어 주세요 (ex apns.xml) (톰캣프로젝트 생성하면 자동으로 생성되는 경우도 있음)

      <Context path="/apns" reloadable="true" docBase="E:\eclipse\workspace\apns"     

       workDir="E:\eclipse\workspace\apns\work" />

      이게 없으면 http://localhost:8080/apns/index.jsp 이렇게 호출 했을 때 해당 프로젝트를 정확히 인식할 수 없어요

 

  3) 톰캣 프로젝트 바로 아래에 index.jsp 파일 하나 생성해주시구요 Hello world 적고 출력해보세요

      http://localhost:8080/apns/index.jsp  (포트는 톰캣 server.xml 설정에 따라 달라 질 수 있어요)

      이게 제대로 나온다면 이제 코딩들어가죠

 

  4) 첨부파일 다운로드 받아서 압축을 풀면 lib 폴더가 나오는데, 해당 폴더 아래의 내용들을

     eclipse\workspace\apns\WEB-INF\lib 폴더에 copy 해주세요

     APNS서버 구성을 위해 필요한 라이브러리들입니다. (개별로 서핑해서 찾으실려면 고생하실까봐 첨부했어요)

        javapns
      log4j
      bcprov-ext
      commons-io
      commons-lang

 

 

 

 

 

<index.jsp 코딩>

 

<%@ page language="java" contentType="text/html; charset=EUC-KR"  pageEncoding="EUC-KR"%>
 
<%@ page import="javapns.back.PushNotificationManager" %>    
<%@ page import="javapns.back.SSLConnectionHelper" %>    
<%@ page import="javapns.data.Device" %>    
<%@ page import="javapns.data.PayLoad" %>    
<%@ page import="java.lang.Object" %>    
<%@ page import="org.apache.commons.lang.StringUtils" %>   

 

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>

<%
 
System.out.println( "start~~!!!" );

 

 

String deviceToken = "4a525b59 273042ce ba95afae eb09db8f 2782ed06 cb5370b9 a57c02d1 fd6cf11d";   

//토큰 번호는 아이폰 클라이언트  구현 후 디버그 모드로 출력하면 알 수 있어요. 아래 5번 클라이언트구현 글 참고

 

PayLoad payLoad = new PayLoad();

payLoad.addAlert("hello kim, 반가워~!!");    // 아이폰에 통지 보낼 메세지 내용입니다.
payLoad.addBadge(1);
payLoad.addSound("default");                  
  
PushNotificationManager pushManager = PushNotificationManager.getInstance();


pushManager.addDevice("iPhone", deviceToken);
  
//Connect to APNs
String host = "gateway.sandbox.push.apple.com";
int port = 2195;
String certificatePath = "E:/eclipse/workspace/apns/ApnsCert.p12";     // 위에 가정2 4번에 설명한 부분이에요, 복사해놓은 경로명+파일명

String certificatePassword = "APNS인증서 패스워드";                                           // 위에 가정2 1번 부분에 설명한 패스워드에요

pushManager.initializeConnection(host, port, certificatePath, certificatePassword, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);

 
//Send Push
Device client = pushManager.getDevice("iPhone");

pushManager.sendNotification(client, payLoad);

pushManager.stopConnection();

pushManager.removeDevice("iPhone");


%>

please wait ...!


</body>
</html>

 

 

 

 

(빨간 색 부분만 변경하시면되요)

 

 

5. 클라이언트 구현

 

 

아이군님의 블로그에 설명이 너무나 잘 되어 있어서 링크 걸어요

http://theeye.pe.kr/entry/how-to-programming-push-notification-on-my-iphone-with-javapns

 

<내용 요약>

APNS 관련 함수들 몇가지면 수정해주시면되요

- (void)application:(UIApplication *)application  
    didRegisterForRemoteNotificationsWithDeviceToken
:(NSData *)deviceToken

 

- (void)application:(UIApplication *)application 
    didReceiveRemoteNotification
:(NSDictionary *)userInfo 

 

- (BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions
:(NSDictionary *)launchOptions  

 

 

 

일단, 구현은 다 되었네요. 테스트를 해봐야 하는데요

 

 

 

<테스트방법>

1. 맥북에 아이폰 연결 후 실행모드(Device) 변경 해서 실행 (폰에 설치되고 실행됩니다. 화면에는 회색 화면만 뜨겠죠)

2. http://localhost:8080/apns/index.jsp  pc 브라우저에 해당 페이지 호출

3. 몇 초 후 아이폰에 푸시메시지 들어옴 확인

   어플이 실행중이지 않을 경우 닫기/보기 버튼 중 보기버튼을 누르면 해당 어플이 뜹니다.

 

 

메세지가 잘 들어왔나요?

한번만에 되신 분은 정말... 존경~!!

 

저는 톰캣 설정하는 것부터 오랫만에 해보는 거라 많이 헤맸거든요 ^^;

처음부터 다시 꼼꼼히 살펴보시면~~~  되실거에요

 

일단, 무작정 따라하기로 통보는 정상적으로 들어왔네요~!

 

이제 앞으로 몇가지 응용을 더 해봐야겠죠?

 

특정인에게만 통보 하기~

통보 받은 걸 화면에 대화창에 보여주기~

메신저 비스무리해보이는 어플 만들어보기~

 

 

완성되는 대로 포스팅할께요~~!!

긴글 읽어주셔서 감사합니다.

'컴퓨터 > 아이폰' 카테고리의 다른 글

아이폰 다음버전 출시설..ㅋ  (0) 2011.06.24
UIWebView와 Application(App) 간의 통신  (0) 2011.06.24
DES암호화  (0) 2011.06.24
나침반 소스  (0) 2011.06.24
local notification  (0) 2011.06.14
      
Posted by k_ben

DES암호화

컴퓨터/아이폰 : 2011. 6. 24. 14:05


죄송합니다. 

input과 output의 문자열이 다른 오류(NSData에 쓰레기값이 체워지는 버그)가 발견되어

후다닥 수정하여 올립니다.






암호화 관련으로 이야기가 많은거 같더군요.

저도 암호화 부분을 항상 고민해 오다가 이번 기회에 적용을 시켜 보았습니다.

카페에 있는 DES암호화는 왠지 적용이 안되는 부분이 있었습니다. 

암호화는 물론 복호화도 중요하겠죠.



우선 암호화 / 복호화 하는 함수를 알려드리겠습니다.

/*************************************************************************************************/
- (NSString *)encryptDES:(NSString *)str
{
NSLog(@"encrypt input string : %@", str);
NSLog(@"input length : %d", [str length]);
NSData *data = [str dataUsingEncoding: NSUTF8StringEncoding];
NSLog(@"data : %@", data);
unsigned char *input = (unsigned char*)[data bytes];
NSUInteger inLength = [data length];
NSInteger outLength = ((inLength + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1));
unsigned char *output =(unsigned char *)calloc(outLength, sizeof(unsigned char));
bzero(output, outLength*sizeof(unsigned char));
size_t additionalNeeded = 0;
unsigned char *iv = (unsigned char *)calloc(kCCBlockSizeDES, sizeof(unsigned char));
bzero(iv, kCCBlockSizeDES * sizeof(unsigned char));
NSString *key = @"abcdefg123123123";
const void *vkey = (const void *) [key UTF8String];

CCCryptorStatus err = CCCrypt(kCCEncrypt,
  kCCAlgorithmDES,
  kCCOptionPKCS7Padding | kCCOptionECBMode,
  vkey,
  kCCKeySizeDES,
  iv,
  input,
  inLength,
  output,
  outLength,
  &additionalNeeded); 
NSLog(@"encrypt err: %d", err);
if(0);
else if (err == kCCParamError) NSLog(@"PARAM ERROR");
else if (err == kCCBufferTooSmall) NSLog(@"BUFFER TOO SMALL");
else if (err == kCCMemoryFailure) NSLog(@"MEMORY FAILURE");
else if (err == kCCAlignmentError) NSLog(@"ALIGNMENT");
else if (err == kCCDecodeError) NSLog(@"DECODE ERROR");
else if (err == kCCUnimplemented) NSLog(@"UNIMPLEMENTED");
free(iv);

NSString *result;
//NSData *myData = [NSData dataWithBytesNoCopy:output length:outLength freeWhenDone:YES];
NSData *myData = [NSData dataWithBytesNoCopy:output length:(NSUInteger)additionalNeeded freeWhenDone:YES];
NSLog(@"data : %@", myData);
NSLog(@"encrypted string : %s", [myData bytes]);
NSLog(@"encrypted length : %d", [myData length]);
result = [myData base64Encoding];

NSLog(@"base64encoded : %@", result);
return result;
}

- (NSString *)decryptDES:(NSString *)str
{
NSLog(@"decrypt input string : %@", str);
NSData *decodedData = [NSData dataWithBase64EncodedString:str]; 
NSLog(@"data : %@", decodedData);
NSLog(@"base64decoded : %s", [decodedData bytes]);
unsigned char *input = (unsigned char*)[decodedData bytes];
NSUInteger inLength = [decodedData length];
NSInteger outLength = ((inLength + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1));
unsigned char *output =(unsigned char *)calloc(outLength, sizeof(unsigned char));
bzero(output, outLength*sizeof(unsigned char));
size_t additionalNeeded = 0;
unsigned char *iv = (unsigned char *)calloc(kCCBlockSizeDES, sizeof(unsigned char));
bzero(iv, kCCBlockSizeDES * sizeof(unsigned char));
NSString *key = @"abcdefg123123123";
const void *vkey = (const void *) [key UTF8String];

CCCryptorStatus err = CCCrypt(kCCDecrypt,
  kCCAlgorithmDES,
  kCCOptionPKCS7Padding | kCCOptionECBMode,
  vkey,
  kCCKeySizeDES,
  iv,
  input,
  inLength,
  output,
  outLength,
  &additionalNeeded); 
NSLog(@"encrypt err: %d", err);

if(0);
else if (err == kCCParamError) NSLog(@"PARAM ERROR");
else if (err == kCCBufferTooSmall) NSLog(@"BUFFER TOO SMALL");
else if (err == kCCMemoryFailure) NSLog(@"MEMORY FAILURE");
else if (err == kCCAlignmentError) NSLog(@"ALIGNMENT");
else if (err == kCCDecodeError) NSLog(@"DECODE ERROR");
else if (err == kCCUnimplemented) NSLog(@"UNIMPLEMENTED");
free(iv);

NSString *result;
//NSData *myData = [NSData dataWithBytes:(const void *)output length:(NSUInteger)additionalNeeded];
//NSData *myData = [NSData dataWithBytesNoCopy:output length:outLength freeWhenDone:YES];
NSData *myData = [NSData dataWithBytesNoCopy:output length:(NSUInteger)additionalNeeded freeWhenDone:YES];
NSLog(@"data : %@", myData);
NSLog(@"decrypted string : %s", [myData bytes]);
NSLog(@"decrypted length : %d", [myData length]);

result = [NSString stringWithFormat:@"%.*s",[myData length], [myData bytes]];
//result = [NSString stringWithUTF8String:[myData bytes]];
NSLog(@"output length : %d", [result length]);
NSLog(@"result : %@", result);

return result;
}
/*************************************************************************************************/




사용 방법입니다.

우선 암호화를 진행할 곳에

#import <CommonCrypto/CommonCryptor.h>

이 해더파일을 import해주어야 합니다.


그리고 제가 첨부한 파일을 본인의 프로젝트에 추가시키고, 사용할 곳에서 마찬가지로 

#import "NSDataAdditions.h"

해주셔야 합니다.

이유는 밑에서 설명하겠습니다.



그리고 함수를 적어주는건 말 할 필요도 없겠죠.

함수의 input은 string으로 들어갑니다. 물론 output도 string입니다.

NSData로 나오는걸 사용하기 편하도록 고쳐놓았습니다.


[self encryptDES:암호];
[self decryptDES:암호화된 스트링];

이런식으로 사용하면 되겠죠.




위의 함수는

암호화를 한 후 base64로 인코딩을 시킵니다.

base64로 인코딩하는 이유는 암호화가 된 문자열에 가끔 뒤에 쓰레기 값이 붙어 보일 수 있습니다.

이 쓰레기값을 처리할 수 있도록 base64로 비교적 보기 편한 문자열로 인코딩을 시키는 것이죠.

이거 때문에 제가 첨부한 파일들이 필요한겁니다.




이 함수들은

- 암호화

1. 문자열 입력

2. DES 암호화

3. 암호화된 문자열을 base64로 인코딩


- 복호화

1. 암호화되고 base64로 된 문자열 입력

2. base64를 UTF8로 암호화만 되어있는 문자열로 디코딩

3. 복호화


로 진행됩니다.



비밀키는

NSString *key = @"testtesttesttesttest";

이 부분입니다.

원하시는 문자열을 넣으시면 되겠죠.




그럼 도움이 되었으면 좋겠습니다.




아...파일을 첨부하니 대문자가 모두 소문자가 되어버리네요..

유의해주세요.

'컴퓨터 > 아이폰' 카테고리의 다른 글

아이폰 다음버전 출시설..ㅋ  (0) 2011.06.24
UIWebView와 Application(App) 간의 통신  (0) 2011.06.24
push notification  (0) 2011.06.24
나침반 소스  (0) 2011.06.24
local notification  (0) 2011.06.14
      
Posted by k_ben

나침반 소스

컴퓨터/아이폰 : 2011. 6. 24. 13:19


앱개발 하다가 나침반을 넣을 일이 있어서 여기저기 검색했는데 너무 쉬워서인지
자세하세 설명이 된걸 찾을수가 없었습니다.
그래서 이번에는 제가만든 소스를 올려 보려고 합니다.

compass로 애플에서 검색하면 telsameter인가 하는것만 검색되더군요.
그걸로 값을 계산해서 알수도 있는것 같던데 복잡하고 귀찮아서 포기하고
CLHeading을 이용하는 방법을 사용했습니다.

아주 간단한건데요 CLLocationManager를 등록해주고 update되는 Heading데이터만
화면에 출력해주면 끝입니다.

일단 이것을 구현하기위해서는 
CoreLocation.framework과 CoreGraphics.framework 두가지가 꼭 필요합니다.
자신의 프로젝트에 Frameworks에다 등록해주시고
저는 나침반을 여기저기 자주 사용할것 같아서 compassview를 하나 만들어서 재활용 하기로 했습니다.
화려한 UI가 추가되면 좋겠지만 그건 각자 알아서 하시고
이번에는 간단하게 화면에다 동그라미와 막대기로 방향만 표시합니다.

이제 코드를 보겠습니다. 
LocationManager를 생성해 줍니다. 뷰의 initWithFrame함수또는 뷰컨트롤러에 적당한곳에다
넣어도 되겠습니다. 저는 나침반을 갖다붙여쓰기쉽게 뷰에다 넣어놓기로 했습니다.

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        
        curColor = [UIColor redColor];
        
        // 현재 뷰에다 locationManager를 붙여줍니다.
        self.locationManager = [[[CLLocationManager alloc] init] autorelease];
        
        // setup delegate callbacks( 콜백 즉 이벤트를 받을 대리자를 설정합니다.)
        locationManager.delegate = self;

        // start the compass( 나침반을 만들 heading데이터를 받기 시작합니다.)
        [locationManager startUpdatingHeading];
        
    }
    return self;
}

그다음은 화면이 갱신될때마다 나침반 배경과 바늘을 각도에 맞게 출력합니다.
만약 이미지로 처리한다면 아마 더블버퍼링을 해야할듯한데 저는 그냥 선으로 그렸기때문에
단순히 처리했습니다. 물론 예쁘게 꾸미는건 각자가....
그리고 나침반 바늘은 원래 길게 그려야되지만 편의상 시계바늘처럼 반만 그렸습니다.

- (void)drawRect:(CGRect)rect
{
 
    CGPoint ptCenter;
    CGPoint compassPoint;
    CGFloat diameter;
    CGFloat degreeNorth = 0.0f;
    
   // 화면 context를 받아옵니다.
   // 윈도우에서 dc같은거 같던데 파일핸들 처럼 화면 핸들이라고 보면 될것 같군요.
   // 이걸로 화면에다 이것저것 각종 삽질을 해줄수 있는...
    CGContextRef context = UIGraphicsGetCurrentContext();

    // 이건 단순한 테스트 코드입니다. (필요없는 코드입니다.)
    CGContextSetRGBFillColor (context, 1, 0, 0, 1);// 3
    CGContextFillRect (context, CGRectMake (0, 0, 200, 100 ));// 4
    CGContextSetRGBFillColor (context, 0, 0, 1, .5);// 5
    CGContextFillRect (context, CGRectMake (0, 0, 100, 200));
   
   // 화면가운데에다 나침반을 표시하기위해 center포인트를 구합니다.
    ptCenter = CGPointMake(320/2, 450/2);
    
   // 반지름(Radious)로 지름을 계산합니다. 
   // RADIOUS는 위에서 define된 값입니다.
    diameter = RADIOUS * 2;
    
   // 나침반 바깥테두리를 그립니다.
    CGContextStrokeEllipseInRect(context, CGRectMake(ptCenter.x-RADIOUS,ptCenter.y-RADIOUS, diameter, diameter));
   // 나침반 가운데 작은원을 그립니다.
    CGContextStrokeEllipseInRect(context, CGRectMake(ptCenter.x-5,ptCenter.y-5, 10,10));
    
    NSLog(@"%f, %f", ptCenter.x, ptCenter.y);
    
    // Heading데이터는 내가 바라보는 방향이므로 북쪽은 360도 에서 각도를 빼줍니다.
    degreeNorth = 360 - headingDegree;
    
     // 나침반 바늘을 그리는 함수인데 아래쪽에 코드를 추가했습니다.
    [self drawLineCenterContext:context withCenter:ptCenter toDegree:degreeNorth withRadious:RADIOUS];
}


아래함수가 나침반의 바늘을 그리는 함수입니다.
위에서도 말씀드렸지만 편의상 시계바늘처럼 짧은 바늘만 그렸습니다.

- (void)drawLineCenterContext:(CGContextRef)context withCenter:(CGPoint)center toDegree:(CGFloat)degree withRadious:(NSInteger)radious
{
    CGPoint ptDest;
    
    CGFloat chkRadian;

    // 각도를 라디안으로 변화합니다. 왜냐하면 sin,cos같은 삼각함수는 라디안으로 처리해야되기때문에
    // 라디안변환은 각도 * (PI/180)입니다.
    // DEG2RAD는 위에서 Define한 수식입니다.
    // 미리계산된값 
0.0174532925 를 사용해도 됩니다.
    CGFloat radAngle = DEG2RAD(degree); 
    
    // 단순히 바늘을 그리는 작업이므로 0, 90, 180, 270도는 계산할 필요없이 바로 좌표를 입력합니다.
    // 그외에는 삼각함수로 계산하는데 삼각함수는 각도에따라 값이 +, -를 왔다갔다 하므로 일일이
    // 신경쓰기보다는 항상 90도 이하의 각도로 만들어서 계산하면 편리합니다.
    // 1,2,3,4 분면에따라 x,y좌표 계산시에 sin, cos을 바꿔줘야합니다. 약간 머리를 굴려야되는데
    // 더쉬운 방법도 있을것 같은데 단순한 제머리로는 이게 한계라..-_-;;
    // 다른방법 있으시면 댓글로 공유좀 부탁드립니다.
    if (degree == 0.0f) {
        ptDest.x = center.x;
        ptDest.y = center.y - radious;
    }
    else if( degree == 90.0f )
    {
        ptDest.x = center.x + radious;
        ptDest.y = center.y;
    }
    else if( degree == 180.0f )
    {
        ptDest.x = center.x;
        ptDest.y = center.y + radious;
    }
    else if( degree == 270.0 )
    {
        ptDest.x = center.x - radious;
        ptDest.y = center.y;
    }
    else if( degree > 0.0f && degree < 90.0f )
    {
        
        ptDest.x = center.x + (radious * sin(radAngle));
        ptDest.y = center.y - (radious * cos(radAngle));        
    }
    else if( degree > 90.0f && degree < 180.0f )
    {
            chkRadian = (degree - 90.0f) * 0.0174532925;  // convert to radian
        
        ptDest.x = center.x + (radious * cos(chkRadian));
        ptDest.y = center.y + (radious * sin(chkRadian));        
    }
    else if( degree > 180.0f && degree < 270.0f )
    {
        chkRadian = (degree - 180.0f) * 0.0174532925;  // convert to radian
        
        ptDest.x = center.x - (radious * sin(chkRadian));
        ptDest.y = center.y + (radious * cos(chkRadian));        
    }
    else if( degree > 270.0f && degree < 360.0f )
    {
        chkRadian = (degree - 270.0f) * 0.0174532925;  // convert to radian
        
        ptDest.x = center.x - (radious * cos(chkRadian));
        ptDest.y = center.y - (radious * sin(chkRadian));        
    }
    
    NSLog(@"%f (%d) : X:%f, Y:%f", degree, radious, ptDest.x, ptDest.y);
    
   // 최종적으로 계산된 좌표를 이용해서 중심점에서 좌표까지 선을 그립니다.
    CGContextMoveToPoint(context, center.x , center.y );
    CGContextAddLineToPoint(context, ptDest.x, ptDest.y);
    CGContextStrokePath(context);
 
}


여기까지 하면 다 된것이 아니라 
이제 제일중요한 heading데이터를 받아야 합니다.
그러기 위해서는 최초에 뷰를 만들고나서 <CLLocationManagerDelegate> 프로토콜을 사용해야합니다.
LocationManager의 대리인으로 LocationManager로부터 넘어오는 각종 이벤트들을 뷰에서 처리하겠다는
의미이죠.
코드에서는 이렇게 들어가 있으면 된 것입니다.
@interface CompassView : UIView <CLLocationManagerDelegate> {

그리고 .m파일에서 실제 처리 메소드를 구현해줘야 합니다.
아래 두개 메소드인데요 heading데이터가 업데이트 될때와 에러가 발생했을때 처리할 두개의 메소드입니다.

#pragma mark -
#pragma CLLocationManager delegate Methods

// This delegate method is invoked when the location manager has heading data.
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)heading 
{
    // 데이터로는 마그네틱해딩 즉 자북 을 사용합니다.
    // 실제 북쪽 즉 진북을 쓰려면 trueHeading을 사용하면 됩니다.
    CGFloat magHeading = heading.magneticHeading;
    
    // 화면이 갱신될때마다 사용할 수 있도록 headingDegree에다 넣어줍니다.
    self.headingDegree = magHeading;
    NSLog(@"Heading : %f", magHeading);
    
    // 업데이트된 바늘을 그리기위해 지금즉시 화면을 갱신하도록 뷰를 갱신합니다.
    [self setNeedsDisplay];
}

// This delegate method is invoked when the location managed encounters an error condition.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 
{
    
    if ([error code] == kCLErrorDenied) {
        // This error indicates that the user has denied the application's request to use location services.
        NSLog(@"Stop updating Heading");
        [manager stopUpdatingHeading];
    } else if ([error code] == kCLErrorHeadingFailure) {
        // This error indicates that the heading could not be determined, most likely because of strong magnetic interference.
        NSLog(@"Heading failure");
    }
    
}

이상 간단한 나침반 만들기였습니다.
소스는 뷰소스를 파일로 첨부했습니다.

'컴퓨터 > 아이폰' 카테고리의 다른 글

아이폰 다음버전 출시설..ㅋ  (0) 2011.06.24
UIWebView와 Application(App) 간의 통신  (0) 2011.06.24
push notification  (0) 2011.06.24
DES암호화  (0) 2011.06.24
local notification  (0) 2011.06.14
      
Posted by k_ben


이 글은 iOS에서 Local Notification에 대한 전반적인 이해를 돕기위한 글이다. 그래서 유사형태인 APNS와 비교해보기도 했다. 검색해보면 Local Notification에 대한 문의는 있어도 이에 대해서 설명된 한글문서가 없는 것 같아 정리해보았다.

Local Notification에 대해
iOS 4.0 이상부터 Local Notification(지역알림, 내부통지, http://goo.gl/jFFsT)을 지원한다.  그러므로  iOS 4.0 미만 버전을 지원하는 어플의 경우 호환성을 유지할 수 있도록 개발해야할 것이다.

Local Notification은 어플이 실행중이 아니거나 Background, Foreground 상태에 관계없이 지정된 날짜와 시간에 필요한 최소한의 데이터를 전송하여 어플에게 전달해 실행하거나 다른 행동을 취할 수 있도록 구현할 수 있다. 심지어 Local Notification을 예약하고 iOS를 재부팅해도 정상적으로 동작한다.  이러한 형태가 가능한 것은 Local Notification 관리는 iOS 자체에서 하기 때문이다. 

Local Notification과 APNS(Apple Push Notification Service, http://goo.gl/fWknl)의 큰 차이점은 Notification을 위한 서버가 필요한가 아닌가의 차이에 있다. APNS는 서버가 준비가 되어 있어야 하고 Push를 위한 인증서도 발급해야한다. 처음 테스트 환경을 만들고 운용하는게 복잡한 편이다. 반면 Local Notification은 이런 절차가 전혀 필요없이 간단하게 코드상에서 처리할 수 있다. 이처럼 Local Notification을 사용하는 방법은 꽤 간단한 편이다. 하지만 APNS에 비해서 테스트하기가 좀 까다로운 면이 있다. 왜냐하면 Local Notification은 시간기반으로 하는 통지가 되는 형태이기 때문에 통지에 대한 제어권이 iOS에 있으며 개발자에게 있다고 볼 수 없기 때문이다. 반면에 APNS는 서버측에서 어떤 시간에 상관없이 개발자가 원하는데로 바로 통지를 할 수 있다. 

Local Notification와 APNS가 이처럼 차이점이 있지만 넘겨주는 데이터나 동작하는 방식은 거의 유사한 편이다.  그래서 어플내에서 동작하는 형태를 하나의 인터페이스로 만들어 운영할 수 있다. 이것이 가능한 이유는 둘다 PayLoad(http://goo.gl/mulVQ)가 유사한 형태를 가지며 통지되었을때 같은 동작을 하기 때문이다. (PayLoad는 일종의 메시지 데이터를 보유하는 패킷이나 프레임의 부분을 말한다.) PayLoad에는 Notification Type과 Custom Data를 담는다. Notification Type은 메시지 ,버튼 제목, 아이콘뱃지숫자, 사운드등으로 구성되어 있고 Custom Data에는 이외에 데이터가 필요한 경우  Dictionary형태로 구성된다. 하지만 APNS와 Location Notification간에 PayLoad데이터 관리의 차이는 있다. APNS는 Dictionary로 관리되며, Location Notification은 UILocalNotification 클래스(http://goo.gl/3TyTg)로 관리 된다. 

Local Notification은 APNS와 다르게 시간기반으로 운용된다. 이것은 iOS에서 스케쥴링을 해준다는 말과 같다. 그래서 통지가 일어나야하는 날짜와 시간을 정해줘야한다. 

Local Notification 사용법 
지금까지  Local Notification을 설명하면서 APNS와의 차이점도 알아보았다. 이러한 내용을 미리 언급하는 것은 처음 이를 접근할 때 Local Notification에 대한 전반적인 이해가 필요하기 때문이다. 여러가지로 복잡하고 잘 이해가 안되겠지만 실제로 해보면 이보다 쉬울 순 없다. 

Local Notification을 학습하기 위해서  Apple문서를 먼저 참고하는 것이 좋겠다.
 - About Local Notifications and Push Notifications : http://goo.gl/jFFsT

그럼 간단하게 Local Notification을 사용하는 방법을 알아보자. 크게 등록과 처리하는 방법을 구분해서 정리했다.

1. Local Notification 등록하기

Xcode상에서 Window Based 어플 프로젝트를 생성한뒤 AppDeleage 소스코드내에 application:didFinishLaunchingwithOptions: 메시지에 다음 코드를 넣는다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {    

    

    // Override point for customization after application launch.

    

    [self.window makeKeyAndVisible];


    //통지시간 정하기 

NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];

NSDateComponents *dateComps = [[NSDateComponents allocinit];

[dateComps setYear:2011];

[dateComps setMonth:3];

[dateComps setDay:22];

[dateComps setHour:15];

[dateComps setMinute:30];

[dateComps setSecond:0];

NSDate *date = [calendar dateFromComponents:dateComps];

[dateComps release];

UILocalNotification *localNotif = [[UILocalNotification alloc]init];

if (localNotif != nil

{

//통지시간 

localNotif.fireDate = date;

localNotif.timeZone = [NSTimeZone defaultTimeZone];

//Payload

localNotif.alertBody = [NSString stringWithFormat:@"내부통지 %@",date];

localNotif.alertAction = @"상세보기";

localNotif.soundName = UILocalNotificationDefaultSoundName;

localNotif.applicationIconBadgeNumber = 1;

//Custom Data

NSDictionary *infoDict = [NSDictionary dictionaryWithObject:@"mypage"forKey:@"page"];

localNotif.userInfo = infoDict;

//Local Notification 등록

[[UIApplication sharedApplicationscheduleLocalNotification:localNotif];

}

[localNotif release];

    return YES;

}


이게 끝이다. Local Notification을 등록하는 시점은 어디라도 상관없다. 필요할 때 등록하면 된다. UILocalNotification 객체를 생성하고 통지시간, Payload, Custom Data를 설정한뒤 등록하면 지정된 시간에 통지가 발생할 것이다. APNS럼 APNS 서버에 DeviceToken을 받는 과정이 모두 생략되기 때문에 등록절차는 매우 쉬운 것을 알 수 있다. 

이 코드에서 Local Notification 등록을 scheduleLocalNotification을 사용했다. 필요한 경우에 스케쥴링 필요없이 즉각적으로 Local Notification을 줄 필요가 있는 경우에는 다음 메시지를 사용하면 되겠다. 

[[UIApplication sharedApplicationpresentLocalNotificationNow:localNotif];


만약 fireDate를 현재시간보다 이전시간으로 등록하면 iOS는 바로 통지해버린다. 이 말이 그냥 쉽게 넘어갈 수 있는 문제인데 경험상 현재시간보다 이전시간으로 가는 경우는 없기 때문에 왠만하면 이전시간으로 등록하는 경우가 없도록 코딩을 해야 버그를 유발시키지 않을 것이다.

만약 이전에 등록된 Local Notification을 삭제하고 싶은 경우가 발생할 수 있다. 그런 경우에는 다음 메시지 중에 하나를 사용하면 되겠다.

[[UIApplication sharedApplicationcancelAllLocalNotifications];

[[UIApplication sharedApplicationcancelLocalNotification:localNotif];




2. Local Notification 처리하기 
앞서 Local Notification을 등록하는 방법을 알았다. 등록된 통지는 iOS에서 스케쥴링해준다.  어플의 실행여부, 및 iOS재부팅에 전혀 상관없이 동작하기 때문에 개발자는 이런부분에 대해 별다른 노력없이 통지 처리에 대한 로직만 만들면 된다.

내부 통지는 다음 3가지 형태로 처리가 가능하다. 이는 APNS와 유사하다.

[경우 1] 어플이 실행중이지 않은 경우 
이 경우에 iOS에 등록된 통지를 정해진 시간에 발생하면 자동으로 Alert창을 띄워준다. 거기에는 UILocalNotification에 Payload로 등록한 alertBody, alertAction이 반영되어 있으며 주어진 사운드를 들려준다. 어플의 아이콘에도 정해진 badge숫자가 표시된다. 


위의 경우 특별히 AppDelegate에서 application:didFinishLaunchingWithOptions: 메세지 내에서 통지된 UILocalNotification객체를 참고할 수 있다. Local Notification을 통해 어플이 실행되는 경우 별다른 작업이 필요하다면 이를 이용하면 유용할 것이다. 접근방법은 간단한다. 아래처럼 접근해서 사용하면 되겠다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {    

    

    // Override point for customization after application launch.

    

    [self.window makeKeyAndVisible];

UILocalNotification *notif = [launchOptionsobjectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

if (notif != nil

{

UIAlertView *alert = [[UIAlertView allocinitWithTitle:@"알림" 

message:[NSString stringWithFormat:@"didFinishLaunchingWithOptions %@",notif.alertBody

  delegate:nil 

 cancelButtonTitle:nil 

 otherButtonTitles:@"확인",nil];

[alert show];

[alert release];

}

    return YES;

}


이 경우 다음과 같은 화면을 볼 수 있을 것이다. 



또한 AppDelegate 상에 application:didReceiveLocalNotification: 메시지를 구현하면 Local Notification을 처리할 수 있다. 이 메시지는 다음에 나오는 [경우2], [경우3]에도 동일하게 동작한다. 아래처럼 구현해보자.

-(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

{

application.applicationIconBadgeNumber = 0;

UIAlertView *alert = [[UIAlertView allocinitWithTitle:@"알림" 

message:[NSString stringWithFormat:@"didReceiveLocalNotification %@",notification.alertBody

  delegate:nil 

 cancelButtonTitle:nil 

 otherButtonTitles:@"확인",nil];

[alert show];

[alert release];

}


다음은 위코드가 실행될 때 화면이다.



[경우2]어플이 실행중이나 background에 위치해 있는 경우 
[경우1]과의 유일한 차이점은 application:didFinishLaunchingWithOptions: 를 통해 UILocalNotification 객체정보를 얻을 수 없다는 것이다. 이 경우에는 이미 어플이 실행중이기 때문에 어플이 처음 실행할때 최초 한번만 호출되는 AppDeleage의 application:didReceiveLocalNotification:가 실행될 수 없기 때문이다. 이 의미는 application:didFinishLaunchingWithOptions: 와 application:didReceiveLocalNotification: 에서 얻어지는 UILocalNotification 객체정보가 같더라도 서로 다른 일을 할 수 있도록 한다는 점을 시사한다.  

application:didReceiveLocalNotification: 메시지는 여전히 호출되므로 이때 UILocalNotification 객체를 처리하면 되겠다.


[경우3]어플이 실행중이며 foreground에 위치해 있는 경우
마지막으로 어플이 화면위에 실행중인 경우이다. 이때도 [경우1], [경우2]와 차이점은 iOS에서 직접적으로 Alert창을 띄워주지 않는다는 점이다. application:didFinishLaunchingWithOptions: 는 당연히 호출되지 않으며 application:didReceiveLocalNotification:  만 호출된다. 


Local Notification 처리에 대한 경우 1, 2, 3을 표로 정리하면 다음과 같을 것이다. 
   경고창   didFinishLaunchingWithOptions를 통한 UILocalNotification참고  didReciveLocalNotification메시지를 통해 UILocalNotification 참고
 경우 1 (어플 실행X)  O
 경우 2 (어플 background)  O
 경우 3 (어플 foreground)


지금까지 설명한 내용 대해서 더 자세히 알고 싶다면 다음 문서를 참고한다.
Scheduling, Registering, and Handling Notifications : http://goo.gl/qHVPi


팁(Tip)
Local Notification을 사용하면서 이런 점은 알아둘 필요가 있다. 

1. 등록시 현재 시간보다 빠른 시간을 등록하면 바로 통지가 된다. 이 점은 어플 버그를 유발할 수 있으므로 각별히 주의하길 바란다. 개발 경험상에서 말씀드린다. (여기서 버그는 실제 버그가 아니라 의도하지 않는 동작을 유발시킨다는 말이다.)

2. 테스트를 위해서는 아이폰 자체 시간설정 기능을 적극 활용하면 되겠다. Local Notification의 통지는 iOS가 스케쥴링을 해주기 때문에 개발자가 통제할 수 없다. 그러므로 아이폰 자체 시간설정 기능을 활용해 테스트할 수 있겠다.

3. PayLoad대신 Custom Data를 사용하는 방법은 별도로 설명을 안했지만 UILocalNotification상에 userInfo속성을 활용하면 된다는 점을 설명하지 않아도 여러분은 잘 사용할 수 있을 것이라 생각한다. ^^


정리하며
Local Notification에 대해서 전반적인 내용을 다뤄보았다. 생각보다 개념자체는 간단하지만 어느 경우에 어떻게 사용하고 동작하는지에 대한 명확한 지식이 없으면 오용할 여지는 많다. 또한 잘못 사용하면 뜻하지 않는 동작을 유발할 수 있기 때문에 등록시 시간을 잘 설정해야하는 것은 꼭 염두해야 한다. 또한 클라이언트 베이스로 등록/처리를 해야하는 부분은 이에 대한 적절한 설계를 바탕으로 하지 않으면 로직이 복잡해져 관리가 어려워질 수 있다는 점도 개인적인 경험이다. 

아무튼 회사에서 이를 이용한 관련 어플을 만들면서 처음 사용해 봤는데 자세히 알지 않고 사용하면 문제가 될 것 같아 정리를 해보았다.


관련글 
About Local Notifications and Push Notifications : http://goo.gl/jFFsT
The Notification Payload : http://goo.gl/mulVQ
UILocalNotification 클래스 : http://goo.gl/3TyTg
Scheduling, Registering, and Handling Notifications : http://goo.gl/qHVPi
내가 만든 어플에 Push Notification 적용하기 : http://goo.gl/kH7BQ 
APNS 개발버전과 배포버전의 차이점. : http://blog.jidolstar.com/726 
APNS Device Token을 못받아올때 : http://blog.jidolstar.com/725 
 
글쓴이 : 지돌스타(http://blog.jidolstar.com/758)  

////////////////////////////////////////////

구글링을 해 보아도 매분, 매시간, 매일...처럼.

NSYearCalendarUnit

NSMonthCalendarUnit

NSDayCalendarUnit

NSHourCalendarUnit

NSMinuteCalendarUnit

NSSecondCalendarUnit

 

NSWeekCalendarUnit

NSWeekdayCalendarUnit

NSWeekdayOrdinalCalendarUnit

NSQuarterCalendarUnit 

'컴퓨터 > 아이폰' 카테고리의 다른 글

아이폰 다음버전 출시설..ㅋ  (0) 2011.06.24
UIWebView와 Application(App) 간의 통신  (0) 2011.06.24
push notification  (0) 2011.06.24
DES암호화  (0) 2011.06.24
나침반 소스  (0) 2011.06.24
      
Posted by k_ben