iOS 라이프 사이클이 잘 정리된 사이트

http://d.hatena.ne.jp/glass-_-onion/20120405/1333611664


UIApplication Life Cycle


ViewController Life Cycle


Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

최근에 갑느님이 알아먹기 쉽게 하기위한 목적으로 데모용 프로젝트를 만들어야 했다.

아무리 데모용이지만 어느정도 형태는 갖추어야 하기에..여기저기 이미지를 다른앱에서 긁어모아 

만들기 시작했다.

지금 프로젝트엔 디자이너님이 없는 관계로..


아무튼 가져온 이미지를 문제없이 잘 사용하고 있었는데(적어도 시뮬레이터에는...) 정작 디바이스에 넣어보니 

콘솔에 지저분한 에러로그를 토해내며 XCode가 반항을 하기 시작했다.

「While reading ... pngcrush caught libpng error」


분명 컴파일 에러이면서 앱은 실행되는 그런 이중적 태도를 취하면서 위에 로그대로 해당이미지는 표시하지 않는 짜증나는 현상이었다.

혹시 다른앱에서 퍼온 이미지라서 그러나? 뭔가 락이 걸려있는 이미지인가? 뒤가 구린생각에 오만가지 생각을 다봤지만

그런건 들어본적이 없기에 구글링+스택플로우 에서 찾아보기로 했다.


두시간정도 삽질하니 아래의 두가지정도의 패턴이 발견되었다.


첫번째..

해당파일이 프로젝트 리소스 파일 타겟에서 빠져있는경우.

정말 이경우라면 문제는 간단히 해결.그러나 내가 이런 초보적인 실수를 할리가 없어라고 자신없게 외치며 확인을 해보니 이문제는 아니었음.

참고로 확인방법은 해당파일을 선택한 후 오른쪽 프로파티창에 Target Membership 에서 해당 타겟을 

체크해 되어 있는지 확인하면 됨. 안되 있음 해당 타겟에 체크해면 해결.

 



그리고 두번째..

인터레이스(インタレース)가 적용된 이미지파일일 경우.


인터레이스가 존재자체가 몰랐기에 구글링 해보니 이미지 저장방식의 한종류라고 함.

간단히 예를들어 웹페이지를 열었을때 이미지가 처음에는 뿌옇게 보이다가 다운로드가 진행되면서 

점점 선명해지는 이미지.. 바로 그런이미지로 저장하는 방식이란다.


어쨋든 인터레이스로 되어 있는 이미지는 XCode에서 받아들이지 못하니 변경해주야 한다.

물론 포토샾으로 해주면 깔끔하겠지만 회사에서 준 맥에는 당연하게도 포토샾이 없고 그렇다고 gimp는 사용할 줄 모르고..

더군다나 데모용이었기 때문에 맥 기본 이미지뷰어에서 대충 해결하기로 했다.


해당파일을 이미지뷰어에서 연 후 내보내기에서 알파값속성체크를 제거후 저장한다.




근데 신기한건.. 다른 앱에서 가저온 이미지인데 왜 안된걸까? 

Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

프로젝트를 마치고 납품할때 설계서를 납품하기도 하지만 종종 고객에 따라 Doxyzen형태의 문서를 요구 하는 경우가 있다.

예전 자바프로젝트의 경우 이클립스에서 Doxyzen용으로 자동으로 코멘트를 생성하주는 편리한 기능이 있었는데 (물론 템플릿 자동생성성)이 기능을 XCode에서도 사용할 수 있다.

상훈아 고마워~ 


이 방법을 몰라 이전 프로젝트는 코멘트를 다 손코딩으로 했었는데 무식하면 몸이고생한다.


방법은 간단. 아래의 설명을 따라하길 바란다.


1.일단 아래링크에서 파일을 하나 다운받는다.

http://www.duckrowing.com/2011/05/14/using-the-doxygen-helper-in-xcode-4/

download the service. <-- 여기에서 다운



2.다운받은 파일은 .tar 로 압축되어 있는데 압축을 풀면 workflow라는 확장자의 파일이 나타난다.

