달력

9

« 2014/9 »

  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  •  
  •  
  •  
  •  

지난 토요일 아침에 침대에 누워서 밍기적 대다가 iOS8에서 사라진 camera roll을 처리했다는 글을 보게 되었다..


https://medium.com/a-startup-hustlers-guide/%EC%9A%B0%EB%A6%AC%EB%A5%BC-%EB%8B%B9%ED%99%A9%EC%8B%9C%ED%82%A8-ios-8-%EC%82%AC%EC%A7%84-914d441deeba


바로 일어나서 PhotoKit을 보기 시작했다가 그냥 별 성과 없이 주말을 보내고 어제 다시 보기 시작했는데 오늘에서야 결국 해냈다.. ㄷㄷㄷ


저 링크에 있는 글을 읽은 후라 그런지 저 글에 나온대로 전체 사진 리스트를 얻어와서 겹치는 사진들을 제외하는 방법으로 접근을 했던게 시간을 잡아먹게 됐고 오늘 아침에 다른 분과 잠깐 이에 대해 얘기를 하다가 아이디어가 생각이 나서 그대로 했더니 해결이 되었다..


서론이 길었고.. 소스 나간다.. ㅎㅎ



                    

        PHFetchOptions *options = [[PHFetchOptions alloc] init];
        options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"startDate" ascending:NO]];
        NSMutableArray *aAll = [[NSMutableArray alloc] init];

        __block BOOL bBusy = YES;

        PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeMoment subtype:PHAssetCollectionSubtypeAlbumRegular options:options];
        [smartAlbums enumerateObjectsUsingBlock:^(PHAssetCollection* collection, NSUInteger idx, BOOL *stop) {
            
            PHFetchOptions *options = [[PHFetchOptions alloc] init];
            options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
            PHFetchResult* assets2 = [PHAsset fetchAssetsInAssetCollection:collection options:options];
            [assets2 enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
                
                [aAll addObject:obj];
                
            }];
            
            bBusy = !stop;

        }];

        while (bBusy)
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

        NSLog(@"aAll count : %d", (int)aAll.count);
        assetGridViewController.assetsFetchResults = aAll;


사진 앱에서 첫번째 탭인 사진을 보면 날짜나 장소 등의 기준으로 사진이 분류가 된다. 이게 PhotoKit에서 얘기하는 컬렉션 타입 중에 PHAssetCollectionType 이다. 이 타입으로 컬렉션을 가지고 오면 사진 탭에 있는 리스트를 가지고 올 수 있게 되고 각각의 컬렉션에 포함되어 있는 사진들을 다시 읽어오면 전체 사진 리스트를 겹치지 않게 가지고 올 수 있게 된다.


위 소스는 애플에서 제공하고 있는 컴파일도 제대로 안되는 PhotoKit 샘플에 적용을 하느라 저런 모양이 됐고 컬렉션 목록을 가지고 오는 enumerateObjectsUsingBlock이 끝날때 화면을 갱신시켜준다거나 원하는 다른 작업을 하면 된다.


어제 사진들 리스트를 얻어오기 위해 PhotosTypes.h에 정의되어있는 데이터 타입들을 천천히 살펴보고 왠만한건 테스트도 해보고 그랬는데, 기존 ALAsset보다 PhotoKit에 새로 추가된 기능들이 많이 있어서 이쪽은 좀더 프로토타이핑을 해볼 필요가 있을 것 같기는 하다. 


PhotoKit의 구조나 용어들에 대한 설명은 딱히 하지 않았는데 그건 셀프임.. ㅋㅋ

암턴 Cameral Roll이 사라진 것에 대한 문제는 해결을 했으니 CameraW 다음 버전에도 적용을 하고 오픈소스 올렸던것에도 적용을 해야겠다.. 훗..

굿보이


끗~


참.. PhotoKit에 대한 예제는 애플 샘플에 잘 나와있는데 이 샘플이 다운을 받아서 컴파일을 하면 컴파일 에러가 남.. -_-;; info.plist 파일을 못읽는다고 에러가 나는데 프로젝트안에 SamplePhotosAppTests 요 폴더를 만들고 그 안에 info.plist를 카피해주고 프로젝트에 있던 파일 지우고 요걸 다시 넣어주면 컴파일이 잘 됨.. 애플 PhotoKit 담당자야.. 우리 잘좀 하자.. 응?


PS : iOS 8.0.2에서 이 문제가 패치되어서 더이상 이 소스를 쓸 일은 없을 듯.. 다행(?)이다.. ㅎㅎ


Posted by 도노보노

올해 WWDC를 보면서 가장 눈에 꽂혔던 내용 중에 하나가 바로 Extension 기능이었드랬다.. 그래서 공부를 해야지 해야지 하다가 iOS8 GM을 설치하고서야 부랴부랴 보기 시작했는데 인터페이스가 정말 간단하게 만들어져 있어서 의외로 쉽게 프로토타이핑을 해보았다.. 


Extension을 사용하기 위해서는 먼저 프로젝트에 새로운 타겟을 하나 추가를 해야한다.



