'iPhone/Development'에 해당되는 글 41건
2012/01/10 10:14
#define TCP_NODELAY 0x0001
int opt_val = 1;
setsockopt( sock, IPPROTO_TCP, TCP_NODELAY, &opt_val, sizeof(opt_val));
Trackback Address ::
http://joyholic.kr/trackback/446
2011/02/07 10:36
Trackback Address ::
http://joyholic.kr/trackback/435
2011/02/07 10:16
Original :
http://improgrammer.com/12
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 < 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:range withString:string];
if(textField == IDField) {
maxLength = 8;
} else if(textField == AgeField) {
//숫자여부 점검
//length가 0보다 클 경우만 체크
//0인 경우는 백스페이스의 경우이므로 체크하지 않아야 한다
if ([string length] > 0) {
//numberFormatter는 자주 사용할 예정이므로 아래 코드를 이용해서 생성해둬야함
//numberFormatter = [[NSNumberFormatter alloc] init];
//[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
//numberFormatter 를 이용해서 NSNumber로 변환
candidateNumber = [numberFormatter numberFromString:candidateString];
//nil이면 숫자가 아니므로 NO 리턴해서 입력취소
if(candidateNumber == nil) {
return NO;
}
//원 래 문자열과 숫자로 변환한 후의 값이 문자열 비교시 다르면
//숫자가 아닌 부분이 섞여있다는 의미임
if ([[candidateNumber stringValue] compare: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) 이제 시뮬레이터의 사진앨범에 가 보시면 아까 저장한 사진이 들어가있을겁니다.
위 글이 유용하셨다면
http://durl.kr/23tin 응원 한마디 부탁드립니다.
Trackback Address ::
http://joyholic.kr/trackback/434
2010/06/25 14:07
#if __APPLE__
#include "TargetConditionals.h"
#endif
#if TARGET_IPHONE_SIMULATOR
// jobs which should run on your simulator.
[yourObject doSomethingWithSimulator];
#else //TARGET_IPHONE_SIMULATOR
// jobs which should run on a real device.
[yourObject doSomethingWithDevice];
#endif //TARGET_IPHONE_SIMULATOR
Trackback Address ::
http://joyholic.kr/trackback/420
2010/06/14 12:35
뭘까나??..
[UITextField명 becomeFirstResponder];
Trackback Address ::
http://joyholic.kr/trackback/413
2010/06/14 11:30
#!/bin/bash
projectName="FlashCard"
xcodebuild -project $projectName.xcodeproj -configuration DIST clean build
rm -rf ~/Desktop/$projectName.zip
cd build/DIST-iphoneos/
zip -y -r ~/Desktop/$projectName.zip $projectName.app
Trackback Address ::
http://joyholic.kr/trackback/412
2010/06/07 11:10
Creating Xcode project templates
From Mac Guides
This guide explains how to create new project templates in Xcode. Project templates appear in the list of project types in the New Project dialog.
- Create a new project and setup everything as you'd like (NIB files, graphics, sounds, settings, code etc)
- Optionally, build and make sure the project works
- Use Finder and locate the project folder for your project you created in step 1
- Open another Finder window and navigate to /Library/Application Support/Apple/Developer Tools/Project Templates/. You have two options here:
- Create a new folder for your custom project templates - this will appear as a category when creating a new project in XCode
- Choose an already existing folder (eg Application) - this will place the project template in that category
- Open the new/chosen category folder and create a new folder inside. You can name this new folder whatever you like and it will appear as the project template name.
- Copy all files from the project folder in step 3 to the new template folder created in step 5. Note: If you built the project, delete the build folder from the template folder.
- Try to create a new project in Xcode. You should see your project template in one of the original categories or in the category you created, whichever you decided.
Trackback Address ::
http://joyholic.kr/trackback/409
2010/05/31 17:39
Originals :
http://www.greengar.com/2010/03/iphone-opengl-es-drawing-references/
We’ve been working with lots of OpenGL code today, so I thought I should document some of the resources we’re using. These might prove useful for others, too.
Apple’s GLSprite Sample Code
Framebuffer Object 201 – GameDev.net
Official OpenGL Documentation for glFramebufferTexture2D, which is very closely related to glFramebufferTexture2DEXT() and glFramebufferTexture2DOES() [most importantly, for iPhone OS]
Using Framebuffer Objects to Render to a Texture - iPhone Dev Center
Using a Framebuffer Object as a Texture - Mac OS X Reference Library
Forum – Render to Texture Example – Related to this Developer Forums post on how to Blit from one GL_TEXTURE_2D to another
Framebuffer Object 101
GLPaint Dissected – Forays into iPhone OpenGL ES – Introduction
FBO direction – iDevGames – iPhone Game Developers Forum – Render to texture example
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // notice the 'f'. is this guaranteed to fail?
rendering to an offscreen framebuffer – apple discussion forums
That’s all for now.
Trackback Address ::
http://joyholic.kr/trackback/402
2010/05/27 17:34
[NSString stringWithCString:message
encoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingEUC_KR)];
Trackback Address ::
http://joyholic.kr/trackback/400
2010/05/11 10:12
defaults write com.apple.Xcode PBXCustomTemplateMacroDefinitions '{"ORGANIZATIONNAME" = "YourCompanyName"; }'
Trackback Address ::
http://joyholic.kr/trackback/392
2010/04/29 17:28
Origins : http://blog.naver.com/melilyoo/140104172738
우선 이곳에서 푸시서비스를 등록해 보자.
http://ti-agile.blogspot.com/2010/01/programming-apple-push-notification.html
Device에 토큰 받아오는 부분까지 성공했다면.....
자바로 프로바이더 부분을 구현해보자.
KeyManagerFactory의 인증은 내가 가진 apple의 인증서를 넣어야 한다.
그리고 TrustManagerFactory의 인증은 공인인증된 인증서를 넣어야 한다. 그래서 java의 공인인증서를 넣은것이다.
그런다음 소켓을 연결하고 byte형식으로 토큰을 보내면 된다. ^^V
토큰은 아래와 같이 저장되었다. 알아보기 쉽게 하기 위해서 HEX값으로 표기했다. 보툥 0x를 빼고 저장하던데... 그냥 0x까지 붙여넣었다.
0x6d0x4b0x950x440x6d0xe30x650x8f0xd90xe30xab0x5c0x090xcb0x970xd20x1b0x6f0x880xfe0x810xa50xf80xf70x030xfa0xeb0x7f0xc00x130xe50xc0
====== Source ======================================================================================================
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import kr.co.confitech.girlboard.common.RowData;
public class APNSProvider{
private final String HOST = "gateway.sandbox.push.apple.com";
private final int POST = 2195;
private SSLSocket socket = null;
public void provider(String[] tokens, RowData data) throws Exception{
try{
// Apple PNS 인증
char[] password = "confitech".toCharArray();
FileInputStream fin = new FileInputStream("C:/Java/jdk1.5.0_16/jre/lib/security/pns.p12");
KeyStore ks1 = KeyStore.getInstance("PKCS12");
ks1.load(fin, password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks1, password);
// 공인 인증서 인증
char[] password1 = "changeit".toCharArray();
fin = new FileInputStream("C:/Java/jdk1.5.0_16/jre/lib/security/cacerts");
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(fin, password1);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
fin.close();
// 소켓 연결
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLSocketFactory sf = ctx.getSocketFactory();
socket = (SSLSocket)sf.createSocket(HOST, POST);
if(!socket.isConnected()){
return;
}
socket.setSoTimeout(10000);
socket.startHandshake();
String msg = "{\"aps\":{\"alert\":\""+data.get("alert")+"\",\"badge\":"+data.get("badge");
if(data.get("sound") == null){
msg = msg + "}}";
}else{
msg = msg + ",\"sound\":\""+data.get("sound")+"\"}}";
}
System.out.println(msg);
OutputStream out = socket.getOutputStream();
for(int i=0; i<tokens.length; i++){
String strToken = tokens[i];
ByteArrayOutputStream bout = new ByteArrayOutputStream();
//1. 0
bout.write((byte)0x00);
//2. 32 (token length)
bout.write(to2ByteArray(32));
//3. token
for(int j = 0; j < 32; j++){
String s = strToken.substring((j * 4) + 2, (j * 4) + 4);
int z = Integer.parseInt(s, 16);
bout.write((byte)z);
}
//4. message length
bout.write(to2ByteArray(msg.getBytes().length));
//5. message
bout.write(msg.getBytes());
// 푸시 보내기
out.write(bout.toByteArray());
out.flush();
}
out.close();
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
/**
*
* @param i
* @return
*/
public static byte[] to2ByteArray(int i){
byte[] b = new byte[2];
b[0] = (byte)((i >>> 8) & 0xFF);
b[1] = (byte)((i >>> 0) & 0xFF);
return b;
}
}
====== end ======================================================================================================
Trackback Address ::
http://joyholic.kr/trackback/390
2010/04/29 17:27
One of the key limitations of the iPhone is its constraint on running applications in the background. Because of this, applications cannot keep running in the background when the user switches to another application. So, applications that require a constant state of connectivity (such as social networking applications) will not be able to receive timely updates.
To remedy this limitation, Apple released the Apple Push Notification Service (APNs). The APNs is a service that allows your device to be constantly connected to Apple's push notification server. When you want to send a push notification to an application installed on the users' devices, you (the provider) can contact the APNs so that it can deliver a push message to the particular application installed on the intended device.
In this article, you will learn how to perform the various steps needed to create an iPhone application that uses the APNs.
Generating a Certificate Request
The first step to using the APNs is to generate a certificate request file so that you can use it to request for a development SSL certificate later on.
1. Launch the Keychain Access application in your Mac OS X.
2. Select Keychain Access'Certificate Assistant'Request a Certificate From a Certificate Authority (see Figure 1):
Figure 1. Generating a certificate request
3. Enter the information required and check the Saved to disk option. Click Continue (see Figure 2).
Figure 2. Saving the certificate request to disk
4. Save the certificate request using the suggested name and click Save (see Figure 3): Click Done in the next screen.
Figure 3. Naming the certificate request
Creating an App ID
Each iPhone applications that uses the APNs must have a unique application ID that uniquely identifies itself. In this step, you will learn how to create an App ID for push notification.
Figure 4. Launching the iPhone Developer Program Portal
2. You should see the welcome page (see Figure 5).
Figure 5. The welcome screen of the iPhone Developer Program Portal
3. Click on the App IDs tab on the left and then click on the New App ID button (see Figure 6).
Figure 6. Clicking on the App ID tab
4. Enter "PushAppID" for the Description and select Generate New for the Bundle Seed ID. For the Bundle Identifier, enternet.learn2develop.MyPushApp. Click Submit (see Figure 7).
Figure 7. Creating a new App ID
5. You should now see the App ID that you have created (together with those you have previously created) (see Figure 8).
Figure 8. Viewing the newly created App ID
Configuring an App ID for Push Notifications
Once an App ID is created, you need to configure it for push notifications.
1. To configure an App ID for push notification, you need to click the Configure link displayed to the right of the App ID. You will now see the option (see Figure 9).
Figure 9. Configuring an App ID for push notification service
Check the Enable for Apple Push Notification service option and click the Configure button displayed to the right of the Development Push SSL Certificate.
2. You will now see the Apple Push Notification service SSL Certificate Assistant screen. Click Continue (see Figure 10).
Figure 10. The Apple Push Notification service SSL Certificate Assistant screen
3. Click the Choose File button to locate the Certificate Request file that you have saved earlier. Click Generate (see Figure 11).
Figure 11. Generating the SSL certificate
4. Your SSL Certificate will now be generated. Click Continue (see Figure 12).
Figure 12. The APNs SSL certificate that is generated
5. Click the Download Now button to download the SSL Certificate. Click Done (see Figure 13).
Figure 13. Downloading the certificate generated
6. The SSL Certificate that you download is named aps.developer.identity.cer. Double-click on it to install it in the Keychain Access application (see Figure 14). The SSL certificate will be used by your provider application so that it can contact the APNs to send push notifications to your applications.
Figure 14. Installing the generated certificate into the Keychain Access application
Creating a Provisioning Profile
The next step is to create a provisioning profile so that your application can be installed onto a real device.
1. Back in the iPhone Development Program Portal, click on the Provisioning tab and click on the New Profile button (see Figure 15).
2. Type in MyDevicesProfile as the profile name. Select PushAppID as the App ID. Finally, check all the devices that you want to provision (you can register these devices with the iPhone Developer Program Portal through the Devices tab). Click Submit (see Figure 16).
Figure 16. Creating a new provisioning profile
3. The provisioning profile will now be pending approval. After a while, you will see it appear. Click on the Download button to download the provisioning profile (see Figure 17).
Figure 17. Pending the approval of the provisioning profile
4. The downloaded provisioning profile is named MyDevicesProfile.mobileprovision.
Provisioning a Device
With the provision profile created, you will now install it onto a real device.
1. Connect your iPhone or iPod Touch to your Mac.
2. Drag and drop the downloaded MyDevicesProfile.mobileprovision file onto the Xcode icon on the Dock.
3. Launch the Organizer application from within Xcode and select the device currently connected to your Mac. You should see the MyDevicesProfile installed on the device (see Figure 18).
Figure 18. Viewing the installed provisioning profile
Creating the iPhone Application
1. In Xcode, create a new View-Based Application project and name it as ApplePushNotification.
2. Drag and drop a WAV file (shown as beep.wav in this example) onto the Resources folder in Xcode (see Figure 19).
Figure 19. Adding a WAV file to the project
3. Expand on the Targets item in Xcode and select the ApplePushNotification item. Press Command-I. In the Info window, click the Properties tab (see Figure 20).
Figure 20. Entering the App ID for the application
In the Identifier textbox, type <net.learn2develop.MyPushApp.
4. Click on the Build tab and type "Code Signing" in the search box. In the Any iPhone OS Device item, select the profile as shown in Figure 21:
Figure 21. Selecting the profile for code signing
5. In the ApplePushNotificationAppDelegate.m file, type the following code in bold:
#import "ApplePushNotificationAppDelegate.h"
#import "ApplePushNotificationViewController.h"
@implementation ApplePushNotificationAppDelegate
@synthesize window;
@synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:viewController.view];
[window makeKeyAndVisible];
NSLog(@"Registering for push notifications...");
[[UIApplication sharedApplication]
registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeAlert |
UIRemoteNotificationTypeBadge |
UIRemoteNotificationTypeSound)];
}
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSString *str = [NSString
stringWithFormat:@"Device Token=%@",deviceToken];
NSLog(str);
}
- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
NSString *str = [NSString stringWithFormat: @"Error: %@", err];
NSLog(str);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
for (id key in userInfo) {
NSLog(@"key: %@, value: %@", key, [userInfo objectForKey:key]);
}
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
@end
6. Press Command-R to test the application on a real device. Press Shift-Command-R in Xcode to display the Debugger Console window. Observe carefully the device token that is printed (see Figure 22). In the figure below, the token is:38c866dd bb323b39 ffa73487 5e157ee5 a85e0b7c e90d56e9 fe145bcc 6c2c594b. Record down this device token (you might want to cut and paste it into a text file).
Figure 22. Viewing the device token for push notification
7. If you go to the Settings application on your iPhone/iPod Touch, you will notice that you now have the Notifications item (see Figure 23).
Figure 23. Viewing the Notifications item in the Settings application
Creating the Push Notification Provider
A Push Notification provider is an application written by the application's developer to send push notifications to the iPhone application through the APNs.
Here are the basic steps to send push notifications to your applications via the Apple Push Notification Service (APNs):
1. Communicate with the APNs using the SSL certificate you have created earlier.
2. Construct the payload for the message you want to send.
3. Send the push notification containing the payload to the APNs.
The APNs is a stream TCP socket that your provider can communicate using a SSL secured communication channel. You send the push notification (containing the payload) as a binary stream. Once connected to the APNs, you should maintain the connection and send as many push notifications as you want within the duration of the connection.
Tip: Refrain from opening and closing the connections to the APNs for each push notification that you want to send. Rapid opening and closing of connections to the APNs will be deemed as a Denial-of-Service (DOS) attack and may prevent your provider from sending push notifications to your applications.
The format of a push notification message looks like Figure 24 (figure from Apple's documentation):
Figure 24. Format of a push notification message
For more details, please refer to Apple Push Notification Service Programming Guide.
The payload is a JSON formatted string (maximum 256 bytes) carrying the information you want to send to your application. An example of a payload looks like this:
{
"aps": {
"alert" : "You got a new message!" ,
"badge" : 5,
"sound" : "beep.wav"},
"acme1" : "bar",
"acme2" : 42
}
To save yourself the trouble in developing a push notification provider from scratch, you can use the PushMeBabyapplication (for Mac OS X) written by Stefan Hafeneger (Get it here).
1. Open the PushMeBaby application in Xcode.
2. Right-click on the Resources folder in Xcode and select Add Existing Files…. Select theaps.developer.identity.cer file that you have downloaded earlier (see Figure 25).
Figure 25. Adding the SSL certificate to the application
3. In the ApplicationDelegate.m file, modify the code as shown in bold below:
- (id)init {
self = [super init];
if(self != nil) {
self.deviceToken = @"38c866dd bb323b39 ffa73487 5e157ee5 a85e0b7c e90d56e9 fe145bcc 6c2c594b";
self.payload = @"{\"aps\":{\"alert\":\"You got a new message!\",\"badge\":5,\"sound\":\"beep.wav\"},\"acme1\":\"bar\",\"acme2\":42}";
self.certificate = [[NSBundle mainBundle]
pathForResource:@"aps_developer_identity" ofType:@"cer"];
}
return self;
}
4. Press Command-R to test the application. You will be asked to grant access to the certificate. Click Always Allow (see Figure 26):
Figure 26. Granting access to the SSL certificate
On the iPhone/iPod Touch, ensure that the ApplePushNotification application is not running. To send a message to the device, click the Push button. The server essentially sends the following message to the Apple Push Notification server:
{
"aps": {
"alert" : "You got a new message!" ,
"badge" : 5,
"sound" : "beep.wav"},
"acme1" : "bar",
"acme2" : 42
}
5. If the message is pushed correctly, you should see the notification as shown in Figure 27.
Figure 27. Receiving a Push Notification message
6. If you now debug the ApplePushNotification application by pressing Command-R and send a push message from the PushMeBaby application, the Debugger Console window will display the following outputs:
2009-11-24 21:11:49.182 ApplePushNotification[1461:207] key: acme1, value: bar
2009-11-24 21:11:49.187 ApplePushNotification[1461:207] key: aps, value: {
alert = "You got a new message!";
badge = 5;
sound = "beep.wav";
}
2009-11-24 21:11:49.191 ApplePushNotification[1461:207] key: acme2, value: 42
From http://mobiforge.com/developing/story/programming-apple-push-notification-services
Trackback Address ::
http://joyholic.kr/trackback/389
2010/04/07 15:48
Original : http://blog.boxedice.com/2009/07/10/how-to-build-an-apple-push-notification-provider-server-tutorial/
One of the widely anticipated features of the new iPhone OS 3.0 is push notifications which allow messages to be sent directly to an individual device relevant to the application that has been installed. Apple have demoed this as useful for news alerts, or IM notifications however it fits in perfectly with the nature of our server monitoring service, Server Density.

As part of the product, we have an iPhone application that includes push notifications as an alerting option so you can be notified via push direct to your iPhone when one of your server alerts have been triggered. This is useful since our app can then be launched to instantly see the details of the server that has caused the alert.
Apple provides detailed code documentation for the iPhone OS code that is needed to implement and handle the alerts on the device but only provides a higher level guide for the provider server side.
As a provider, you need to communicate with the Apple Push Notification Service (APNS) to send the messages that are then pushed to the phone. This is necessary so that the device only needs to maintain 1 connection to the APNS, helping to reduce battery usage.
This tutorial will go into code-level detail about how we built our push notification provider server to allow us to interact with the APNS and use the push notifications with our server monitoring iPhone application. Since we develop in PHP, our examples will be in PHP 5.
Basic Structure
- You connect to the APNS using your unique SSL certificate
- Cycle through the messages you want to send (or just send 1 if you only have 1)
- Construct the payload for each message
- Disconnect from APNS
The flow of remote-notification data is one-way. The provider composes a notification package that includes the device token for a client application and the payload. The provider sends the notification to APNs which in turn pushes the notification to the device.
- Apple documentation

Restrictions
- The payload is limited to 256 bytes in total – this includes both the actual body message and all of the optional and additional attributes you might wish to send. Push notifications are not designed for large data transfer, only for small alerts. For example we only send a short alert message detailing the server monitoring alert triggered.
- APNS does not provide any status feedback as to whether your message was successfully delivered. One reason for this is that messages are queued to be sent to the device if it is unreachable, however only the last sent message will be queued – overwriting any previously sent but undelivered messages.
- Push notifications should not be used for critical alerts because the message will only be delivered if the device has wifi or cellular connectivity, which is why we recommend combining push with another alerting method such as e-mail or SMS for our server monitoring alerts.
- The SSL certificates used to communicate with APNS, discussed below, are generated on an application level. The implementation discussed in this tutorial only concerns a single iPhone application so if you have several, you will need to adapt the code to use the appropriate certificate(s) where necessary.
Device Token
Each push message must be “addressed” to a specific device. This is achieved by using a unique deviceToken generated by APNS within your iPhone application. Once this token has been retrieved, you need to store it on your server, not within your iPhone application itself. It looks something like this:
c9d4c07c fbbc26d6 ef87a44d 53e16983 1096a5d5 fd825475 56659ddd f715defc
For the Server Density iPhone application, we call the necessary generation methods on app launch and pass it back to our servers via an HTTP API call. This stores the deviceToken in a database on our servers for that user so we can then communicate with the device linked to that user.
Feedback Service
Apple provide a feedback service which you are supposed to occasionally poll. This will provide a list of deviceTokens that were previously but are no longer valid, such as if the user has uninstalled your iPhone application. You can then remove the deviceToken from your database so you do not communicate with an invalid device.
Using the feedback service is not covered by this tutorial.
Certificates
The first thing you need is your Push certificates. These identify you when communicating with APNS over SSL.
Generating the Apple Push Notification SSL certificate on Mac:
- Log in to the iPhone Developer Connection Portal and click App IDs
- Ensure you have created an App ID without a wildcard. Wildcard IDs cannot use the push notification service. For example, our iPhone application ID looks something like
AB123346CD.com.serverdensity.iphone
- Click Configure next to your App ID and then click the button to generate a Push Notification certificate. A wizard will appear guiding you through the steps to generate a signing authority and then upload it to the portal, then download the newly generated certificate. This step is also covered in the Apple documentation.
- Import your
aps_developer_identity.cer into your Keychain by double clicking the .cer file.
- Launch Keychain Assistant from your local Mac and from the login keychain, filter by the Certificates category. You will see an expandable option called “Apple Development Push Services”
- Expand this option then right click on “Apple Development Push Services” > Export “Apple Development Push Services ID123″. Save this as apns-dev-cert.p12 file somewhere you can access it.
- Do the same again for the “Private Key” that was revealed when you expanded “Apple Development Push Services” ensuring you save it as apns-dev-key.p12 file.
- These files now need to be converted to the PEM format by executing this command from the terminal:
openssl pkcs12 -clcerts -nokeys -out apns-dev-cert.pem -in apns-dev-cert.p12
openssl pkcs12 -nocerts -out apns-dev-key.pem -in apns-dev-key.p12
- If you wish to remove the passphrase, either do not set one when exporting/converting or execute:
openssl rsa -in apns-dev-key.pem -out apns-dev-key-noenc.pem
- Finally, you need to combine the key and cert files into a apns-dev.pem file we will use when connecting to APNS:
cat apns-dev-cert.pem apns-dev-key-noenc.pem > apns-dev.pem
It is a good idea to keep the files and give them descriptive names should you need to use them at a later date. The same process above applies when generating the production certificate.
Payload Contents
The payload is formatted in JSON, compliant with the RFC 4627 standard. It consists of several parts:
- Alert – the text string to display on the device
- Badge – the integer number to display as a badge by the application icon on the device home screen
- Sound – the text string of the name of the sound to accompany the display of the message on the device
- This tutorial will only deal with the basics by sending a simple alert text string but this can also be another dictionary containing various options to display custom buttons and the like.
Creating the payload
Using PHP it is very easy to create the payload based on an array and convert it to JSON:
$payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');
$payload = json_encode($payload);
Echoing the contents of $payload would show you the JSON string that can be sent to APNS:
{
"aps" : { "alert" : "This is the alert text", "badge" : 1, "sound" : "default" }
}
This will cause a message to be displayed on the device, trigger the default alert sound and place a “1″ in the badge by the application icon. The default buttons “Close” and “View” would also appear on the alert that pops up.
For the Server Density server monitoring iPhone application, it is important for the user to be able to tap “View” and go directly to the server that generated the alert. To do this, we add an extra dictionary in of our own custom values:
$payload['aps'] = array('alert' => 'This is the alert text', 'badge' => 1, 'sound' => 'default');
$payload['server'] = array('serverId' => $serverId, 'name' => $name);
$output = json_encode($payload);
The custom dictionary server is passed to the application on the device when the user taps “View” so we can load the right server. The JSON looks like this:
{
"aps" : { "alert" : "This is the alert text", "badge" : 1, "sound" : "default" },
"server" : { "serverId" : 1, "name" : "Server name")
}
The size limit of 256 bytes applies to this entire payload, including any custom dictionaries.
The raw interface
Once an alert is generated within Server Density, the payload is built and then inserted into a queue. This is processed separately so that we can send multiple payloads in one go if necessary.
Apple recommends this method because if you are constantly connecting and disconnecting to send each payload, APNS may block your IP.
As described by Apple:
The raw interface employs a raw socket, has binary content, is streaming in nature, and has zero acknowledgment responses.

Opening the connection
The PHP 5 code to open the connection looks like this:
$apnsHost = 'gateway.sandbox.push.apple.com';
$apnsPort = 2195;
$apnsCert = 'apns-dev.pem';
$streamContext = stream_context_create();
stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);
$apns = stream_socket_client('ssl://' . $apnsHost . ':' . $apnsPort, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
If an error has occurred you can pick up the error message from $errorString. This will also contain the details if your SSL certificate is not correct.
The certificate file is read in relative to the current working directory of the executing PHP script, so specify the full absolute path to your certificate if necessary.
Note that when testing you must use the sandbox with the development certificates. The production hostname is gateway.push.apple.com and must use the separate and different production certificate.
Sending the payload
At this point, the code we use loops through all the queued payloads and sends them. Constructing the binary content to send to APNS is simple:
$apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
fwrite($apns, $apnsMessage);
Note that the $deviceToken is included from our database and stripped of the spaces it is provided with by default. We also include a check to send an error to us in the event that the $payload is over 256 bytes.
$apnsMessage contains the correctly binary formatted payload and the fwrite call writes the payload to the currently active streaming connection we opened previously, contained in $apns.
Once completed, you can close the connection:
socket_close($apns);
fclose($apns);
php-apns
There is a free, open source server library that does all the above functionality called php-apns. We chose to implement it ourselves because it has a further dependancy on memcached, we do not want to rely on 3rd party code for large and critical aspects of our code-base and I am apprehensive about the suitability of PHP for running a continuous server process. We do all the above queue processing using our own custom cron system which runs every few seconds – that way PHP scripts do not need to be run as processes, something I’m not sure they were designed to do!
All done
That’s it! If you have any problems, post in the comments below and we’ll do our best to help out. Also, Stack Overflow is your friend.
Trackback Address ::
http://joyholic.kr/trackback/387
2010/03/23 09:56
UIButton *btn = [[UIButton alloc] init];
UIImage *img = [UIImage imageNamed:@"image.png"];
[btn setImage:img forState:UIControlStateNormal]
[img release];
Trackback Address ::
http://joyholic.kr/trackback/386
2010/03/19 15:20
- (void)loadView {
[super loadView];
self.view.autoresizesSubviews = YES;
self.view.autoresizingMask = {UIViewAutoresizingFlexibleWidth | UIViewAutosizingFleszbleHeight};
}
Trackback Address ::
http://joyholic.kr/trackback/385
2009/10/29 09:54
Original : http://www.therareair.com/2009/01/01/tutorial-how-to-compile-openssl-for-the-iphone/
This is a quick tutorial to show you how to minimally compile a version of the openssl and crypto libraries for the iPhone.
Download and Configure OpenSSL
First thing to do is grab the openssl source. You can get that here. I’ll be using openssl-0.9.8i for this demo. Unzip this file (mines on the desktop). Open up a terminal and go to the unzipped folder and run the default configuration. The argument passed is where your ‘make install’ will place the compiled libraries. You should replace this with your path.
cd Desktop/openssl-0.9.8i
./config --openssldir=/Users/airpard/Desktop/openssl_arm/
Edit the Makefile
Next thing to do is open up the make file. This is named “Makefile” in the current directory you should already be in with the terminal. Here are the list of changes to make:
Find CC= cc and change it to:
CC= /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0
Find -arch i386 in CFLAG and change it to:
-arch armv6
Find CFLAG and add to the BEGINNING!!:
-isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk
Find SHARED_LDFLAGS=-arch i386 -dynamiclib and change it to:
SHARED_LDFLAGS=-arch armv6 -dynamiclib
Fix Build Error
If you build it at this point you may have noticed a build error. To fix this open up ui_openssl.c. This is located in openssl-0.9.8i/crypto/ui/ folder. If you have a text editor with line numbers, head down to line 403. Otherwise do a text search to make this change:
static volatile sig_atomic_t intr_signal;
to
static volatile int intr_signal;
Save your changes and you should now be able to build with no errors.
Build Libraries
make
make install
That’s it. You’ll notice that everything was moved to the path provided in step 1 when configuring openssl. Remember to add the include folder to your Xcode project. Also, remember these libraries are only built for the iPhone and will not work in the simulator. You can change all the armv6 references to i386 and build it again if you choose to. Happy Coding!
Examples
Some people had some questions about how to use the libraries in an Xcode project. Here is a simple xcode project including just the linking of the libraries and adding of the header files: openssl_tutorial
For the lazy people. Compiled libraries: compiled_libraries
Posted by: Eric
Categories:
Responses
Trackback Address ::
http://joyholic.kr/trackback/382
2009/07/10 01:38
Summary
If you need to find your iPhone serial number, International Mobile Equipment Identity (IMEI) number, identifier, or ICCID number this article shows you several different ways you can locate it.
Click one of the items below to see how to view this info:
Products Affected
iPhone, iTunes, iPhone 3G
Note: Some carriers may not store the phone number on the SIM card so the data may not be available in iTunes. If that is the case, use one of the other methods to find the phone number. See HT2232 for more information.
- Connect your iPhone to your computer.
- When your iPhone appears in iTunes 7.6 or later, select it.
- Click the Summary tab, and your iPhone's serial number and phone number will display on screen as shown below:
- If you click the words "Phone Number" in this tab iTunes will also display the IMEI of your iPhone as shown below. If you click "IMEI," iTunes will display the ICCID. If you click "Serial Number" iTunes will display the identifier.


Note: You can choose Edit > Copy to put the serial number on the Clipboard. You can then paste the serial number into an email or web page (for service or registration for example).
Note: Some carriers may not store the phone number on the SIM card so the data may not be available in iTunes. If that's the case, use one of the other methods to find the phone number. See HT2232 for more information.
Open iTunes and mouse over a device backup:
- If you are using iTunes 8.1 or later, open Preferences in iTunes (In Mac OS X, choose iTunes > Preferences. In Windows, choose Edit > Preferences).
- Click the Devices tab.
- Position the mouse over a backup to display the phone number, serial number, and IMEI of the backed up iPhone.

- If you are using iTunes 7.6.2 or later, you can also hold down the Control key and choose Help > About iTunes (Windows) or iTunes > About iTunes (Mac).
- Release the Control key.
- As the iTunes and QuickTime version information scrolls, you will see the last connected iPhone's serial number and IMEI.

About Screen Tips:
- Hold down the Option key (Shift key in Windows) to reverse the scrolling.
- Press the Space bar to pause the scrolling.
- You can copy this information onto the Clipboard and and paste it into a document.
In Mac OS X, choose Edit > Copy (or Command-C).
In Windows, press Control-C

Your original iPhone serial number and IMEI are engraved on the back metal case as shown in the photo below:
You can find your iPhone serial number,IMEI, and ICCID in the About screen on your iPhone. From the Home screen, tap Settings > General > About and scroll down.

When iPhone is in recovery mode, iTunes will display n/a for the Serial Number and IMEI, but if you have the latest version of iTunes installed, you can use Apple System Profiler on your Mac to view the Serial Number and IMEI:

If you still have the original packaging that your iPhone came in, you can find your iPhone serial number and IMEI printed on the barcode label that's affixed to the packaging.
Trackback Address ::
http://joyholic.kr/trackback/380
2009/07/10 01:35
There is no oficial way to get it, but....
in the apples private framework "CoreTelephony.framework" (Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.0.sdk/System/Library/PrivateFrameworks/CoreTelephony.framework)
There is a method __CTGetIMEI
If you know, how to work with private frameworks, it can help you. ;)
Trackback Address ::
http://joyholic.kr/trackback/379
2009/06/08 14:55
Originals :
http://iphonedevelopertips.com/cocoa/launching-other-apps-within-an-iphone-application.html
In an earlier post I talked about how to launch the browser from within an iPhone application using the UIApplciation:openURL: method.
It is also possible to use this same technique to launch other applications on the iPhone that are very useful.
Examples of some of the key applications that you can launch via URL are:
- Launch the Browser (see earlier post )
- Launch Google Maps
- Launch Apple Mail
- Dial a Phone Number
- Launch the SMS Application
- Launch the Browser
- Launch the AppStore
Launch Google Maps
The URL string for launching Google Maps with a particular keyword follows this structure:
http://maps.google.com/maps?q=${QUERY_STRING}
The only trick to this is to ensure that the value for the ${QUERY_STRING} is properly URL encoded. Here is a quick example of how you would launch Google Maps for a specific address:
1
2
3
4
5
6
7
8
9
10
11
|
// Create your query ...
NSString* searchQuery = @"1 Infinite Loop, Cupertino, CA 95014";
// Be careful to always URL encode things like spaces and other symbols that aren't URL friendly
searchQuery = [addressText stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
// Now create the URL string ...
NSString* urlString = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@", searchQuery];
// An the final magic ... openURL!
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]]; |
Launch Apple Mail
Also very useful, is the ability to enable a user to quickly send an email by launching the email client in compose mode and the address already filled out. The format of this URI should be familiar to anyone that has done any work with HTML and looks like this:
mailto://${EMAIL_ADDRESS}
For example, here we are opening the email application and filling the “to:” address with info@iphonedevelopertips.com :
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://info@iphonedevelopertips.com"]];
Dial a Phone Number (iPhone Only)
You can use openURL: to dial a phone number. One advantage this has over other URLs that launch applications, is that the dialer will return control back to the application when the user hits the “End Call” button.
Anyone familiar with J2ME or WML will find this URL scheme familiar:
tel://${PHONE_NUMBER}
Here is an example of how we would dial the number (800) 867-5309:
1
|
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://8004664411"]]; |
NOTE When providing an international number you will need to include the country code.
Launch the SMS Application
Also not supported by the iPod Touch, is the ability to quickly setup the SMS client so that your users can quickly send a text message. It is also possible to provide the body of the text message.
The format looks like this:
sms:${PHONENUMBER_OR_SHORTCODE}
NOTE: Unlike other URLs, an SMS url doesn’t use the “//” syntax. If you add these it will assume it is part of the phone number which is not.
1
|
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms:55555"]]; |
NOTE: According to the official SMS specification, you should be able to send a body as well as the phone number by including “?body=” parameter on the end of the URL … unfortunately Apple doesn’t seem to support this standard.
Launching the AppStore
Finally, it is worth noting that you can launch the AppStore and have the "buy" page of a specific application appear. To do this, there is no special URL scheme. All you need to do is open up iTunes to the application you want to launch; right-click on the application icon at the top left of the page; and select Copy iTunes Store URL .
The URL will look something like this:
http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=291586600&mt=8
Launching the AppStore URL is exactly the same as you would launch the browser. Using the link above, here is an example of how we would launch the AppStore:
1
2
|
NSURL *appStoreUrl = [NSURL URLWithString:@"http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=291586600&mt=8"];
[[UIApplication sharedApplication] openURL:appStoreUrl]; |
Comments
23 Responses to “Launching Other Apps within an iPhone Application”
Trackback Address ::
http://joyholic.kr/trackback/377
2009/05/13 18:20
Original :
http://developer.apple.com/iphone/library/technotes/tn2009/tn2242.html
Technical Note TN2242
Resolving "0xE800003A", applications not launching and "missing entitlement" |
|
If your application fails to launch on the device with an error of "0xE800003A", it generally means your application is signed in a way that prevents it from launching on the device on which it's running.
There are a number of reasons why this might happen. The most common reasons are an incorrect (or no) Code Signing Identity was selected in Xcode's Build Info pane or a mismatch between your App ID (in your provisioning profile) and your Bundle Identifier (in your Info.plist).
Resolve the former issue by ensuring you've selected the correct Code Signing Identity (under the grey provisioning profile name); resolve the latter issue by ensuring your App ID and Bundle ID match; they need to be identical to run your application on the device. This document provides background and details.
Another common cause is you're doing an Ad Hoc distribution and haven't added and configured the Entitlements.plist, as described in the "Building your Application with Xcode for Distribution" section of the iPhone Developer Program Portal User Guide in the iPhone Portal.
Other causes include not adding the device UDID to your provisioning profile or having multiple iPhone Developer (or Distribution) certificates. Read this document for more on this and other possible causes and resolutions. |