이렇게 쇠파이프를 들고 있는 로봇이다.



3. 자 그러면 이 로봇을 더블클릭하여 실행한다.

* 실행하면 동시에 이 로봇이 말도 없이 사라지는데 놀라진 말자. 중요! 나중에 등록시 이놈의 이름(Document Code)이 필요하므로 외워두자. 


4. 시스템 환경설정에서 키보드를 선택하고 왼쪽에 어플리케이션을 선택하 "+" 버튼을 눌러 아래의 그림과 같이 등록한다.

여기서 등록할때 이름을 3번에서 외워두었던 Document Code를 넣어준다.

단축키를 등록하게 되는데 내경우는 cmd+shift+D 로 지정하였다.


5. 여기까지 되었으면 XCode로 돌아가보자.

XCode가 실행중 이었다면 종료후 다시 시작해야 적용이 된다.


메소드를 선택한 후 아까 지정했던 단축키를 누르면 아래와 같이 Doxyzen용 템플릿이 나타난다.







Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

iPhone앱안에 있는 /document  저장공간내 파일을 제어할때 필요한 메소드를이다. 내용이야 간단하지만 만들려고 하면 여간 귀찮은게 아니라서 만들어 놓고 쓸 생각이다. 급조한거라 좀 부실하지만 다듬어가면서 업데이트해야지.


이번 프로젝트의 경우 특이하게 파일관련 기능을 자주 썻지만(드롭박스 같은 클라우드 API를 포함해서) 다음 프로젝트에선 어떨지 모르겠다.



1. 파일복사.

- (BOOL)copyFile:(NSString *)srcPath destination:(NSString *)destPath error:(NSError **)error {

    

    NSFileManager *fileManager = [NSFileManager defaultManager];

    BOOL isDirectory;

BOOL result = NO;

    

    if([self isExistFile:srcPath isDirectory:&isDirectory] == YES) {

        

        if (isDirectory) {

            NSString *preFolderPath = [destPath stringByDeletingLastPathComponent];

            

            [fileManager createDirectoryAtPath: preFolderPath

                   withIntermediateDirectories: YES

                                    attributes: nil

                                         error: error];

            result = [fileManager copyItemAtPath:srcPath toPath:destPath error:error];

            

            return result;

            

        } else {

            result = [fileManager copyItemAtPath:srcPath toPath:destPath error:error];

            

            return result;

        }

        

    }else {

        *error = [NSError errorWithErrorCode:ErrorCodeFileNotFoundError];

        

        return NO;

    }

    

}


2. 파일삭제

- (BOOL)removeFile:(NSString *)filePath error:(NSError **)error {

    

    NSFileManager *fileManager = [NSFileManager defaultManager];

BOOL isDirectory;

    BOOL result = NO;

    

    if([self isExistFile:filePath isDirectory:&isDirectory] == YES) {

        

        if (isDirectory) {

            NSArray *contents = [fileManager contentsOfDirectoryAtPath:filePath error:error];

            for(int i=0;i<[contents count];i++) {

                NSString *childFileName = [contents objectAtIndex:i];

                NSString *nextFilePath =[[filePath stringByAppendingString:@"/"] stringByAppendingString:childFileName];

                

                result = [self removeFile:nextFilePath error:error];

            }

            

            result = [fileManager removeItemAtPath:filePath error:error];

            

            return result;

            

        } else {

            result = [fileManager removeItemAtPath: filePath error:error];

            

            return result;

        }

        

    } else {

        *error = [NSError errorWithErrorCode:ErrorCodeFileNotFoundError];

        

        return NO;

        

    }

}


3. 이름변경하기