위 화면처럼 Extension은 총 6가지를 지원한다.. 각각의 Extension은 다음과 같은 역할을 수행한다..




해석은 생략함.. ㄷㄷㄷ

Extension에 대한 자세한 사항은 이곳에서 셀프로 공부하시길..

https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/ExtensibilityPG/index.html


암턴.. 난 이중에 가장 관심이 있는게 Photo edit extension이다.. 우선 이넘이 동작하는 과정을 보면..



 


우선 기본 사진 앱에서 사진을 선택하고 네비바의 편집 버튼을 누르면 오른쪽 화면처럼 편집 화면으로 넘어간다.




편집 화면도 기능들이 꽤 많이 추가가 됐는데 화면 왼쪽 위에 쩜쩜쩜 버튼을 누르면 액션시트가 뜨면서 Photo edit extension 기능을 포함하고 있는 앱 리스트가 표시된다. 만일 여기에 없으면 기타 버튼을 눌서서 원하는 앱을 활성화할 수 있다. 물론 비활성화도 가능.

앱을 선택하면 그에 해당하는 extension이 실행되게 된다. 하나 아쉬운건 화면 상단에 취소, 완료 버튼이 포함된 툴바가 하나 뜨는데 이건 어떻게 없애는지 아직 모르겠다. UI의 일관성을 유지하기 위해 무조건 노출이 되어야 하는건가 싶기도 하고..


암턴.. 동작하는 과정은 이러하다..


코드를 잠깐 보면.. Photo edit extension 타겟을 프로젝트에 추가를 하면 몇가지 파일들이 자동으로 생성이 된다.



타겟 이름을 DoPhlogExt라고 만들었더니 이런 이름들로 생성이 됐다.. Supporting Files의 DoPhlogExt.pch는 기본으로 생성되는 파일은 아니고 프로젝트에서 기본적으로 사용하는 pch 파일 대신에 extension에서 딱 쓰는 애들만 import하기 위해 따로 하나 만들어주었다..




이렇게 만든 pch 파일은 프로젝트 셋팅에서 DoPhlogExt를 선택하고 Prefix Header에 적어주면 끝..


다음으로는 기본으로 생성된 소스를 잠시 살펴보면 extension이 실행될때 해당 이미지의 정보가 넘어오는 부분이 있고.. 화면에서 완료 버튼을 눌러 extension을 종료할때 extension을 호출했던 앱으로 그 정보를 돌려주는 부분 크게 두가지로 구성이 된다.



                    

- (void)startContentEditingWithInput:(PHContentEditingInput *)contentEditingInput placeholderImage:(UIImage *)placeholderImage
{
    self.input = contentEditingInput;

    if (self.input.mediaType == PHAssetMediaTypeImage)
    {
        UIImage *iOriginal = [UIImage imageWithContentsOfFile:self.input.fullSizeImageURL.path];
        NSLog(@"original image size : %@", NSStringFromCGSize(iOriginal.size));
    }
}


요게 시작 코드고.. 종료 코드는 