|
Mismatch between App ID and Bundle Identifier
If your App ID (in your provisioning profile) and your Bundle Identifier (in your Info.plist) do not match, your application won't launch on the device. Check your Console log for an "entitlement 'application-identifier' has value not permitted by provisioning profile" error to confirm this mismatch (see Listing 1).
Listing 1: A Console Log error pointing to a App ID/Bundle ID mismatch. Mon Sep 22 19:38:20 unknown securityd[391] <Error>: mobile_installat[399] SecItemCopyMatching: missing entitlement
Mon Sep 22 19:38:20 unknown mobile_installation_proxy[399] <Error>: entitlement 'application-identifier' has value not permitted by a provisioning profile
Mon Sep 22 19:38:20 unknown mobile_installation_proxy[399] <Error>: verify_executable: Could not validate signature: e8008016
[...]
Mon Sep 22 19:38:20 unknown mobile_installation_proxy[399] <Error>: install_application: Could not preflight application install
Mon Sep 22 19:38:20 unknown mobile_installation_proxy[399] <Error>: handle_install: Installation failed
To resolve this, make sure your App ID and your Bundle Identifier match. For example, if your App ID is A1B2C3D4E5.com.yourcompany.productname then your Bundle Identifier needs to be com.yourcompany.productname.
IMPORTANT: The 10-character prefix in the App ID is not included in the Bundle Identifier when entering it into Xcode.
If you created an App ID with a wildcard ("*") at the end of the ID (e.g. A1B2C3D4E5.com.yourcompany.*), you have more flexibility in your choice of Bundle Identifier, as you can use almost anything in place of the wildcard. For example, if you had two applications, you'd be able to use the same App ID (and therefore the same provisioning profile), simply by changing the Bundle Identifier in your project.
-
App ID: A1B2C3D4E5.com.yourcompany.*
-
Bundle ID for Application 1: com.yourcompany.product1
-
Bundle ID for Application 2: com.yourcompany.product2
You can even enter just a wildcard as your App ID (e.g. A1B2C3D4E5.*). This gives you ultimate flexibility as you'd be able to use any Bundle Identifier at all. This is the easiest setup because it requires no changes to your default Bundle Identifier in your project.
IMPORTANT: The App ID seed prefix (in these examples, "A1B2C3D4E5") is unique to you. Any applications you create which share the same App ID will have access to the same Keychain "slice" associated with that App ID. Consider the security implications of this if you develop applications that shouldn't share Keychain information. Generally, use different App IDs for unrelated applications.
A brief digression
The default Bundle Identifier in new projects is com.yourcompany.${PRODUCT_NAME:identifier}. "${PRODUCT_NAME:identifier}" is a variable and will be replaced by the name of your application. This is a source of confusion as you might change your project or application name over the course of development, which changes the effective Bundle Identifier.
If you keep the default Bundle Identifier, and you haven't used the wildcard in your App ID, changing your product name will cause the 0xE800003A error. If you think there's a chance you'll change your project or application name in the future, do one of two things:
-
Create and use a wildcard ("*") in your App ID (e.g. A1B2C3D4E5.com.yourcompany.*); or,
-
Replace the default Bundle Identifier with an explicit one (e.g. com.yourcompany.yourproductname)
Back to Top 
Important caveats for selecting and using a Bundle Identifier
Selecting and using a Bundle Identifier (and by extension, an App ID) has these important caveats:
-
While you can change your Bundle Identifer at will prior to placing your application for sale in the App Store, once it's available for sale, you cannot change your Bundle Identifier. Choose one carefully. Fortunately, the Bundle Identifier is not publicly displayed, so it does not have any marketing requirements, nor a need to be clever. It only needs to be unique within the App Store. We recommend using reverse domain notation (com.yourcompany) as the basis of your Bundle ID, especially if you own your domain name. An alternative is reverse email address notation (e.g. com.domainname.username)
-
The Bundle Identifier (and App ID) is an example of a "Uniform Type Identifier" (UTI), so you can only use valid UTI characters for your Bundle Identifier. In particular, you can't use spaces or underscores. From "The UTI Character Set:
"You may use the Roman alphabet in upper and lower case (A–Z, a–z), the digits 0 through 9, the dot (“.”), and the hyphen (“-”). This restriction is based on DNS name restrictions, set forth in RFC 1035.... Uniform type identifiers may also contain any of the Unicode characters greater than U+007F.... Any illegal character appearing in a UTI string—for example, underscore ("_"), colon (":"), or space (" ")—will cause the string to be rejected as an invalid UTI. At the API layer, no error is generated for invalid UTIs."
If your project name or application name contains a space or other illegal character, either use an explicit Bundle ID (e.g. A1B2C3D4E5.com.yourcompany.yourproductname) instead of the default Bundle Identifier, or change your Product Name in your Target's Build Info pane.
WARNING: While an invalid UTI may work when testing on your device, it will generally cause an error when uploaded to the App Store.
Back to Top 
Ad Hoc Distribution not properly configured
If you're doing an Ad Hoc distribution, you must properly configure your project to include an Entitlements.plist file and uncheck the get-task-allow checkbox (which sets it to False). You can confirm this is the cause of your errors by looking in the Console for errors similar to that in Listing 2
Listing 2: A Console Log error pointing to an improperly configured Ad Hoc Distribution. Tue Nov 11 14:20:24 unknown mobile_installation_proxy[2012] <Error>: install_embedded_profile: Skipping the installation of the embedded profile
Tue Nov 11 14:20:24 unknown securityd[2004] <Error>: mobile_installat[2012] SecItemCopyMatching: missing entitlement
Tue Nov 11 14:20:25 unknown mobile_installation_proxy[2012] <Error>: entitlement 'get-task-allow' has value not permitted by a provisioning profile
Tue Nov 11 14:20:25 unknown mobile_installation_proxy[2012] <Error>: verify_executable: Could not validate signature: e8008016
[...]
Tue Nov 11 14:20:25 unknown mobile_installation_proxy[2012] <Error>: install_application: Could not preflight application install
Tue Nov 11 14:20:25 unknown mobile_installation_proxy[2012] <Error>: handle_install: Installation failed
See the "Building your Application with Xcode for Distribution" section of the iPhone Developer Program Portal User Guide in the iPhone Portal for instructions on setting up your Entitlements.plist.
Back to Top 
Other causes and resolutions
While a mismatch between the App ID and the Bundle Identifier or an improperly configured Ad Hoc distribution are the most common causes of this error, there are others:
Missing or incorrect Unique Device Identifier (UDID)
Your provisioning profile may not include the UDID of the device to which you're deploying. This may happen when you add a new device to your development pool, when you're doing an Ad Hoc distribution, or if you forget to send the provisioning profile to your Ad Hoc testers.
It may also include an incorrect UDID, either because it was mistyped, or because it's not all lowercase (which would happen when copying UDIDs from iTunes 7).
Back to Top 
Revoked certificates
If you've revoked your "iPhone Developer" or "iPhone Distribution" certificates, kept the old certificates on your Keychain, and your provisioning profile or project continue to reference the old certificate, Xcode may sign your application with a certificate that's different from the one in your provisioning profile. You should delete the revoked certificates (after making a backup, of course), and update and install your provisioning profiles.
Back to Top 
Document Revision History
| Date |
Notes |
| 2009-05-11 |
First Version |
Posted: 2009-05-11 |
Trackback Address ::
http://joyholic.kr/trackback/376
2009/04/07 13:14
original : http://www.gamedev.net/reference/articles/article2008.asp
A Guide To Starting With OpenAL
by Lee Winder
Download the sample code for this article here.
So, What Exactly Is OpenAL?
OpenAL is a (smallish) API that is designed to aid cross platform development, specifically in the area of sound and music. It is designed to be very simple at the expense of (personally speaking) functionality e.g. Panning is not supported (though some people would claim that today's 3D games would rarely, if ever, use features like that), though through clever coding, it is possible to simulate all the missing features.
Its style is influenced by OpenGL
, in regards to function / variable name layout, type definitions etc. so any seasoned OpenGL coder will easily be able to find their way around, but even to novices, it is simple and easy to understand (even the docs are helpful!).
Okay, now you know a little about it, let's see how to use it!
Where Can I Get My Hands On It?
Of course, the first thing you need to do is actually get the OpenAL SDK. You can do this by going to www.openAL.org . It's only about 7MB, so it shouldn't take that long to do. When you've installed it (for the sake of this article, I installed it at C:\oalsdk), have a quick look at the docs and the examples to see how simple it is to use.
Initialization
What we need to do first is to set up OpenAL so we can actually use its feature set. This is extremely simple to do:
// Init openAL
alutInit(0, NULL);
// Clear Error Code (so we can catch any new errors)
alGetError();
That's it, now we are ready to use it!
Sources, Buffers and Listeners
Before we carry on, I'll explain the main concept behind OpenAL. The API uses 3 main components: sources, buffers and listeners. Here is a quick explanation of each -
Sources: A source in OpenAL is exactly what it sounds like, a source of a sound in the world. A source is linked to one or more buffers, and then asked to play them. They have position and orientation in the world, as well as velocity, for doppler effects.
Listener: A listener is (simply put) the ears of the world. It is generally set at the location of the player, so that all sounds will be relative to the person playing. This could be the actual camera location, or some other random position, whatever you want…
Buffers: Buffers are exactly like any other kind of sound buffers you may have used. Sound is loaded into the buffer, and then the sound in the buffer is played. The thing that differs from normal is that no functions directly call the buffer. Instead, they are linked to a source (or multiple sources) and then the sources themselves play, playing the sound from the buffers in the order that they have been queued.
Okay, now that we know about the things that make OpenAL what it is, how do you use them? Well, read on…
How Do We Create What We Need?
Buffers
The first things we should create are buffers, so we can actually store the sound we want to play. This is done with one simple call
ALuint buffers[NUM_BUFFERS];
// Create the buffers
alGenBuffers(NUM_BUFFERS, buffers);
if ((error = alGetError()) != AL_NO_ERROR)
{
printf("alGenBuffers : %d", error);
return 0;
}
All this does is create however many buffers you wish, ready to be filled with sound. The error checking is there for completeness.
The buffers do not need to be created at the start of the program; they can be created at any time. However, it's (in my opinion) neater if you create everything you need when you start. Of course, this isn't always possible, so create them in exactly the same way if you need to.
Now, let's load in the sound(s) we want to use
ALenum format;
ALsizei size;
ALsizei freq;
ALboolean loop;
ALvoid* data;
alutLoadWAVFile("exciting_sound.wav", &format, &data, &size, &freq, &loop);
if ((error = alGetError()) != AL_NO_ERROR)
{
printf("alutLoadWAVFile exciting_sound.wav : %d", error);
// Delete Buffers
alDeleteBuffers(NUM_BUFFERS, buffers);
return 0;
}
This loads in the file we have requested and fills in the given the data. Again, the error check is there for completeness. Note though the call to alDeleteBuffers(…). Even though it has failed, we need to clean up after ourselves, unless of course we want memory leaks ;)… There is also a function (alutLoadWAVMemory(…) ) that lets you load the data from memory. Take a peek at the documentation for notes on that one.
Now that we have loaded in the sound, we need to fill up one of the buffers with the data.
alBufferData(buffers[0],format,data,size,freq);
if ((error = alGetError()) != AL_NO_ERROR)
{
printf("alBufferData buffer 0 : %d", error);
// Delete buffers
alDeleteBuffers(NUM_BUFFERS, buffers);
return 0;
}
This takes the data we received from alutLoadWAVFile(…) and puts it into the buffer, ready for it to be assigned to a waiting source and played. Again, notice how we delete the buffers if we fail.
Now that the buffer is filled with data, we still have the sound data in memory also, taking up valuable space. Get rid of it with:
alutUnloadWAV(format,data,size,freq);
if ((error = alGetError()) != AL_NO_ERROR)
{
printf("alutUnloadWAV : %d", error);
// Delete buffers
alDeleteBuffers(NUM_BUFFERS, buffers);
return 0;
}
This just deletes the no longer needed sound data from memory, as the data we actually need is stored in the buffer!
Sources
Okay, so we have loaded the sound into the buffer, but as I said earlier, we can't play it until we have attached it to a source. Here's how to do that!
ALuint source[NUM_SOURCES];
// Generate the sources
alGenSources(NUM_SOURCES, source);
if ((error = alGetError()) != AL_NO_ERROR)
{
printf("alGenSources : %d", error);
return 0;
}
The above piece of code creates all the sources we need. This is exactly the same procedure as alGenBuffers(…), and the same rules apply. It is common to have far more sources than buffers, as a buffer can be attached to more than one source at the same time. Now that the source is created we need to attach a buffer to it, so we can play it…
Attaching buffers to sources is again very easy. There are two ways to do it: One way is to attach a single buffer to the source, whereas the other way is to queue multiple buffers to the source, and play them in turn. For the sake of this article, I'm just going to show you the first way.
alSourcei(source[0], AL_BUFFER, buffers[0]);
if ((error = alGetError()) != AL_NO_ERROR)
{
printf("alSourcei : %d", error);
return 0;
}
This takes the buffer and attaches it to the source, so that when we play the source this buffer is used. The function alSourcei(…) is actually used in more than one place (in that it is a generic set integer property function for sources). I won't really go into this here, maybe another day.
Now that we have set the source and buffer, we need to position the source so that we can actually simulate 3D sound. The properties we will need to set are position, orientation and velocity. These are pretty self explanatory, but I'll mention velocity a little. Velocity is used to simulate a doppler effect. Personally, I can't stand doppler effects so I set the array to 0's, but if you want the effect, the effect will be calculated in respect to the listener's position (That's coming up next!)
Okay to set these values, you use one simple function.
ALvoid alSourcefv(ALuint source,ALenum pname,ALfloat *values);
This function is similar to the alSourcei(…) function except this is a generic function to set an array of floats as a source property, where ALfloat *values will be an array of 3 ALfloats. So, to set our position, velocity and orientaion we call :
alSourcefv (source[0], AL_POSITION, sourcePos);
alSourcefv (source[0], AL_VELOCITY, sourceVel);
alSourcefv (source[0], AL_DIRECTION, sourceOri);
These variables default them selves to 0 if you do not set them, although it is more than likely that you will. I haven't included it here, but it is best to check for errors in the standard way, because it's a good idea to catch them as they happen.
Okay, that is a source set up, now we need one more thing - the Listener.
Listeners
As I said before, the listener is the ears of the world, and as such, you can only have one of them. It wouldn't make sense to have more than one, as OpenAL wouldn't know which one to make the sounds relevant to. Because there is only ever one, we do not need to create it, as it comes ready made. All we have to do is set where it is, the direction it is facing and its velocity (again for doppler effects). This is done in exactly the same way as sources with the one function
ALvoid alListenerfv(ALenum pname,ALfloat *values);
This works in exactly the same way as alSourcefv(…) and alSourcei(…) except it works on the listener. As I said, the listener comes ready made; you do not have to specify it. To set the position, orientation and velocity call:
alListenerfv(AL_POSITION,listenerPos);
alListenerfv(AL_VELOCITY,listenerVel);
alListenerfv(AL_ORIENTATION,listenerOri);
Again, it will be a good idea to check for errors. One thing to note here is that in this case, orientation is an array of 6 ALfloat's . The first three define its look at direction, while the second three define the 'up' vector. Once this is done, everything is finally set up (It wasn't that hard was it?). Now we can get down to the thing we are all here for: Playing the sound at last
The Hills Are Alive, With The Sound of Music (!)
alSourcePlay(source[0]);
Yup, that's it. That's all that is required to play your sample. OpenAL will calculate the volume regarding the distance and the orientation. If you specified a velocity for either sources or listeners you'll also get doppler effects. Now that it's playing, we might need it to stop playing…
alSourceStop(source[0]);
Or reset it to the start of the sample…
alSourceRewind(source[0]);
Or pause it…
alSourcePause(source[0]);
To unpause it, just call alSourcePlay(…) on the sample.
I've rushed through those, but they really are that simple. If you have a look at the OpenAL Specification and Reference document, on page 32, it will tell you exactly the actions that will happen if you call these functions on a source, depending on its state. It's simple enough, but I'm not going to go into it now.
That's all you need to do to get OpenAL up and running, but what about shutting it down?
Shutting It All Down
Shutting down is even easier than it was to set everything up. We just need to get rid of our sources, buffers and close OpenAL.
alDeleteSources(NUM_SOURCES, source);
alDeleteBuffers(NUM_BUFFERS, buffers);
This will delete all the sources in that array of sources. Make sure you have deleted all of them before you call the next line.
alutExit();
And that's it. OpenAL is now shut down and you can carry on with what ever you want to do next
As this is the first article I have written, I hope it is of some use to at least one person. There's lots more to OpenAL, but this simple how-to should easily get you set up so you can look at the more complicated features (if there are any) of the API.
Lee Winder
Leewinder@hotmail.com
Trackback Address ::
http://joyholic.kr/trackback/375
2009/03/23 18:36
Trackback Address ::
http://joyholic.kr/trackback/370
2009/03/20 10:16
Original :
http://discussions.apple.com/thread.jspa?messageID=7512737
|
Topic : iPhone SDK: How to create an image from raw data
 |