- (BOOL)renameFile:(NSString *)filePath newfilename:(NSString *)newFilePath error:(NSError **)error {

    

    NSFileManager *fileManager = [NSFileManager defaultManager];

    BOOL isDirectory;

    BOOL result = NO;

    

    if([self isExistFile:filePath isDirectory:&isDirectory] == YES) {

        

        if (isDirectory) {

            NSString *preFolderPath = [newFilePath stringByDeletingLastPathComponent] ;

            [fileManager createDirectoryAtPath: preFolderPath

                   withIntermediateDirectories: YES

                                    attributes: nil

                                         error: error];

            

            result = [fileManager moveItemAtPath:filePath toPath:newFilePath error:error];

            

            return result;

            

        }else {

            NSString *preFolderPath = [newFilePath stringByDeletingLastPathComponent] ;

            

            [fileManager createDirectoryAtPath: preFolderPath

                   withIntermediateDirectories: YES

                                    attributes: nil

                                         error: error];

            

            result = [fileManager moveItemAtPath:filePath toPath:newFilePath error:error];

            return result;

        }

        

    } else {

        *error = [NSError errorWithErrorCode:ErrorCodeFileNotFoundError];

        return NO;

    }

    

}


4. 파일이동하기.

- (BOOL)moveFile:(NSString *)srcPath destination:(NSString *)destPath error:(NSError **)error {

    

    NSFileManager *fileManager = [NSFileManager defaultManager];

BOOL isDirectory;

    BOOL result = NO;

    

    if([self isExistFile:srcPath isDirectory:&isDirectory] == YES) {

        

        if (isDirectory) {

            NSString *preFolderPath = [destPath stringByDeletingLastPathComponent] ;

            [fileManager createDirectoryAtPath: preFolderPath

                   withIntermediateDirectories: YES

                                    attributes: nil

                                         error: error];

            

            result = [fileManager moveItemAtPath:srcPath toPath:destPath error:error];

            

            return result;

            

        }else {

            NSString *preFolderPath = [destPath stringByDeletingLastPathComponent] ;

            

            [fileManager createDirectoryAtPath: preFolderPath

                   withIntermediateDirectories: YES

                                    attributes: nil

                                         error: error];

            

            result = [fileManager moveItemAtPath:srcPath toPath:destPath error:error];

            return result;

        }

        

    } else {

        *error = [NSError errorWithErrorCode:ErrorCodeFileNotFoundError];

        return NO;

    }

}



5. 파일정보보기

- (NSDictionary *)showPropertyFile:(NSString *)filePath {

    

    NSError *error = nil;

    NSDictionary *attr = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error];

    

    if (error == nil) {

        return attr;

    }

    

    return nil;

    

}


6. 새폴더 만들기.

- (BOOL)createFolder:(NSString *)currentDirectory folderName:(NSString *)foldername error:(NSError **)error {

    

    NSFileManager *filemanager = [NSFileManager defaultManager];

    

    NSString *newFolderPath = [currentDirectory stringByAppendingFormat:@"/%@",foldername];

    BOOL isDirectory;

    

    if([self isExistFile:newFolderPath isDirectory:&isDirectory] == YES) {

        

        if (isDirectory) {

            return NO;

        }else {

            BOOL result = [filemanager createDirectoryAtPath: newFolderPath

                                 withIntermediateDirectories: YES

                                                  attributes: nil

                                                       error:error];

            

            return result;

        }

        

    }else {

        BOOL result = [filemanager createDirectoryAtPath: newFolderPath

                          withIntermediateDirectories: YES

                                           attributes: nil

                                                error:error];

        

        return result;

    }

}




Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

며칠전 운영체제인 iOS7과 iPhone5s와 iPhone5c라는 두가지 디바이스 버전이 발표되었다. 신제품이 출시되면 소비자들은 즐겁겠지만 개발자는 마냥 즐겁지는 않다. 만들어 놓은 앱이나 지금 진행중인 플젝에 반영해야 하기 때문이다.(일이 늘어난다는 얘기임.)

마치 군복무중에 눈이 내리는 장면을 상상하면 딱 맞을듯 싶다.


내 경우는 스마트폰 개발 특성상 안드로이드 개발자들과 일을 같이 하는데 ( 뭐 안드개발자들 바쁘면 도와주기도 한다) 이 디바이스별 대응이라는게 참 손이 많이가는 작업이다. 테스트를 다 할수 없는 거고 안된다고 크레임들어오고.. 대책이 없는거다.


그나마 다행이랄까 애플에서 개발자를 배려해 XCode5의 새로운 기능이 추가되었다.