- (void)finishContentEditingWithCompletionHandler:(void (^)(PHContentEditingOutput *))completionHandler { // Update UI to reflect that editing has finished and output is being rendered. // Render and provide output on a background queue. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Create editing output from the editing input. PHContentEditingOutput *output = [[PHContentEditingOutput alloc] initWithContentEditingInput:self.input]; // Provide new adjustments and render output to given location. // output.adjustmentData = <#new adjustment data#>; // NSData *renderedJPEGData = <#output JPEG#>; // [renderedJPEGData writeToURL:output.renderedContentURL atomically:YES]; // Call completion handler to commit edit to Photos. completionHandler(output); // Clean up temporary files, etc. }); }


요렇게 된다..


시작코드에 인자로 넘어오는 contentEdtingInput 여기에 해당 사진의 정보가 포함이 되어있다. placeholderImage는 스크린 사이즈 정도로 넘어오는 이미지이고 실제 전체 이미지의 URL은 self.input.fullSizeImageURL에 들어있다. 종료코드는 아직 적용을 안했는데 뭐 딱히 어려운건 없어보인다. 커멘트에 나와있는대로 시키는대로 필터 먹인 이미지만 제대로 넣어주면 될 듯 싶다..


Photo edit extension의 인터페이스는 요게 전부다.. 여기서 한가지 주의해야 할 점이 있는데.. 보통 이미지 편집을 하기 위해서는 원래 앱의 코드를 재사용해야 할 경우가 대부분이다.. PhotoEditingViewController에 모든 기능을 새로 구현을 해줘도 무방하지만 이건 정신나간 짓이고 최대한 기존 코드를 재사용하거나 그게 힘들면 상속을 받아서 extension용 클래스를 만들어 쓰던가 해야 시간을 아낄 수 있는데 그런 경우에 프로젝트 셋팅의 Build phases에 재사용하려는 파일들을 추가해주어야한다.

Extension과 본체 앱은 겉에서 보기에는 하나의 바이너리처럼 보이기는 하지만 실제로는 본체 앱의 타겟과 extension 타겟 두개가 하나로 묶여있는 형태다보니 서로 독립되어 바이너리가 존재하게 된다. 그래서 지가 쓸 소스는 지가 포함하고 있어야 한다. 마찬가지로 이미지같은 리소스도 각자의 타겟에 추가를 해주어야 한다. 파일 자체를 새로 넣어야 하는건 아니고 번들에 포함되어 있는 파일들만 추가해주면 된다.




GPUImage가 소스가 겁나 많다보니 Compile Sources에 추가해준 소스 파일이 무척 많다. 타겟을 추가한 직후에는 PhotoEditingViewController 요거 꼴랑 한개 들어있는데 나머지 191개는 본체 앱에서 사용하는 소스를 그대로 추가를 해주었다. 리소스도 서로 공용하는 이미지들을 제대로 분류를 해놓아야 extension쪽에 추가해주기가 편할 듯 싶다. 그런거 생각 안하고 폴더 하나에 다 쑤셔 넣어놨더니 추가해준 이미지가 좀 많아졌는데 나중에 정리를 좀 해야할 듯;;


다른 extension들도 WWDC에서 봤던 대로라면 인터페이스가 무척이나 깔끔하게 되어있어서 구현하기는 그리 어렵지 않아보인다. 대부분 파일을 넘겨 받고 넘겨 주는 일들이 핵심이다보니 그것에 대한 약간의 차이만 보면 될듯..


Extension에서 주의할 점들이 몇가지 있는데.. 앱이 아니다 보니 [UIApplication sharedApplication] 요런걸 사용 못한다거나 [NSUserDefaults standardUserDefaults] 요걸 공유할 수 없어서 따로 별도의 plist 파일을 만들어 쓰던가 해야 하는 일들이 있는데 자세한건 역시 아까 위에서 적었던 URL에서 셀프로 공부하시고 댓글 달아주시길.. ㄷㄷㄷ


참.. 하나의 앱에 여러 extension을 넣을 수도 있다.. 곧 Share extension도 하나 추가를 해볼까 한다..


아.. 또 하나.. Extension에서 사용하는 화면은 아이폰 6 화면 사이즈에 대응되기 때문에 기존 아이폰5 기준으로 만들었던 화면이 다 깨진다.. 크하하하하하.. 뭐 어차피 아이폰 6과 6+를 제대로 대응하기 위해서는 전체적으로 UI를 만져줘야 할 필요는 있겠지만 갑자기 일이 많이 늘어난것 같다는 불만은 어쩔 수 없다.. 걍 320에 @3x로 해줬으면 좀 좋아.. 젠장.. -_-


끗~


Posted by 도노보노

iOS의 버전이 올라갈때마다 이런 저런 문제들이 생기기 마련인데 이번 iOS8에서는 UIImagePickerController(이하 이미지 피커)에서 약간은 심각한(?) 문제가 발견이 되었다.. Xcode 6에서 컴파일을 하면 괜찮기는 하지만 덩치 큰 프로젝트에 Xcode 6를 쉽게 적용하기는 쉽지않고 크고 작은 이슈들이 많이 야기될 수 있기 때문에 이건 시간을 가지고 천천히 수정을 해야 할 문제기 때문에 당분간은, 특히 업데이트를 목전에 두고 있는 마플 같은 경우 이미지 피커 문제가 좀 크다.. 그렇다고 그냥 묻어둘 수도 없고..


우선 발생하는 문제를 보자면 크게 두가지이다..



하나는 위 화면처럼 이미지 피커가 모달로 뜰 때 배경이 투명하게 보이는 문제.. 모달 창이 다 뜨고 나면 그제서야 내용물이 표시된다..

뭐 이건 크리티컬한 문제는 아닌데.. 요 다음 문제는 크리티컬하다..




종종 이미지 피커 객체를 한번 만들고 다시 피커를 띄우게 되면 좀전에 만들었던 이미지 피커를 재사용하도록 코딩을 하곤 한다..

한번 객체를 만들었던걸 다시 사용하는게 속도면에서 약간 유리할 수도 있기 때문인데, 바로 이때 위 화면과 같은 맹한 상태가 되어버린다.. 화면에 아무것도 표시가 안되고 심지어는 네비바에 취소 버튼조차 표시가 안되어서 창을 닫을 수도 없는 사태가 벌어진다..

이걸 해결하기 위해서는 이미지 피커 객체를 재사용하지 말고 피커를 띄울 때 마다 새로 생성해서 띄우면 된다.. 물론 첫 화면처럼 배경이 뚫려 보이기는 하지만 일단 Xcode 5.x 버전에서는 이것 말고는 이미지를 선택할 때, UIImagePickerController가 아닌 그냥 하나 통으로 만들어서 쓰는 방법 요렇게 두가지밖에 없어 보인다..


https://github.com/donobono/DoImagePickerController

이참에 틀에 박힌 UIImagePickerController말고 요런 훌륭한 오픈소스를 사용해보는 것도 좋을 것 같다..


매번 iOS가 업그레이드될 때마다 조용히 넘어가는 경우가 없네..

애플아.. 잘좀 하자.. 응?


Posted by 도노보노