This topic has been archived - replies are not allowed. |
|
|
This question is answered. "Helpful" answers available: 2 . "Solved" answers available: 1 . |
|
Replies : 7 - Last Post : Jul 7, 2008 12:11 AM by: asnor |
|
|
Posts: 21
Registered: Aug 30, 2006 | |
|
iPhone SDK: How to create an image from raw data
Posted: Apr 30, 2008 12:23 PM |
|
|
Creating a UIImage from some form of bitmap file format is easy, whether you let UIImage load the file itself or create it with an NSData. But what if you have raw bitmap data in memory and you want to create an image?
In Cocoa NSBitmapImageRep can be created by passing it a pointer to a block of memory and the relevant heigh, width, bit depth etc. information. From that you can easily create an NSImage. There doesn't seem to be anything equivalent on the iPhone. CGImage can be created but it looks like you have to write a CGImageProvider. CGBitmapContextCreate takes a void * to a block of memory. Does it clear that block?
Is there a good way to do this?
MacBook Pro / Core Duo Mini Mac OS X (10.5.2)
| |
 |
Posts: 21
Registered: Aug 30, 2006 | |
|
Re: iPhone SDK: How to create an image from raw data
Posted: May 2, 2008 2:29 PM in response to: Andrew Rennard |
|
|
That works if your image data is in some kind of format UIImage recognizes, like TIFF or JPEG. Mine is just raw RGB values. I got it working using CGBitmapContextCreate(). It's basically the same way I ended up doing it with NSImageRep/NSImage on the Mac. I still think it would be handy to have as a method of NSImage AND of UIImage.
MacBook Pro / Core Duo Mini Mac OS X (10.5.2)
| | |
 |