디바이스별 이미지를 관리하는 어셋기능(Asset)이다.


테스트 해보니 기존소스와도 호환성이 있어 예전방식으로 코딩해도 기본적으로는 인식하는듯 하다.

어쨋든 서론이 길어졌지만 직접 해보지 않으면 답답하니 샘플을 만들어 보자.


우선 샘플 프로젝트를 만들고 UIImageView를 배치 IBOutlet로 선언후 연결해 놓는다.




그리고 이미지명을 "animal" 로 지정해서 불러들인다.

그리고 XCode5에 새로생긴 Images.xcassets 폴더를 선택한 후 오른쪽 마우스를 클릭하여 Image Set 을 추가한다.

참고로 폴더를 만들수도 있고 이외 여러가지 메뉴가 있다.




기본으로 Image라는 이름으로 추가되므로 이 이름을 "animal"로 변경해준다.




위의 작업을 해주면 프로젝트내에 폴더가 생성되는데 이곳에다가 사용할 이미지를 복사한다.



펭귄, 코알라, 고양이들을 복사해주자.



복사함과 동시에 XCode상에 추가된 이미지를이 보이기 시작한다. 

오른쪽 프로파티에 속성을 그림과 같이 변경해준다.



각각 동물들을 필요한 곳에 드롭다운 해준다. 




이제 시뮬레이터 버전을 변경해 가면서 표시되는 이미지를 확인해보자. 역시 예상대로 잘 표시된다.



Asset기능과 AutoLayout기능을 적절히 사용하면 디바이스 화면사이즈에 대응하는것이 그리 귀찮은 일은 아닐것 같다.

예전방식에 익숙해서 AutoLayout기능은 쓰질 않았었는데 나중에 한번 더 연구해 볼생각이다.



Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

어느 소스폴더에서 "git init"를 한 폴더 전체가 소스관리 대상에 포함된다.

(git init 는 git로 현재폴더를 소스관리 하겠다는 명령어)


각각의 의미는 아래와 같다.

# 로 시작하는건 코멘트

_

# 하위디렉토리를 포함한 hoge.dcu 등의 파일을 무시

*.dcu


# 최상위디렉토리의 *.exe 파일만 무시

# 하위디렉토리는 무시하지 않는다.