Posts: 43
Registered: Jul 1, 2008 | |
|
Re: iPhone SDK: How to create an image from raw data
Posted: Jul 4, 2008 12:10 AM in response to: ceoyoyo |
|
|
Hi ceoyoyo , can you give me some help , now i just want to create an image from rgb565 raw data , but meet a problem , and my code is here :
//////////////////////////////////////////////////////////////////////////
NSString *imagePath = [NSBundle mainBundle] pathForResource: @"mobile" ofType: @"rgb";
NSFileHandle* file = NSFileHandle fileHandleForReadingAtPath:imagePath;
NSData* imageData = file readDataToEndOfFile;
size_t width = 240;
size_t height = 320;
size_t bitsPerComponent = 5;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
size_t components = CGColorSpaceGetNumberOfComponents( colorSpace );
size_t bytesPerRow = (width * bitsPerComponent * components + 7)/8;
const void* data = imageData bytes;
CGContextRef context = CGBitmapContextCreate((void*)data, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaNoneSkipFirst);
///////////////////////////////////////////////////////////////////////////
till the program run to CGBitmapContextCreate , it always return nil , i don't know why , pls do me a favour.
Mac OS X (10.5.3) iPhone
| | |
 |
Posts: 15
From: USA
Registered: Jun 9, 2008 | |
|
Re: iPhone SDK: How to create an image from raw data
Posted: Jul 4, 2008 6:48 PM in response to: asnor |
|
|
You can't do RGB565 on a CGImageRef/CGContextRef. The only 5bpp modes supported are 1555 ARGB or 5551 RGBA. If you just need to display the image, use OpenGL. One of the supported texture formats is RGB565. If you need to save the image then you're going to have to pre-convert it to RGB888.
| | |
 |
Posts: 43
Registered: Jul 1, 2008 | |
|
Re: iPhone SDK: How to create an image from raw data
Posted: Jul 6, 2008 6:17 PM in response to: ElNono |
|
|
ElNono , thanks very much for your suggestion , i will try it at once.
Mac OS X (10.5.3) iPhone
| | |
 |
Posts: 43
Registered: Jul 1, 2008 | |
|
Re: iPhone SDK: How to create an image from raw data
Posted: Jul 7, 2008 12:11 AM in response to: ElNono |
|
|
You can't do RGB565 on a CGImageRef/CGContextRef. The only 5bpp modes supported are 1555 ARGB or 5551 RGBA. If you just need to display the image, use OpenGL. One of the supported texture formats is RGB565. If you need to save the image then you're going to have to pre-convert it to RGB888.
hi ElNono , i have test the RGB888 data now , the image can show , but another problem is the image just like serveral picture over lap together , also is blurred , my code is here:
const size_t width = 1024;
const size_t height = 768;
const size_t bitsPerComponent = 8;
const size_t bitsPerPixel = 32;
const size_t bytesPerRow = (bitsPerPixel * width)/8;
CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSString *imagePath = [NSBundle mainBundle] pathForResource: @"Test" ofType: @"rgb";
NSFileHandle* file = NSFileHandle fileHandleForReadingAtPath:imagePath;
NSData* imageData = file readDataToEndOfFile;
CGContextRef context = CGBitmapContextCreate((void*)imageData bytes, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
CGImageRef imageRef = CGBitmapContextCreateImage (context);
UIImage*rawImage = UIImage imageWithCGImage:imageRef;
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
CGImageRelease(imageRef);
Mac OS X (10.5.3) iPhone
| | | |
Trackback Address ::
http://joyholic.kr/trackback/368
2009/03/19 21:26
Original :
http://craiggiles.wordpress.com/2009/01/
Since I am developing a game engine that I would like to re-use, I have chosen to host all game data in the form of XML files. There are various reasons for doing this, partly because I can make game editors (Map Editor, Item Editor, NPC Editor, etc) and partly because I value using re-useable code.
In order to get it all working, I had to explore the NSXMLParser given by the iPhone SDK. With XNA and the .NET framework, I got used to reading in XML in a very specific way, and the iPhone does it quite differently. Currently, my test map’s XML file looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Map>
<MapName>Test Map</MapName>
<MapContentName>Map001</MapContentName>
<MapDimensions>
<MapWidth>5</MapWidth>
<MapHeight>5</MapHeight>
</MapDimensions>
<TileDimensions>
<TileWidth>32</TileWidth>
<TileHeight>32</TileHeight>
</TileDimensions>
<SpriteSheetName></SpriteSheetName>
<MapLayers>
<BaseLayer>0, 1, 0, 0, 0, 0, 0, 0, 0</BaseLayer>
<MiddleLayer>0, 1, 0, 0, 0, 0, 0, 0, 0</MiddleLayer>
<TopLayer>0, 1, 0, 0, 0, 0, 0, 0, 0</TopLayer>
<AtmosphereLayer>0, 1, 0, 0, 0, 0, 0, 0, 0</AtmosphereLayer>
<CollisionLayer>0, 0, 0, 0, 0, 0, 0, 0, 0</CollisionLayer>
</MapLayers>
</Map>
In order to read in the XML, there are 3 methods that you need to implement. Since your XML parser goes line by line, you will need to write a method that starts an element, ends an element, and reads a character. Such as:
-
-
- - (void)parser:(NSXMLParser *)parser
- didStartElement:(NSString *)elementName
- namespaceURI:(NSString *)namespaceURI
- qualifiedName:(NSString *)qName
- attributes:(NSDictionary *)attributeDict
- {
- }
-
-
- - (void)parser:(NSXMLParser *)parser foundCharacters:(NSMutableString *)string
- {
- }
-
-
- - (void) parser:(NSXMLParser *)parser
- didEndElement:(NSString *)elementName
- namespaceURI:(NSString *)namespaceURI
- qualifiedName:(NSString *)qName
- {
- }
// Start of element
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
}
// Found Character
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSMutableString *)string
{
}
// End Element
- (void) parser:(NSXMLParser *)parser
didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
}
Once you have these methods set up, all you really need to do is populate them. For instance, in the “Start Element” method, if your “elementName” = “MapName” (in the above XML case) you would allocate the map classes NSString like so;
-
- mapName = [NSMutableString string];
mapName = [NSMutableString string];
When you found a character, you would store those into a string, and when the end of the element is reached, you would put that string into whatever element it was reading. For example, the map name:
-
- mapName = stringValueFromFoundCharacter;
mapName = stringValueFromFoundCharacter;
Not too hard, but wasn’t easy to figure out either.. At least I know it and now can implement readers for every data that I wish to store as XML!
Trackback Address ::
http://joyholic.kr/trackback/367
2009/03/19 21:19
Original : http://craiggiles.wordpress.com/2009/01/28/iphone-gaming-framework-screen-manager-update/
I don’t have time to write up a complete tutorial, but I will soon.. but I wanted to show just how the screen manager works. First, the video so you have an idea;
Click here for iPhone Screen Management Demo
Since I am on OSX, I am working on a way to record videos and upload them to youtube like I did with windows. When I do, I’ll embed them into the page again. For now, this solution works.
As you can see, the transitions and everything works just like an XNA project would. As said before, I converted Jeff’s GLViewController to be my screen manager. To use it, what you would do is something like the following;
-
- TitleScreen *newScreen = [[TitleScreen alloc] init];
- [controller addScreen:newScreen];
- [newScreen release];
TitleScreen *newScreen = [[TitleScreen alloc] init];
[controller addScreen:newScreen];
[newScreen release];
the addScreen method will retain the screen, load any content the screen will need in the game, and then add it to the screens array. Since the controller is handling the screen, and has retained the screen, we then need to release it. It is now in the controllers hands!
The controller knows if a screen is a popup screen (ala dialog box) or a full game screen (ala battle screen / inventory screen / main game screen, etc) and will transition based on what kind of screen it is. Popups get no transition, full screens will get the fade effect seen in the video. Same for transitioning off. To exit a screen, you would do the following;
-
- if (condition == true)
- {
-
- [self exitScreen];
- }
if (condition == true)
{
//in the game screens "update" method. Self refers to the game screen
[self exitScreen];
}
the game screen will handle any transitions if it needs to.. popup’s will just pop off the stack.
One other thing that I found really interesting, was input handling. since the iPhone uses an event like system, the moment you touch the screen the iPhone sends a message saying “HEY! I’ve been touched!” What I’ve done was create an InputManager class that takes that input, and stores it in either the previousInputState, currentInputState, or queryInputState. Obviously the previous and current input states are self explanitory, the queryInputState is the state that has happened but has not been committed quite yet (meaning, the screen manager has not updated the input state quite yet) The screen manager would then update the input state, and filter it to the top-most screen.
What I would like to do, is create a project template for this framework for any 2d developer wishing to get started in iPhone Games Development. Obviously this template will be an ongoing project, and as improvements are made the template will be updated. My problem, is google has been unhelpful for trying to create a template file. If anyone knows of a good tutorial to look at, or good reading material, please send it my way! I can be reached at my listed email address ( CraigGiles9@yahoo.com ) If I can’t find a way to convert this into a template, the best way to distribute this would be to zip it up and that would be a pain when you want to start a new project.
Later this weekend, I will try to do a full writeup of the screen management system. Until then, happy coding!
Trackback Address ::
http://joyholic.kr/trackback/366
2009/03/19 21:16
Original :
http://craiggiles.wordpress.com/2009/02/18/iphone-gaming-framework-amendment/
Its been great to see a lot of you take apart the code and really see what you can do! There have been several people who have been in contacts with me via email, trying to get everything up and running.. but as you may have known, there are a few things missing from the tutorials. This is the amendment, going to patch up the final few things to get you back on track!
First thing is in the GLView.m file. We have a screen manager, but we are not telling the game to update or draw through the screen manager. Lets fix that! Go into your -(void)drawView method, and right below the glBindFrameBufferOES() call, you should have a [controller drawView:self]; … we’re going to change that to the following:
-
-
-
- [controller updateView:self WithTime:(float)[animationTimer timeInterval]];
-
-
-
- [controller drawView:self WithTime:(float)[animationTimer timeInterval]];
//
// Update the view
//
[controller updateView:self WithTime:(float)[animationTimer timeInterval]];
//
// Draw the view
//
[controller drawView:self WithTime:(float)[animationTimer timeInterval]];
You’re going to call the controllers updateView and drawView methods, and pass in a time interval from the animationTimer. Now the controller will update and draw the game screens!
Secondly, There were a few people who never added a blankTexture to their project. I suggest opening an image editor, creating a black image called “blankTexture.png” and drag it into your resources file. You’ll notice, in the loadContent method, the screen manager allocates memory for the input manager, sets landscape mode, and then right after that loads in a blankTexture.png. If it doesn’t have one, it can’t load it.
Next amendment is more of a “clean up” since I didn’t fully understand how the retain / release system worked (Hey! i’m still a new mac developer too! :D ) In your addScreen method, you don’t need a [screen retain] since adding it to the screens NSMutableArray will retain the object. Likewise in the releaseScreen method, you’ll need to take out the [screen release] unless you like having your game crash when releasing a screen that has already been deallocated :)
With everything working, you’ll notice that your textures are being drawn “upside down” … well since we changed the way the coordinate system worked, and Apples “Texture2D” class works with the previous coordinate system, that will need to be changed. There are a few ways to do this; some people who really know their OpenGL suggested to flip the image before binding it.. the approach I took was just to adjust the vertices in the Texture2D draw methods.
This goes into your “drawAtpoint” method, comment out the current array:
-
-
-
- GLfloat vertices[] =
- {
- -width / 2 + point.x, height / 2 + point.y, 0.0,
- width / 2 + point.x, height / 2 + point.y, 0.0,
- -width / 2 + point.x, -height / 2 + point.y, 0.0,
- width / 2 + point.x, -height / 2 + point.y, 0.0
-
- };
//
// Modified by Craig Giles to flip the texture upside down while using my coord system
//
GLfloat vertices[] =
{
-width / 2 + point.x, height / 2 + point.y, 0.0,
width / 2 + point.x, height / 2 + point.y, 0.0,
-width / 2 + point.x, -height / 2 + point.y, 0.0,
width / 2 + point.x, -height / 2 + point.y, 0.0
};
This goes into your “drawAtRect” method, comment out the current array:
-
-
-
- GLfloat vertices[] =
- {
- rect.origin.x, rect.origin.y + rect.size.height, 0.0,
- rect.origin.x + rect.size.width, rect.origin.y + rect.size.height, 0.0,
- rect.origin.x, rect.origin.y, 0.0,
- rect.origin.x + rect.size.width, rect.origin.y, 0.0
-
- };
//
// Modified by Craig Giles to flip the texture upside down while using my coord system
//
GLfloat vertices[] =
{
rect.origin.x, rect.origin.y + rect.size.height, 0.0,
rect.origin.x + rect.size.width, rect.origin.y + rect.size.height, 0.0,
rect.origin.x, rect.origin.y, 0.0,
rect.origin.x + rect.size.width, rect.origin.y, 0.0
};
I think thats all the changes. Thanks again for everyones feedback on the last few writeups! I am looking over a few documents sent to me about templates, so I can release this as a starting template. Will let everyone know more when I can! As always, feel free to email me or post a comment if you need help with something.
Trackback Address ::
http://joyholic.kr/trackback/365
2009/03/19 19:49
Original : http://craiggiles.wordpress.com/2009/02/03/iphone-gaming-framework-stage-2-tutorial/
NOTE:: I am still looking for a good way to turn this into a template and release it for anyone wishing to install this for the base of their game. If you know of a good resource for doing so, please let me know, as google has been fairly unhelpful as of this point.
Welcome back everyone! Did you all finish Stage 1 of the tutorial? If not, please do that, as we are going to be building off stage 1 in our next tutorial. Stage 1 can be found HERE
Okay, now that stage 1 is done, you have a working screen management system… except you don’t have an input manager to help you with input management! Remember my note from previous tutorials, there are MANY solutions to a problem, and this is just one of many. Our input class works as follows: If a touch is detected, the GLViewController will send a message to the input manager, and that message will be stored in an input “state” called “queryState.” Before the view controller updates any of the game screens, it will send a message to the input manager to update the input, and this is when the input is changed from the “queryState” to “currentState” and the current state is then set to the previous state.
So lets look at the code, yeah? First the InputManager.h file
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #import <Foundation/Foundation.h>
- #import "InputState.h"
-
- @interface InputManager : NSObject
- {
- @private
- bool isLandscape;
- InputState *currentState;
- InputState *previousState;
- InputState *queryState;
- }
-
- @property (nonatomic, readwrite) bool isLandscape;
- @property (nonatomic, readonly) InputState *currentState;
- @property (nonatomic, readonly) InputState *previousState;
-
- - (void) update:(float)deltaTime;
-
-
-
-
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
- - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
-
-
-
-
- - (void) update:(float)deltaTime;
- - (bool) isButtonPressed:(CGRect)rect;
- - (bool) isButtonHeld:(CGRect)rect;
- - (void) convertCoordinatesToLandscape;
-
-
-
-
- + (bool) doesRectangle:(CGRect)rect ContainPoint:(CGPoint)point;
-
- @end
//
// The input manager is a helper class that houses any input
// that can be obtained by the game engine. As a touch is detected
// on screen, it will send a message to the input helper. The input
// helper will then hold onto that message and filter it into the
// current state on the next game loop. The current state is moved
// to the previous state, and any incoming touches are then put
// back into the query state, waiting to be updated.
//
// This method of updating lets the game filter updates to the top-most
// game screen and not have to worry about un-focused screens handling
// input that was not intended for them.
//
// Created by Craig Giles on 1/3/09.
//
#import <Foundation/Foundation.h>
#import "InputState.h"
@interface InputManager : NSObject
{
@private
bool isLandscape;
InputState *currentState;
InputState *previousState;
InputState *queryState;
}
@property (nonatomic, readwrite) bool isLandscape;
@property (nonatomic, readonly) InputState *currentState;
@property (nonatomic, readonly) InputState *previousState;
- (void) update:(float)deltaTime;
//
// Touch events
//
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer;
//
// Helper Methods
//
- (void) update:(float)deltaTime;
- (bool) isButtonPressed:(CGRect)rect;
- (bool) isButtonHeld:(CGRect)rect;
- (void) convertCoordinatesToLandscape;
//
// Class methods
//
+ (bool) doesRectangle:(CGRect)rect ContainPoint:(CGPoint)point;
@end
And the .m file
//
// The input manager is a helper class that houses any input
// that can be obtained by the game engine. As a touch is detected
// on screen, it will send a message to the input helper. The input
// helper will then hold onto that message and filter it into the
// current state on the next game loop. The current state is moved
// to the previous state, and any incoming touches are then put
// back into the query state, waiting to be updated.
//
// This method of updating lets the game filter updates to the top-most
// game screen and not have to worry about un-focused screens handling
// input that was not intended for them.
//
// Created by Craig Giles on 1/3/09.
//
#import "InputManager.h"
@implementation InputManager
//
// Getters / Setters
//
@synthesize isLandscape;
@synthesize currentState;
@synthesize previousState;
//
// Initialization
//
- (id) init
{
self = [super init];
if (self != nil)
{
//
// Allocate memory for all of the possible states
//
currentState = [[InputState alloc] init];
previousState = [[InputState alloc] init];
queryState = [[InputState alloc] init];
//
// Set the initial coords for the touch locations.
//
currentState.touchLocation = CGPointMake(0, 0);
previousState.touchLocation = CGPointMake(0, 0);
queryState.touchLocation = CGPointMake(0, 0);
}
return self;
}
//
// Deallocation
//
- (void) dealloc
{
[currentState release];
[previousState release];
[queryState release];
[super dealloc];
}
//
// Update the input manager. This method will take the
// values in updateState and apply them to the current state.
// in essence, this method will "query" the current state
//
- (void) update:(float)deltaTime
{
// Sets previous state to current state
previousState.isBeingTouched = currentState.isBeingTouched;
previousState.touchLocation = currentState.touchLocation;
// Sets the current state to the query state
currentState.isBeingTouched = queryState.isBeingTouched;
currentState.touchLocation = queryState.touchLocation;
// converts the coordinate system if the game is in landscape mode
[self convertCoordinatesToLandscape];
}
//
// Touch events
//
// These events are filtered into the input manager as they occur.
// Since we want to control how our input, we are going to use a
// queryState as the "Live" state, while our current and previous
// states are updated every loop. For this reason, we are always
// modifying the queryState when these touch events are detected,
// and the current state is only modified on [self update:deltaTime];
//
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer
{
queryState.isBeingTouched = YES;
queryState.touchLocation = [[touches anyObject] locationInView:view];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer
{
queryState.isBeingTouched = YES;
queryState.touchLocation = [[touches anyObject] locationInView:view];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer
{
queryState.isBeingTouched = NO;
queryState.touchLocation = [[touches anyObject] locationInView:view];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)view WithTimer:(NSTimer *)deltaTimer
{
queryState.isBeingTouched = NO;
}
//
// When in landscape mode, the touch screen still records input
// as if it were in portrait mode. To get around this, if we
// are writing a game in landscape we need to adjust the coordinate
// system on the touchscreen to match that of our world.
//
- (void) convertCoordinatesToLandscape
{
// If we are not in landscape mode, don't convert anything
if ( !isLandscape )
return;
// Otherwise, we will need to take the current touch location
// swap the x and y values (since in landscape, the portrait
// coordinate system means x will point up / down instead of
// left / right) and move the y position to match our origin
// point of (0,0) in the upper left corner.
int x = currentState.touchLocation.y;
int y = (currentState.touchLocation.x - 320);
// make sure we take the absolute value of y, since if we didn't
// y would always be a negative number.
y = abs(y);
// Since we were converting the current state, we need to update
// the current touch location
currentState.touchLocation = CGPointMake( x, y );
}
//
// Looks at the previous state, and the current state to determine
// weather or not the button (rectangle) was just pressed and released.
//
- (bool) isButtonPressed:(CGRect)rect
{
//
// If the current state is not being touched
// and the previous state is being touched, the
// user just released their touch. This is
// personal preference really, But i've found with
// my XNA programming, that its better to detect if
// a button was just released rather than if it was
// just pressed in when determining a button press.
//
if ( !currentState.isBeingTouched &&
previousState.isBeingTouched )
{
return [InputManager doesRectangle:rect ContainPoint:currentState.touchLocation];
}
return NO;
}
//
// Looks at the previous state, and the current state to determine
// weather or not the button (rectangle) is being held down.
//
- (bool) isButtonHeld:(CGRect)rect
{
//
// If the current state and the previous states
// are being touched, the user is holding their
// touch on the screen.
//
if ( currentState.isBeingTouched &&
previousState.isBeingTouched )
{
return [InputManager doesRectangle:rect ContainPoint:currentState.touchLocation];
}
return NO;
}
//
// Helper method for determining if a rectangle contains a point.
// Unsure if this will stay in the input helper or be moved to some
// sort of "RectangleHelper" class in the future, but for now this
// is a good spot for it. Remember, this works with our current coord
// system. If your engine uses a different coord system (IE: (0,0) is at
// the bottom left of the screen) you'll need to modify this method.
//
+ (bool) doesRectangle:(CGRect)rect ContainPoint:(CGPoint)point
{
//
// If the rectangle contains the given point, return YES
// Otherwise, the point is outside the rectangle, return NO
//
if (point.x > rect.origin.x &&
point.x < rect.origin.x + rect.size.width &&
point.y > rect.origin.y &&
point.y < rect.origin.y + rect.size.height)
{
return YES;
}
return NO;
}
@end
InputState just contains 2 values, and I have chosen to set them as the following:
-
- #import <Foundation/Foundation.h>
-
- @interface InputState : NSObject
- {
- bool isBeingTouched;
- CGPoint touchLocation;
- }
-
- @property (nonatomic, readwrite) bool isBeingTouched;
- @property (nonatomic, readwrite) CGPoint touchLocation;
-
- @end
-
-
-
-
- @implementation InputState
-
- @synthesize isBeingTouched;
- @synthesize touchLocation;
-
- - (id) init
- {
- self = [super init];
- if (self != nil) {
- isBeingTouched = NO;
- touchLocation = CGPointMake(0, 0);
- }
- return self;
- }
-
- @end
#import <Foundation/Foundation.h>
@interface InputState : NSObject
{
bool isBeingTouched;
CGPoint touchLocation;
}
@property (nonatomic, readwrite) bool isBeingTouched;
@property (nonatomic, readwrite) CGPoint touchLocation;
@end
//
// Implementation of InputState
//
@implementation InputState
@synthesize isBeingTouched;
@synthesize touchLocation;
- (id) init
{
self = [super init];
if (self != nil) {
isBeingTouched = NO;
touchLocation = CGPointMake(0, 0);
}
return self;
}
@end
It should be a good time to point out, that the input manager changes the coordinates of the actual touch, depending on if you’re playing your game in landscape mode or normal mode. One of the problems I was having, before I realized what was really happening, was my coordinates for the touch screen and coordinates for the game world were different. For example, my touch screen coordinates, if held landscape, (0,0) was in the lower left corner, while in the world coordinates, (0,0) was in the upper left corner. This gave me problems, as you can imagine.
In order to change this, I wrote a method that will convert the coordinates system if the screen is detected in landscape mode. It should be pointed out, that if you’re using a different origin point for your world (IE: Lower left corner instead of upper left) you’re conversions will have to be done differently.
Another method that is currently in the input manager class, is the [self doesRectangle:rect ContainPoint:touchLocation]; Inside this method, you’ll see that both current and previous states are being used in order to detect if a touch is being “touched” or “held.” This can be done differently, but the way I’ve chosen to implement it, is as follows;
if the button was just RELEASED (current state is not pressed, but previous state was) than the button was just “pressed.”
This is important to note, because it means if the user touches the screen, and holds their finger down, it won’t register as a “button press” until they release their finger. Some people prefer to do the opposite, meaning if the current state was just pressed and the previous state was un-pressed. Use what you feel comfortable with.
So now all we need to do is add a game screen or two, right? Well, I told you that I would help you get up a paused screen. This will help you learn how to get any sort of game screen up and running. First, lets take a look at the PausedScreen.h file
-
-
-
-
-
-
-
-
- #import <Foundation/Foundation.h>
-
- #import "GameScreen.h"
- #import "InputManager.h"
- #import "Texture2D.h"
-
- @interface PausedScreen : GameScreen
- {
- Texture2D *pausedText;
- double alphaValue;
- }
-
- @property (nonatomic, retain) Texture2D *pausedText;
-
- - (void) loadContent;
- - (void) unloadContent;
-
- - (void) handleInput:(InputManager *)input;
- - (void) update:(float)deltaTime OtherScreenHasFocus:(bool)otherFocus CoveredByOtherScreen:(bool)coveredByOtherScreen;
- - (void) draw:(float)deltaTime;
-
- @end
//
// The paused screen is just an overlay popup screen that is
// displayed to the user when the game is paused.
//
// Created by Craig Giles on 1/5/09.
//
#import <Foundation/Foundation.h>
#import "GameScreen.h"
#import "InputManager.h"
#import "Texture2D.h"
@interface PausedScreen : GameScreen
{
Texture2D *pausedText;
double alphaValue;
}
@property (nonatomic, retain) Texture2D *pausedText;
- (void) loadContent;
- (void) unloadContent;
- (void) handleInput:(InputManager *)input;
- (void) update:(float)deltaTime OtherScreenHasFocus:(bool)otherFocus CoveredByOtherScreen:(bool)coveredByOtherScreen;
- (void) draw:(float)deltaTime;
@end
If you notice, several of these methods are in “GameScreen.h” right? You’ll also notice the LACK of touch event classes. All input is handled by the input manager, and will be called from the view controller (the [self handleInput:input] method) Aah now you are getting why I went the touch manager route instead of re-writing every single “touchEvent” method in each game screen!
There are several methods that every game screen needs in order to function properly. It will need a loadContent / unloadContent methods, handleInput method, and the update / draw methods. Also keep in mind, every game screen will need to call the [super update:deltaTime...], and every screen (other than the paused screen, which is a popup screen) will need to call the [super draw:deltaTime]; within its draw method.
So now you have the basics of the game screen, let me show you the .m file.
-
-
-
-
-
-
-
-
- #import "PausedScreen.h"
-
- @implementation PausedScreen
-
- @synthesize pausedText;
-
-
-
-
- - (id) init
- {
- self = [super init];
- if (self != nil)
- {
-
-
- self.isPopup = YES;
-
- }
- return self;
- }
-
-
-
-
- - (void) loadContent
- {
-
-
-
-
-
- self.transitionOnTime = 0;
- self.transitionOffTime = 0;
-
-
- pausedText = [[Texture2D alloc] initWithString:@"Paused\nTap screen to unpause"
- dimensions:CGSizeMake(self.viewport.size.width, self.viewport.size.height)
- alignment:UITextAlignmentCenter
- fontName:@"Zapfino"
- fontSize:32];
-
-
-
- alphaValue = 0.75f;
- }
-
- - (void) unloadContent
- {
-
- [pausedText release];
- [super unloadContent];
- }
-
- - (void) handleInput:(InputManager *)input
- {
-
-
- if ([input isButtonPressed:self.viewport])
- {
- [self exitScreen];
- }
- }
-
- - (void) update:(float)deltaTime OtherScreenHasFocus:(bool)otherFocus CoveredByOtherScreen:(bool)coveredByOtherScreen
- {
-
-
-
- [super update:deltaTime OtherScreenHasFocus:otherFocus CoveredByOtherScreen:coveredByOtherScreen];
- }
-
- - (void) draw:(float)deltaTime
- {
-
- [self.controller fadeBackBufferToBlack:alphaValue];
-
- [pausedText drawInRect:CGRectMake(self.viewport.size.width / 4,
- self.viewport.size.height / 4,
- self.viewport.size.width / 2,
- self.viewport.size.height / 2)];
- }
- @end
//
// The paused screen is just an overlay popup screen that is
// displayed to the user when the game is paused.
//
// Created by Craig Giles on 1/5/09.
//
#import "PausedScreen.h"
@implementation PausedScreen
@synthesize pausedText;
//
// Initialize the pause menu screen
//
- (id) init
{
self = [super init];
if (self != nil)
{
// flag that there is no need for the game to transition
// off when the pause menu is on top of it
self.isPopup = YES;
}
return self;
}
//
// Load all content associated with the paused screen
//
- (void) loadContent
{
//
// Since this is a popup screen, we will over-ride the
// view controllers transition time and set this to instantly
// transition on and off.
//
self.transitionOnTime = 0;
self.transitionOffTime = 0;
// set the paused text
pausedText = [[Texture2D alloc] initWithString:@"Paused\nTap screen to unpause"
dimensions:CGSizeMake(self.viewport.size.width, self.viewport.size.height)
alignment:UITextAlignmentCenter
fontName:@"Zapfino"
fontSize:32];
// The alpha value of the background. below
// the paused text.
alphaValue = 0.75f;
}
- (void) unloadContent
{
//TODO: all unload content goes here
[pausedText release];
[super unloadContent];
}
- (void) handleInput:(InputManager *)input
{
// If the 'tap here to resume' button was pressed
// resume game
if ([input isButtonPressed:self.viewport])
{
[self exitScreen];
}
}
- (void) update:(float)deltaTime OtherScreenHasFocus:(bool)otherFocus CoveredByOtherScreen:(bool)coveredByOtherScreen
{
//TODO: Update logic goes here
// Update the base class
[super update:deltaTime OtherScreenHasFocus:otherFocus CoveredByOtherScreen:coveredByOtherScreen];
}
- (void) draw:(float)deltaTime
{
// Darken the screen to alert the player that it has been paused
[self.controller fadeBackBufferToBlack:alphaValue];
[pausedText drawInRect:CGRectMake(self.viewport.size.width / 4,
self.viewport.size.height / 4,
self.viewport.size.width / 2,
self.viewport.size.height / 2)];
}
@end
One thing to take note, since the PausedScreen is a popup screen, it has overwritten the transition on and transition off values sent to it by the view controller. Any game screen can do the same, for example if you are transitioning to a screen that you’ve made your own custom transition, turn the view controllers transition off and let the screen transition itself. (IE: a battle screen.)
So there you have it! I don’t remember if textures are drawing upside down with this coord system, but if they are, all you have to do is edit the Texture2D.m file to fix that. If you don’t know how, send me an email and I’ll show you how I did it, but there are several ways of doing it.
I hope you enjoyed my heavily commented code for the screen manager, input manager, and game screen classes. This should give you the basic knowledge to get up and running with your own iPhone OpenGL applications. If you found these useful, let me know and I’ll write up some more when I have the time. I’m still learning all of this myself, but sharing my knowledge will lead to more interesting games for everyone! Keep in mind these are very basic systems and can be heavily expanded on by creative programmers. Can’t wait to see what you guys come up with!
Happy coding all!
Trackback Address ::
http://joyholic.kr/trackback/364
2009/03/19 19:46
Buckle in guys, this is going to be a rather large tutorial. The goal for this tutorial is to get a basic screen management system up and running, ready to start writing game code. I would like to start off by saying the following: This is not the only way to get a project up and running! There are many many many ways of solving problems in the programming world. Some people might prefer to use Cocos2D for the iPhone, while others might prefer to roll their own engine from scratch. I did this more as a learning process for myself, and now that I’ve learned what I could, i thought I should share the knowledge to everyone else who is struggling with the problems that I’ve solved.
Also, keep in mind that this screen management system is basically a port of the GameStateManagement demo from the XNA sample ( http://creators.xna.com/ ) from C# to Objective-C with some modifications. Anyone currently using XNA should have a fairly easy time porting this over, as a lot of the code should be recognizable to you.
So, now that I’ve got that out of the way, lets begin! Your first step is going to head over to Jeff’s blog iPhoneDevelopment and pick up the Updated OpenGL Xcode Project Template.
Next step, is to follow his directions and install it! Once you have it installed, load a new project using his template. You will find that a few things are different, and a whole lot is added. Open up the GLView.m in the classes subdirectory, and add the following four methods:
-
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- {
- [controller touchesBegan:touches withEvent:event InView:self WithTimer:animationTimer];
- }
-
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- {
- [controller touchesMoved:touches withEvent:event InView:self WithTimer:animationTimer];
- }
-
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
- {
- [controller touchesEnded:touches withEvent:event InView:self WithTimer:animationTimer];
- }
-
- - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
- {
- [controller touchesCancelled:touches withEvent:event InView:self WithTimer:animationTimer];
- }
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[controller touchesBegan:touches withEvent:event InView:self WithTimer:animationTimer];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[controller touchesMoved:touches withEvent:event InView:self WithTimer:animationTimer];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[controller touchesEnded:touches withEvent:event InView:self WithTimer:animationTimer];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[controller touchesCancelled:touches withEvent:event InView:self WithTimer:animationTimer];
}
What this is going to do, is when your iPod touch or iPhone is touched, a message is sent to the GLView. We are going to capture that message, and send it to the GLViewController. Okay, got that done? GREAT! Now comes the fun stuff.
Open up your GLViewController.h file. You are going to be putting in quite a bit of code, and i’ll explain everything when we do the .m file, so for right now just adjust your .h file to look like the following. You’ll see the .m file is HEAVILY commented to show what everything is and what it does, and i’ll make some additional notes here as well… so here is the GLViewController.h file.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #import <UIKit/UIKit.h>
- #import <OpenGLES/EAGL.h>
- #import <OpenGLES/ES1/gl.h>
- #import <OpenGLES/ES1/glext.h>
-
- #import "Texture2D.h"
- #import "InputManager.h"
- #import "GameScreen.h"
- #import "TitleScreen.h"
-
- @class GLView;
- @interface GLViewController : UIViewController
- {
- NSMutableArray *screens;
- NSMutableArray *screensToUpdate;
- InputManager *input;
- Texture2D *blankTexture;
-
- bool isInitialized;
- bool traceEnabled;
-
- UIView *gameView;
- CGRect viewport;
- }
-
-
-
-
- @property (nonatomic, retain) NSMutableArray *screens;
- @property (nonatomic, retain) NSMutableArray *screensToUpdate;
- @property (nonatomic, retain) InputManager *input;
- @property (nonatomic, retain) Texture2D *blankTexture;
-
- @property (nonatomic, readwrite) bool isInitialized;
- @property (nonatomic, readwrite) bool traceEnabled;
-
- @property (nonatomic, retain) UIView *gameView;
- @property (nonatomic, readwrite) CGRect viewport;
-
-
-
-
- - (void) setupView:(GLView*)view;
- - (void) loadContent;
- - (void) addScreen:(GameScreen *)screen;
- - (void) removeScreen:(GameScreen *)screen;
- - (void) releaseScreen:(GameScreen *)screen;
- - (void) updateView:(GLView *)view WithTime:(float)deltaTime;
- - (void) drawView:(GLView *)view WithTime:(float)deltaTime;
- - (void) traceScreens;
- - (void) fadeBackBufferToBlack:(double)alpha;
-
-
-
-
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
-
- @end
//
// The View Controller is a service which mananges one or more GameScreen
// instances. It maintains a stack of screens, calls their Update and Draw
// methods at the appropriate times, and automatically routes the input to
// the topmost active screen.
//
// Created by XNA Development Team ( http://creators.xna.com/ ) as a
// ScreenManager.cs GameComponent.
//
// Adapted for iPhone Game Development by Craig Giles on 1/1/09.
//
//
// Import statements
//
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#import "Texture2D.h"
#import "InputManager.h"
#import "GameScreen.h"
#import "TitleScreen.h"
@class GLView;
@interface GLViewController : UIViewController
{
NSMutableArray *screens;
NSMutableArray *screensToUpdate;
InputManager *input;
Texture2D *blankTexture;
bool isInitialized;
bool traceEnabled;
UIView *gameView;
CGRect viewport;
}
//
// Properties
//
@property (nonatomic, retain) NSMutableArray *screens;
@property (nonatomic, retain) NSMutableArray *screensToUpdate;
@property (nonatomic, retain) InputManager *input;
@property (nonatomic, retain) Texture2D *blankTexture;
@property (nonatomic, readwrite) bool isInitialized;
@property (nonatomic, readwrite) bool traceEnabled;
@property (nonatomic, retain) UIView *gameView;
@property (nonatomic, readwrite) CGRect viewport;
//
// Methods
//
- (void) setupView:(GLView*)view;
- (void) loadContent;
- (void) addScreen:(GameScreen *)screen;
- (void) removeScreen:(GameScreen *)screen;
- (void) releaseScreen:(GameScreen *)screen;
- (void) updateView:(GLView *)view WithTime:(float)deltaTime;
- (void) drawView:(GLView *)view WithTime:(float)deltaTime;
- (void) traceScreens;
- (void) fadeBackBufferToBlack:(double)alpha;
//
// Touches events
//
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer;
@end
Its a good idea to look through the .h file to see what you can do with the screen manager. Obviously you can do the touch events (remember we connected those from the GLView?) but also, looking at the methods you will be able to add and remove screens from the screen manager, update and draw, fade back buffer to black, and a few other things. Lets see how it all works!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- #import "GLViewController.h"
- #import "GLView.h"
- #import "OpenGLCommon.h"
- #import "ConstantsAndMacros.h"
-
-
-
-
-
-
-
-
- const bool LANDSCAPE_MODE = NO;
-
-
-
-
-
-
-
- const float TRANSITION_ON_TIME = .70f;
- const float TRANSITION_OFF_TIME = .20f;
-
-
-
-
- @implementation GLViewController
-
-
-
-
- @synthesize screens;
- @synthesize screensToUpdate;
- @synthesize input;
- @synthesize blankTexture;
-
- @synthesize isInitialized;
- @synthesize traceEnabled;
-
- @synthesize gameView;
- @synthesize viewport;
-
-
-
-
-
- -(void)setupView:(GLView*)view
- {
-
- gameView = view;
-
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
-
-
-
-
-
-
-
-
-
-
- if ( LANDSCAPE_MODE )
- {
- viewport = CGRectMake(0, 0, 480, 320);
- glViewport(0, 0, viewport.size.height, viewport.size.width);
- glRotatef(-90, 0, 0, 1);
- glOrthof(0, viewport.size.width, viewport.size.height, 0, -10.0, 10.0);
-
- }
- else
- {
- viewport = CGRectMake(0, 0, 320, 480);
- glViewport(0, 0, viewport.size.width, viewport.size.height);
- glOrthof(0.0, viewport.size.width, viewport.size.height, 0.0, -1.0, 1.0);
-
- }
-
-
-
-
-
- glMatrixMode(GL_MODELVIEW);
-
- glDisable(GL_DEPTH_TEST);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- glEnable(GL_BLEND);
-
-
- glEnable(GL_TEXTURE_2D);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_VERTEX_ARRAY);
-
-
-
- glAlphaFunc(GL_GREATER, 0.1f);
- glEnable(GL_ALPHA_TEST);
-
-
-
-
-
-
-
- glLoadIdentity();
- glClearColor(.39f, 0.58f, 0.920f, 1.0f);
-
-
-
-
- [self loadContent];
-
- }
-
-
-
-
-
-
-
- - (void)loadContent
- {
-
-
-
-
- screens = [[NSMutableArray alloc] init];
- screensToUpdate = [[NSMutableArray alloc] init];
-
-
-
-
-
- input = [[InputManager alloc] init];
- input.isLandscape = LANDSCAPE_MODE;
- blankTexture = [[Texture2D alloc] initWithImage:[UIImage imageNamed:@"blankTexture.png"]];
-
- for (GameScreen *screen in screens)
- [screen loadContent];
-
-
-
-
- isInitialized = YES;
- traceEnabled = NO;
-
-
-
-
-
-
-
- TitleScreen *newScreen = [[TitleScreen alloc] init];
- [self addScreen:newScreen];
- [newScreen release];
- }
-
-
-
-
- - (void)dealloc
- {
-
-
-
-
-
-
-
- NSMutableArray *deleteScreens = [[NSMutableArray alloc] initWithArray:screens];
-
- for (GameScreen *screen in deleteScreens)
- {
- [self removeScreen:screen];
- [self releaseScreen:screen];
- }
-
- [deleteScreens release];
- [screens release];
- [screensToUpdate release];
- [input release];
- [blankTexture release];
-
- [super dealloc];
- }
-
-
-
-
-
-
- - (void)didReceiveMemoryWarning
- {
-
- [super didReceiveMemoryWarning];
- }
-
-
-
-
- - (void) addScreen:(GameScreen *)screen
- {
-
-
-
-
-
-
-
- screen.controller = self;
- screen.viewport = self.viewport;
- screen.transitionOnTime = TRANSITION_ON_TIME;
- screen.transitionOffTime = TRANSITION_OFF_TIME;
- screen.currentScreenState = TransitionOn;
- screen.transitionPosition = 1;
- [screen loadContent];
-
- [screen retain];
- [screens addObject:screen];
- }
-
-
-
-
-
-
-
- - (void) removeScreen:(GameScreen *)screen
- {
-
- [screen unloadContent];
- }
-
-
-
-
-
-
- - (void) releaseScreen:(GameScreen *)screen
- {
-
- [screens removeObject:screen];
- [screensToUpdate removeObject:screen];
-
-
- [screen release];
- }
-
-
-
-
-
-
-
- - (void) updateView:(GLView *)view WithTime:(float)deltaTime
- {
-
- [input update:deltaTime];
-
-
-
- [screensToUpdate removeAllObjects];
-
- for(GameScreen *screen in screens)
- [screensToUpdate addObject:screen];
-
- bool otherScreenHasFocus = NO;
- bool coveredByOtherScreen = NO;
-
-
- while ([screensToUpdate count] > 0)
- {
-
- GameScreen *screen = [screensToUpdate objectAtIndex:([screensToUpdate count] - 1)];
-
- [screensToUpdate removeObjectAtIndex:[screensToUpdate count] - 1];
-
-
- [screen update:deltaTime OtherScreenHasFocus:otherScreenHasFocus
- CoveredByOtherScreen:coveredByOtherScreen];
-
- if ([screen currentScreenState] == TransitionOn ||
- [screen currentScreenState] == Active)
- {
-
-
- if (!otherScreenHasFocus)
- {
- [screen handleInput:input];
- otherScreenHasFocus = YES;
- }
-
-
-
- if (![screen isPopup])
- coveredByOtherScreen = YES;
-
- }
- }
-
-
- if (traceEnabled)
- [self traceScreens];
-
-
-
-
-
-
-
- for (GameScreen *screen in screens)
- {
- if (screen.hasBeenUnloaded)
- {
- [self releaseScreen:screen];
- }
- }
- }
-
-
-
-
-
-
- - (void) drawView:(GLView *)view WithTime:(float)deltaTime
- {
-
- glClear(GL_COLOR_BUFFER_BIT);
-
-
- for (GameScreen *screen in screens)
- {
-
- if (screen.hasBeenUnloaded)
- continue;
-
- [screen draw:deltaTime];
- }
- }
-
-
-
-
-
-
- - (void) traceScreens
- {
-
- }
-
-
-
-
-
-
- - (void) fadeBackBufferToBlack:(double)alpha
- {
- glColor4f(alpha,alpha,alpha,alpha);
- [blankTexture drawInRect:self.viewport];
- glColor4f(1, 1, 1, 1);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
- {
- [input touchesBegan:touches withEvent:event InView:touchView WithTimer:timer];
- }
-
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
- {
- [input touchesMoved:touches withEvent:event InView:touchView WithTimer:timer];
- }
-
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
- {
- [input touchesEnded:touches withEvent:event InView:touchView WithTimer:timer];
- }
-
- - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
- {
- [input touchesCancelled:touches withEvent:event InView:touchView WithTimer:timer];
- }
-
- @end
//
// The View Controller is a service which mananges one or more GameScreen
// instances. It maintains a stack of screens, calls their Update and Draw
// methods at the appropriate times, and automatically routes the input to
// the topmost active screen.
//
// Created by XNA Development Team ( http://creators.xna.com/ ) as a
// ScreenManager.cs GameComponent.
//
// Adapted for iPhone Game Development by Craig Giles on 1/1/09.
//
//
// Import commands from Jeff's template
//
#import "GLViewController.h"
#import "GLView.h"
#import "OpenGLCommon.h"
#import "ConstantsAndMacros.h"
//
// This indicates weather or not the game will be played in
// landscape or portrait mode. While in landscape mode, the
// screen will be rotated, but also the input will be off.
// Touch coordinates for the screen will have to be converted
// before it reaches the input manager class.
//
const bool LANDSCAPE_MODE = NO;
//
// The time it takes for a game screen to transition
// These can be over written in the game screen init.
// If there is no values in the game screen itself, these
// will be used as the default values.
//
const float TRANSITION_ON_TIME = .70f;
const float TRANSITION_OFF_TIME = .20f;
//
// Implementation of the Screen Manager class
//
@implementation GLViewController
//
// Getters / Setters
//
@synthesize screens;
@synthesize screensToUpdate;
@synthesize input;
@synthesize blankTexture;
@synthesize isInitialized;
@synthesize traceEnabled;
@synthesize gameView;
@synthesize viewport;
//
// Setup View handles setting up OpenGL's Projection Matrix and
// enables all states needed for rendering the game to screen.
//
-(void)setupView:(GLView*)view
{
// Set the view to the gameView
gameView = view;
// Modify the Projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//
// Orthof projection is used for 2d games. This sets the coordinates to
// (0, 0) at the top left corner of the screen, and as you move downward
// your y value will increase. As you move to the right, your x value will
// increase.
// (left, right, bottom, top, near, far)
//
// If the game is going to be played in landscape mode, enable
// it via the bool switch at the top of the GLViewController.m file.
if ( LANDSCAPE_MODE )
{
viewport = CGRectMake(0, 0, 480, 320);
glViewport(0, 0, viewport.size.height, viewport.size.width);
glRotatef(-90, 0, 0, 1);
glOrthof(0, viewport.size.width, viewport.size.height, 0, -10.0, 10.0);
}
else // Game is to be played in portrait
{
viewport = CGRectMake(0, 0, 320, 480);
glViewport(0, 0, viewport.size.width, viewport.size.height);
glOrthof(0.0, viewport.size.width, viewport.size.height, 0.0, -1.0, 1.0);
}
//
// Setup Model view matrix
// Load graphics settings
//
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// needed to draw textures using Texture2D
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
// enables alpha for transparent textures
// I forget where I got these commands, iDevGames.net I think
glAlphaFunc(GL_GREATER, 0.1f);
glEnable(GL_ALPHA_TEST);
//
// Setup clear color (cornflower blue'ish)
// Call me crazy, but I got so used to this color developing
// for XNA. This is a little nod to the Microsoft Development
// Team :)
//
glLoadIdentity();
glClearColor(.39f, 0.58f, 0.920f, 1.0f);
//
// Call the view controllers loadContent method
//
[self loadContent];
}
//
// Loads all content needed to run the screen manager. This is seperated
// from the setupView method in order to seperate what is needed from OpenGL
// to setup the screen, and what is needed from the screen manager to set
// up the game structure.
//
- (void)loadContent
{
//
// Allocate memory for your arrays to hold the Screens "stacks."
// All game screens will be housed in this array for easy manipulation.
//
screens = [[NSMutableArray alloc] init];
screensToUpdate = [[NSMutableArray alloc] init];
//
// Allocate memory for the input manager and the blankTexture used
// to fade the screen in / out.
//
input = [[InputManager alloc] init];
input.isLandscape = LANDSCAPE_MODE;
blankTexture = [[Texture2D alloc] initWithImage:[UIImage imageNamed:@"blankTexture.png"]];
for (GameScreen *screen in screens)
[screen loadContent];
//
// Once we are initialized, set the bool values to appropriate values.
//
isInitialized = YES;
traceEnabled = NO;
//
// Adds a title screen to the game stack. This will be taken out
// later, and right now is only used for debugging purposes. It
// will be replaced with your splash screen or game introduction
// screen.
//
TitleScreen *newScreen = [[TitleScreen alloc] init];
[self addScreen:newScreen];
[newScreen release];
}
//
// When the view controller exits, we will need to clean up any memory used.
//
- (void)dealloc
{
//
// setup a delete screens array and add all of the current game screens
// to this array. We will then cycle through all game screens, unloading
// their content, and releasing them from the view controller. After all
// is said and done, we will then remove the deleteScreens array, and
// continue on releasing any other memory allocated for the view controller.
//
NSMutableArray *deleteScreens = [[NSMutableArray alloc] initWithArray:screens];
for (GameScreen *screen in deleteScreens)
{
[self removeScreen:screen];
[self releaseScreen:screen];
}
[deleteScreens release];
[screens release];
[screensToUpdate release];
[input release];
[blankTexture release];
[super dealloc];
}
//
// If the game is going over memory, this method will be called by the device
// warning that we are running low on memory and should release any un needed
// items.
//
- (void)didReceiveMemoryWarning
{
// <<TODO: Unload any un-needed game content here>>
[super didReceiveMemoryWarning];
}
//
// Add a screen to the view controller
//
- (void) addScreen:(GameScreen *)screen
{
//
// When adding a screen to the view controller, we will be
// setting some default values for the screen, and then call
// the screens "loadContent" method. Once everything is loaded,
// the view controller will retain the screen and add it to the
// screens array.
//
screen.controller = self;
screen.viewport = self.viewport;
screen.transitionOnTime = TRANSITION_ON_TIME;
screen.transitionOffTime = TRANSITION_OFF_TIME;
screen.currentScreenState = TransitionOn;
screen.transitionPosition = 1;
[screen loadContent];
[screen retain];
[screens addObject:screen];
}
//
// Unload all game content from the screen. This in turn
// sets a flag within the screen itself, that the content has
// been unloaded, and in the controllers Update method, all game
// screens that have been unloaded will be released from memory.
//
- (void) removeScreen:(GameScreen *)screen
{
//unload any content it has stored
[screen unloadContent];
}
//
// Release all game screens from memory, that have had their content
// unloaded. This will release all screens themselves, as well as remove
// them from the screens arrays.
//
- (void) releaseScreen:(GameScreen *)screen
{
// remove the screen from all screen arrays
[screens removeObject:screen];
[screensToUpdate removeObject:screen];
// deallocate any memory used for the screen
[screen release];
}
//
// Update every screen in the screens stack, keeping track
// of which screens are covered and which are fully active.
// if a screen is fully active and "on top" of the stack, it
// should receive any input.
//
- (void) updateView:(GLView *)view WithTime:(float)deltaTime
{
// Read the touch input
[input update:deltaTime];
// make a copy of hte master screen list, to avoid confusion if
// the process of updating one screens adds or removes others.
[screensToUpdate removeAllObjects];
for(GameScreen *screen in screens)
[screensToUpdate addObject:screen];
bool otherScreenHasFocus = NO;
bool coveredByOtherScreen = NO;
// loop as long as there are screens waiting to be updated
while ([screensToUpdate count] > 0)
{
// pop the topmost screen off the waiting list
GameScreen *screen = [screensToUpdate objectAtIndex:([screensToUpdate count] - 1)];
[screensToUpdate removeObjectAtIndex:[screensToUpdate count] - 1];
// update the screen
[screen update:deltaTime OtherScreenHasFocus:otherScreenHasFocus
CoveredByOtherScreen:coveredByOtherScreen];
if ([screen currentScreenState] == TransitionOn ||
[screen currentScreenState] == Active)
{
// if this is the first active screen we came across,
// give it a chance to handle input.
if (!otherScreenHasFocus)
{
[screen handleInput:input];
otherScreenHasFocus = YES;
}
// if this is an active non-popup, inform any subsequent
// screens that they are covered by it
if (![screen isPopup])
coveredByOtherScreen = YES;
}
}
// do we need to print the debug trace?
if (traceEnabled)
[self traceScreens];
//
// For every screen that had their content unloaded.. release
// the memory used for that screen here. We do this up front
// to ensure that any released screen doesn't get their update
// or draw methods called, when there is nothing to update or draw.
//
for (GameScreen *screen in screens)
{
if (screen.hasBeenUnloaded)
{
[self releaseScreen:screen];
}
}
}
//
// Draw the game screens from "Bottom to Top." This is done
// in order to ensure that any pop'up screens are drawn on top
// of the full screen below it.
//
- (void) drawView:(GLView *)view WithTime:(float)deltaTime
{
// Clear the screen to preset color before drawing
glClear(GL_COLOR_BUFFER_BIT);
// Draw every screen in the screens array
for (GameScreen *screen in screens)
{
//if the screens content has been unloaded, don't draw
if (screen.hasBeenUnloaded)
continue;
[screen draw:deltaTime];
}
}
//
// Helper method designed to draw the screen names currently
// in the game stack in order to see if they are being added
// and removed correctly.
//
- (void) traceScreens
{
// <<TODO: Input code to draw the screen names>>
}
//
// Helper method to draw a translecent black fullscreen sprite, used
// for fading screens in and out, and for darkening the background
// behind pop up screens.
//
- (void) fadeBackBufferToBlack:(double)alpha
{
glColor4f(alpha,alpha,alpha,alpha);
[blankTexture drawInRect:self.viewport];
glColor4f(1, 1, 1, 1);
}
//
// When the screen is touched by the user, the GLView will pass along a message
// to the view controller that the screen has been touched. The view controller
// will take the message, and pass it along to the input manager where the
// necessary information will be stored and filtered to the game screen that
// will handle the user input.
//
// In order for this to work, in your GLView, you need to write the following
// 4 methods:
// - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
// - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
// - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
// - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
//
// Those methods will call the methods below.
//
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
[input touchesBegan:touches withEvent:event InView:touchView WithTimer:timer];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
[input touchesMoved:touches withEvent:event InView:touchView WithTimer:timer];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
[input touchesEnded:touches withEvent:event InView:touchView WithTimer:timer];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event InView:(UIView *)touchView WithTimer:(NSTimer *)timer
{
[input touchesCancelled:touches withEvent:event InView:touchView WithTimer:timer];
}
@end
As you can see, this is a pretty good sized class. What makes it bigger is I have a nasty habit of commenting everything to hell! I always believe it is best to comment heavily, because if you come back a year later and want to adjust your game, comments make it very helpful for remembering what does what.
The comments in the GLViewController (screen manager) class explains what everything does, but if you have any questions feel free to post them here.
So… now we need a game screen or two!! Remember, the following code should never be used to make a game screen directly. What I mean is, use this as a super class and inherit from it with your screens. For example, your TitleScreen should inherit from GameScreen. Make sense?
here is the GameScreen.h file
-
-
-
-
-
-
-
-
-
-
- #import <Foundation/Foundation.h>
-
- #import <OpenGLES/EAGL.h>
- #import <OpenGLES/ES1/gl.h>
- #import <OpenGLES/ES1/glext.h>
-
- #import "InputManager.h"
- #import "Texture2D.h"
-
-
-
-
- enum ScreenState {
- TransitionOn = 0,
- Active,
- TransitionOff,
- Hidden
- };
-
-
-
-
- @class GLViewController;
-
- @interface GameScreen : NSObject
- {
- @private
- GLViewController *controller;
- CGRect viewport;
-
- bool hasBeenUnloaded;
- bool isPopup;
-
- float transitionOnTime;
- float transitionOffTime;
- float transitionPosition;
- float transitionAlpha;
- enum ScreenState currentScreenState;
-
- bool isExiting;
- bool isActive;
- bool otherScreenHasFocus;
- }
-
- @property (nonatomic, retain) GLViewController *controller;
- @property (readwrite) CGRect viewport;
-
- @property (readwrite) bool hasBeenUnloaded;
- @property (readwrite) bool isPopup;
-
- @property (readwrite) float transitionOnTime;
- @property (readwrite) float transitionOffTime;
- @property (readwrite) float transitionPosition;
- @property (readwrite) float transitionAlpha;
-
- @property (readwrite) enum ScreenState currentScreenState;
-
- @property (readwrite) bool isExiting;
- @property (readwrite) bool isActive;
- @property (readwrite) bool otherScreenHasFocus;
-
- - (void) loadContent;
- - (void) unloadContent;
-
- - (void) handleInput:(InputManager *)input;
- - (void) update:(float)deltaTime OtherScreenHasFocus:(bool)otherFocus CoveredByOtherScreen:(bool)coveredByOtherScreen;
- - (bool) updateTransition:(float)deltaTime TransitionTime:(float)transition Direction:(int)direction;
- - (void) draw:(float)deltaTime;
-
- - (void) exitScreen;
-
- @end
//
// A screen is a single layer that has update and draw logic, and which
// can be combined with other layers to build up a complex screen system
// or menu system, or even dialog system.
//
// Developed by XNA Development Studio ( http://creators.xna.com/ )
// Modified for the iPhone Gameing Framework by Craig Giles on 1/1/09.
//
#import <Foundation/Foundation.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
#import "InputManager.h"
#import "Texture2D.h"
//
// Enum to describe the screens transition state
//
enum ScreenState {
TransitionOn = 0,
Active,
TransitionOff,
Hidden
};
//
// Forward Declarations
//
@class GLViewController;
@interface GameScreen : NSObject
{
@private
GLViewController *controller;
CGRect viewport;
bool hasBeenUnloaded;
bool isPopup;
float transitionOnTime;
float transitionOffTime;
float transitionPosition;
float transitionAlpha;
enum ScreenState currentScreenState;
bool isExiting;
bool isActive;
bool otherScreenHasFocus;
}
@property (nonatomic, retain) GLViewController *controller;
@property (readwrite) CGRect viewport;
@property (readwrite) bool hasBeenUnloaded;
@property (readwrite) bool isPopup;
@property (readwrite) float transitionOnTime;
@property (readwrite) float transitionOffTime;
@property (readwrite) float transitionPosition;
@property (readwrite) float transitionAlpha;
@property (readwrite) enum ScreenState currentScreenState;
@property (readwrite) bool isExiting;
@property (readwrite) bool isActive;
@property (readwrite) bool otherScreenHasFocus;
- (void) loadContent;
- (void) unloadContent;
- (void) handleInput:(InputManager *)input;
- (void) update:(float)deltaTime OtherScreenHasFocus:(bool)otherFocus CoveredByOtherScreen:(bool)coveredByOtherScreen;
- (bool) updateTransition:(float)deltaTime TransitionTime:(float)transition Direction:(int)direction;
- (void) draw:(float)deltaTime;
- (void) exitScreen;
@end
and the GameScreen.m file
//
// A screen is a single layer that has update and draw logic, and which
// can be combined with other layers to build up a complex screen system
// or menu system, or even dialog system.
//
// Developed by XNA Development Studio ( http://creators.xna.com/ )
// Modified for the iPhone Gameing Framework by Craig Giles on 1/1/09.
//
#import "GameScreen.h"
@implementation GameScreen
//
// Properties
//
@synthesize controller;
@synthesize viewport;
@synthesize hasBeenUnloaded;
@synthesize isPopup;
@synthesize transitionOnTime;
@synthesize transitionOffTime;
@synthesize transitionPosition;
@synthesize transitionAlpha;
@synthesize currentScreenState;
@synthesize isExiting;
@synthesize otherScreenHasFocus;
@dynamic isActive;
- (bool) isActive
{
return !otherScreenHasFocus &&
(currentScreenState == TransitionOn ||
currentScreenState == Active);
}
//
// Constructor(s) / destructors
//
- (id) init
{
self = [super init];
if (self != nil)
{
//initializations go here
isExiting = NO;
}
return self;
}
- (void) dealloc
{
//Deallocations go here
[super dealloc];
}
//
// Loads all content associated with the current screen
//
- (void) loadContent
{
}
//
// Unloads all content associated with the current screen
//
- (void) unloadContent
{
// Release the screen manager
[controller release];
// inidicate that the screens content has been unloaded
hasBeenUnloaded = YES;
}
//
// Allows the screen to perform its update logic.
//
- (void) handleInput:(InputManager *)input
{
}
//
// Updates the base screen. Since any game screen
// wil be inheriting from this class, the game screen will
// call this update method. This update just helps with the
// transition between two screens, and if a screen is
// transitioning on and off.
//
- (void) update:(float)deltaTime OtherScreenHasFocus:(bool)otherFocus CoveredByOtherScreen:(bool)coveredByOtherScreen
{
otherScreenHasFocus = otherFocus;
if (isExiting)
{
//if the screen is going to die, it should transition off
currentScreenState = TransitionOff;
if (![self updateTransition:deltaTime TransitionTime:transitionOffTime Direction: 1])
{
//when transition finishes, remove the screen
[controller removeScreen:self];
}
}
else if (coveredByOtherScreen)
{
//if the screen is covered by another, it should transition off
if ([self updateTransition:deltaTime TransitionTime:transitionOffTime Direction: 1])
{
//scren is still transitioning
currentScreenState = TransitionOff;
}
else
{
//transition has finished
currentScreenState = Hidden;
}
}
else
{
if ([self updateTransition:deltaTime TransitionTime:transitionOnTime Direction: -1])
{
//still busy transitioning
currentScreenState = TransitionOn;
}
else
{
//transition finished
currentScreenState = Active;
}
}
}
//
// Helper method for updating the screen transition position
// (how much the screen has faded in / out)
//
- (bool) updateTransition:(float)deltaTime TransitionTime:(float)time Direction:(int)direction
{
// how much should we move by?
float transitionDelta;
if (time <= 0)
transitionDelta = 1;
else
transitionDelta = deltaTime / time;
//update the transition position
transitionPosition += transitionDelta * direction;
//did we reach the end of the transition?
if (direction < 0 && transitionPosition <= 0 ||
direction > 0 && transitionPosition >= 1)
{
//clamp transition position to 0, 1, or value;
if (transitionPosition >= 1)
transitionPosition = 1;
else if (transitionPosition <= 0)
transitionPosition = 0;
return NO;
}//end "end of transition"
//otherwise, we are still busy transitioning
return YES;
}
//
// Each screen will have their own draw method. EVERY SCREEN
// should call [super draw:deltaTime] in order to draw
// the fade correctly when the screen manager wishes to fade
// the screen in or out.
//
- (void) draw:(float)deltaTime
{
[self.controller fadeBackBufferToBlack:self.transitionPosition];
}
//
// Tells the screen to go away. Unlike [controller removeScreen] which
// instantly kills the screen, this method respects the transition timings
// and will give the scren a chance to gradually transition off.
//
- (void) exitScreen
{
if (transitionOffTime == 0)
{
//if the screen has zero transition time, kill it
[controller removeScreen:self];
}
else
{
//otherwise flag that it should transition off and exit
isExiting = YES;
}
}
@end
Well that does it for the screen manager and the game screen classes.. But keep in mind.. this will NOT build until the InputManager is built. Why don’t you try to fiddle with that for a while, see what you can come up with? I’ll post Part 2 of this tutorial detailing how I did my input manager and two screens (TitleScreen and PausedScreen) in my next update.
Two thing before I go: I would really like to find a way to turn this into a template for anyone wishing to use it, but I simply do not know how. If you know how to do so, please send me an email at:
CraigGiles9@yahoo.com
Secondly, if you have any questions, comments, sly remarks, please post them. I am very good at reading everyones comments, and getting back to you if needed. You can either post a comment or send me an email and I’ll get back to you.
EDIT:
I just wanted to let everyone know that there have been a few changes to this article since first posting. I just modified the code within the GLViewController in several places. The following changes were made:
- Added [self releaseScreen:screen]; in the dealloc method inside the for loop.
- added const bool LANDSCAPE_MODE = NO; at the top of the view controller, and an if / else statement in the setup view method to help with setting up a landscape view rather than a portrait view. (The first screen manager was written for only portrait view)
- added input.isLandscape = LANDSCAPE_MODE; to the loadContent method.
Again, there are too many people to thank for helping me to get to where I am with my current knowledge. I hope this was informational to a few of you! Happy coding everyone!
Trackback Address ::
http://joyholic.kr/trackback/363
2009/03/17 22:15
Access the Address Book
I got a request on how do I access the address book in the iPhone. So I took around 30 minutes to learn how and here is how we will do it.
First create a new View-Based Application and call it addressBook.

Now the first thing we want to do is setup the 4 IBOutlets and the 1 IBAction for our project. We also need to include the headers for the address book framework. So open up addressBookViewController.h and you want to make it look like the following.
#import <UIKit/UIKit.h>
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>
@interface addressBookViewController : UIViewController {
IBOutlet UIButton *button;
IBOutlet UILabel *firstName;
IBOutlet UILabel *lastName;
IBOutlet UILabel *number;
}
-(IBAction)getContact;
@end
Now that they are added we need to add in the framework files. So you will right click on the addressBook in the Targets option on the left panel and click on Get Info.

At the bottom there is a + and click that and you need to add the following items in AddressBook.framework and AddressBookUI.framework

Now lets layout our view. So double click on addressBookViewController.xib. You want your view to look like the following.

I used the —–’s just so you can see there is a UILabel there. Now we need to setup the connections for the 4 outlets and the one action. You want it to look like the following

So now lets open up addressBookViewController.m and we want to add in the following methods.
-(IBAction)getContact {
// creating the picker
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
// place the delegate of the picker to the controll
picker.peoplePickerDelegate = self;
// showing the picker
[self presentModalViewController:picker animated:YES];
// releasing
[picker release];
}
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker {
// assigning control back to the main controller
[self dismissModalViewControllerAnimated:YES];
}
- (BOOL)peoplePickerNavigationController: (ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person {
// setting the first name
firstName.text = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
// setting the last name
lastName.text = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);
// setting the number
/*
this function will set the first number it finds
if you do not set a number for a contact it will probably
crash
*/
ABMultiValueRef multi = ABRecordCopyValue(person, kABPersonPhoneProperty);
number.text = (NSString*)ABMultiValueCopyValueAtIndex(multi, 0);
// remove the controller
[self dismissModalViewControllerAnimated:YES];
return NO;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{
return NO;
}
Now we can click build and go and see the following



As always you can grab the source here.
Comments
Trackback Address ::
http://joyholic.kr/trackback/361
2009/03/13 13:20
on_lazy_ptr in general
FROM : Nick Zitzmann
DATE : Thu Nov 13 03:13:31 2008
Yesterday, I was building some open source code that depended on a
third-party library, liboil. Liboil is a library that defines most of
its symbols as generic pointers, then provides architecture-specific
implementations of each function, and these implementations are
assigned to the memory addresses of those pointers at initialization
time. I'm guessing they did this so they could support a very broad
number of architectures and CPU features.
The problem is, when linking it against the project that was using it,
I got a linker error like this:
Undefined symbols:
"_some_function", referenced from:
_some_function$non_lazy_ptr in some_source.o
So I searched Google for non_lazy_ptr, and saw lots of other people
who have had this problem compiling various projects out there on Mac
OS X, and no one really knew what was causing this to happen, or how
to fix it.
So what causes these non_lazy_ptr linker errors, and how do I properly
fix them? My interim solution was to use the -U linker option to make
the linker dynamically look up the symbol, but I suspect that wasn't
the correct solution...
Nick Zitzmann
<
http://seiryu.home.comcast.net/>
Trackback Address ::
http://joyholic.kr/trackback/358
URL schemes are great, but one important piece of information that you didn’t mention is that openURL: returns a boolean that can be used to determine whether the device is able to handle the URL.
For example if you do tel: or sms: on an iPod touch it will return NO and you can display an error message.
This becomes critical when you use URL schemes for applications you can download from the AppStore. My app, for example, allows you to add bookmarks to Delicious, but obviously the ‘yummy:’ URL scheme won’t work if it’s not installed!
What about launching some other 3rd party application. Or starting some other process from one process?
@Stephen that is a great point. Thanks for the comment.
@Raj it is possible to invoke a 3rd party application ONLY if said application has taken the necessary steps to register the URL scheme with the phone. I’ll try to dig up an example to illustrate how this is done.
The URL scheme is the text before the “://” in the URL so if you wanted to create a scheme “foo” a URL would look like “foo://….”. You should even be able to pass parameters in the URL. I’ve not tried to do this yet, but as soon as I find out how I’ll post back here.
- Rodney
@Stephen:
Is that correct? It may be true for tel: and sms: URL schemes, but I don’t think it applies to custom URL schemes.
In my testing openUrl: always returns YES, even when called with an unsupported URL scheme. I can’t find a way to prevent the OS from displaying its own “Unsupported URL” alert message, nor a way to query for supported URL schemes.
Darren, yes it does work even for custom URL schemes. The iPhone sometimes gets confused if you install and remove applications with URL schemes:
http://openradar.appspot.com/6045562
Maybe that’s what you’re seeing?
And no, there’s no (documented) way of discovering whether a URL scheme is supported. The way I do it try it and if it fails then disable the option next time. It’s imperfect but as far as I know the best you can do at the moment.
Does anyone know how to launch a custom application from an email or sms?
Cheers
@David Heacock
The process of launching an application is as simple as including a URL in the email or sms message. Follow the steps in this article to register your application to respond to a particular URL and then just put that URL in your message.
NOTE: There is currently no push support so the user will still need to click the URL for it to actually open the application.
@David Heacock
I forgot which article this was … the article you need that explains how to register your own application URL is located here:
http://iphonedevelopertips.com/cocoa/launching-your-own-application-via-a-custom-url-scheme.html
Cheers,
Rodney
Anyway to launch the iPod app to start playing a certain song?
@Dho
To my knowledge this is not possible today.
I’ve seen that Apple’s own iPhone apps can send an email from a special mailer view that comes and goes, within the app– similar to how we are allowed to pick and even add/edit Contacts from within our apps.
Does anyone know if this “SendMail” API has been made available to us in the SDK?
@Scenario: nope, the “SendMail” API is not available unless you’re Apple. The only option is to use the mailto: URL scheme. Or include your own SMTP client.
Also, I found that I now see what @Darren is getting. This certainly worked in iPhone OS 2.0. Looks like something broke.
Thanks guys, now how do you launch iphone’s built-in address book?
Generally code samples talk about creating own interface into the address database (e.g. using AddressBookUI), but say you want your app to just launch iphone’s “Contacts” app? Thx. Gabe.
@Gabe … I am not aware of a way to launch the Address book external to an App. Let us know if you find anything.
Hi,
I have an app in which I need to play a video. Can you tell me if there is a way I can do it without using YouTube? Does QT player support being invoked using URL? Also, once the video is completed, I would like my application to be restored? Is it possible?
Appreciate any pointers on this.
Thanks.
Hi,
I want to open the calendar application from my custom application. What URL i can use for that.?
Hi
i am trying openURL for mailto functionality but no success (in simulator) using 2.2.1. can any body tell where is problem
Also i want to enter date from my app into iphone calender, any body have any idea?
Thanks
@kanayl
The simulator does not come loaded with the email application that is why you can’t use the mailto functionality in the simulator.
As for the calendar, there is not currently a way to do this.
I am trying openurl for call option, Once the call ended it returns back to my application (restarting the application). Can anyone help me , i want to return back to the same place where i clicked to call.
Thanks
Hi Raji, I’m afraid that it can’t be done with the publicly available APIs.
Thanks Stephen.
Hi,
I’m want to open an app if it’s also installed on the device, and notify the user otherwise, but the app hangs on the openurl line of code, so never beeps? Any ideas how I can work around this anyone?
BOOL win = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
if( win == 0 ) { void NSBeep(); };
Rob,
NSBeep isn’t available as part of the iPhone’s API.
Cheers,
–> Stephen