/*.exe


# tmp 디렉토리 전체를 무시하는 경우.

tmp/


# cache 디렉토리를의 안에파일을 전부 무시.

# 그리고 .htaccess 는 제외(무시대상에 제외)

cache/*.*

!.htaccess


# *.o 전부 무시.

# zlib/ 이하의 *.o는 제외(무시대상에서 제외)

*.o

!zlib/*.o




어느 오픈소스에 있는 .gitignore를 열어보았더니 이렇게 설정되어 있었다.

나중에 만들때 참고해 만들면 될듯하다.


# Xcode

build/*

*.pbxuser

!default.pbxuser

*.mode1v3

!default.mode1v3

*.mode2v3

!default.mode2v3

*.perspectivev3

!default.perspectivev3

*.xcworkspace

!default.xcworkspace

xcuserdata

profile

*.moved-aside


#Mac OS

.DS_Store

Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요


이왕 AdHoc배포를 한다면 아이폰 스타일로 다운로드 페이지를 만들어 보자.



아래는 html소스이다.

HTML은 지식이 없어 여기저기 소스를 갇다붙였더니 지저분하다. 뭐 잘 보이기만 하면 되지머~ 

<!DOCTYPE html>

<html>

<head>

  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> 

  <title>Test Applicationダウンロードページ</title>

  <style type="text/css">

    body {

      background: url(bkg.png) repeat #c5ccd4;

      font-family: Helvetica, arial, sans-serif;

    }

    .congrats {

      font-size: 16pt;

      padding: 6px;

      text-align: center;

    }

    .desc {

      font-size: 10pt;

      padding: 6px;

      text-align: left;

    }

    .step {

      background: white;

      border: 1px #ccc solid;

      border-radius: 14px;

      padding: 4px 10px;

      margin: 10px 0;

    }

    .instructions {

      font-size: 12pt;

    }

    .arrow {

      font-size: 15pt;

    }

    .icon_image {

      border: 1px #ccc solid;

      border-radius: 10px;

    }

    table {

      width: 100%;

    }

  </style>

</head>

<body>


<div class="congrats">Test Application</div>

<div class="step">

  <table><tr>

    <td class="instructions"><b>Test Application<b><br /><font size="2px" color="#ccc">ver.0.9.0<br />2013/08/15</font></td>

    <td width="24" class="arrow">&rarr;</td>

    <td width="57" class="imagelink">

      <a href="itms-services://?action=download-manifest&url=http://devkjcode.com/app/TestApplication.plist">

        <img class="icon_image" src="testApplication-icon.png" height="57" width="57" />

      </a>

    </td>

  </tr></table>

</div>

<div class="desc"> 

<p>初めての方は下記のリンクをタップしてProvisioningをダウンロードしてください。<br />

<a href="http://devkjcode.com/app/TestApplication.provisioning">Provisioningをダウンロード</a></p>

</div>

</body>

</html>


배경용 이미지는 아래 이미지를 사용하면 된다.





Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

만들어진 앱을 내부테스트를 위해 AdHoc으로 배포해야할 경우가 생긴다.

만약 자신이 만든앱이 정적라이브러리를 사용하거나 복수의 프로젝트파일을 가지고 있는 앱이라면 Distribute할 때에 아래와 같은 에러가 발생하는 경우가 있다.

「does not contain a single–bundle application or contains multiple products」


해결방법은 해당 정적라이브러리와 프로젝트파일의 설정을 바꾸어주면된다.

Skip Install 을 YES로 변경.




물론 본인의 프로젝트는 Skip Install 을 NO  로 해야한다.



Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

개발중인 앱이 런타임중에 먹통이 되는 현상이 발생하여 디바이스 로그를 까봤더니 <Error>: Max open files: 78 라는 놈이 다량으로 출력되어 있었다.


앱이 먹통이 되는 문제가 이 에러랑 직접적인 관련은 없을거라 생각하면서도 저 찝찝한 에러로그 때문에 원인을 찾아보기로 했다.

가볍게 시작한 일이 하루종일 삽질이되고...

 모든문제를 해결해주는 전지전능한 스택플로우 마저도 명확한 답이 없었다. 있다 싶으면 케이스별로 다 답변도 달랐다.


찾아보면 찾아볼수록 심오한 Objective-C의 세계로 빠져들어 포기하려던 찰나 우연치 않게 해결할 수 있었다.

문제는 뚱딴지 같이 Provisioning설정..

빌드셋팅에서 프로비져닝을 정성것 다시 설정해주니 그 지저분한 에러가 싹 없어졌다.


하루종일 삽질해서 해결됬으니 다행이지만.. 아직도 먹통이되는 문제는 미해결.



Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요

iOS부터 가능해진 블럭코드 ^{}  (대충 이런형식의 처리로직?을 파라메터로 넘기는 방법) 에서 "ARC Retain Cycle Error " 라는 경고가 발생하는 경우가 있다.


Capturing 'self' strongly in this block is likely to lead to a retain cycle


ARC로 된 프로젝트에서 블럭코딩을 할 경우 블럭 밖에 선언된 변수가 블럭안에서 값이 변할때 위와같은 에러가 발생한다고 한다.

내자신도 블럭코드는 아직 지식이없어 자신있게 말할순 없지만...


어쨋든 해결방법은 문제의 변수를 __block 로 선언하면 경고가 사라진다.


만약 이런소스가 있다고 가정하면,

@implementation Hoge
-(void)hogeMethod{
  hogeHandler = ^(Fuga *fuga){
    [self someMethod:fuga];
  };
}
@end


이런식으로 변경.

@implementation Hoge
-(void)hogeMethod{
  // 여기서self를 카피
  __block Hoge *blockself = self;
  hogeHandler = ^(Fuga *fuga){
    [blockself someMethod:fuga];
  };
}
@end

Posted by 악당잰 트랙백 0 : 댓글 0

댓글을 달아 주세요