본문 바로가기
아이폰 개발/ios 개념&튜토리얼

iOS Photos Framework로 아이폰 사진앱 만들기

by 인생여희 2020. 12. 15.

iOS Photos Framework로 사진앱 만들기

 

지난포스팅에서 iOS Photos Framework 개념에 대해서 정리를 해보는 시간을 가졌다. 이번포스팅에서는 iOS Photos Framework 개념을 가지고 간단한 사진앱을 만들어 보도록 하자. 먼저 기본 테이블 뷰를 셋팅했다는 가정하에 진행하도록 하겠다. ios 테이블 뷰 내용과 샘플 코드는 이곳에서 다운로드 할 수 있다.

 

 

화면구성

아래 사진을 보면 중간에 tableview가 보인다. tableview 셀안에 imageView와 label을 넣어주었다. photoframework를 이용해서 사진을 뿌려 줄 예정이다. 그리고 셀을 클릭하면 우측에 DetailViewController 가 열리고 이미지가 크게 보이도록 구현해보자.

 

Custom table view cell

먼저 사진과 라벨을 넣은 셀을 커스터마이징 하기 위해서 UITableViewCell 을 상속 받는 CustomCellTableViewCell 클래스를 만들어 주고, 위에서 만든 image 객체와 label 객체를 화면과 이어준다. 그리고 cell의 custom class 이름도 'CustomCellTableViewCell' 이라고 작성해 준다.

 

CustomCellTableViewCell.h

 

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface CustomCellTableViewCell : UITableViewCell

@property (strong, nonatomic) IBOutlet UIImageView *imageView;

@property (strong, nonatomic) IBOutlet UILabel *label;

@end

NS_ASSUME_NONNULL_END


 

CustomCellTableViewCell.m

 

#import "CustomCellTableViewCell.h"

@implementation CustomCellTableViewCell

- (void)awakeFromNib {
    [super awakeFromNib];
    // Initialization code
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];

    // Configure the view for the selected state
}
@end

 

사진 상세화면 작성

TableView Cell 구현은 끝이 났다. 이제 TableView Cell을 눌렀을 때 나타날 DetailViewController를 구현한다. DetailViewController에는 중간에 표시해줄 제목과 이미지를 담아줄 변수가 있다. 또 TableView에서 string 값과 PHAsset 값을 담아 줄 예정이기 때문에 이와 관련된 변수도 만들어 준다.

 

DetailViewController.h

 

@import Photos;
#import <UIKit/UIKit.h>
 
NS_ASSUME_NONNULL_BEGIN

@interface DetailViewController : UIViewController

//IBOutlet 중간 타이틀
@property (strong, nonatomic) IBOutlet UILabel *centerLabel;

//테이블 뷰에서 데이터를 전달 받게될 변수
@property(strong,nonatomic) NSString *data;


//IBOutlet 이미지 객체
@property (strong, nonatomic) IBOutlet UIImageView *imageView;

//테이블 뷰에서 데이터 전달 받을 이미지타입 변수
@property(strong,nonatomic) UIImage *image;


//사진 하나하나
@property (strong) PHAsset *asset;

@end

NS_ASSUME_NONNULL_END

 

m 파일은 테이블 뷰에서 넣어준 PHAsset 데이터를 가지고 PHImageManager 클래스의 requestImageForAsset 메소드를 이용해서 사진을 가져오는 로직이 담겨있다. 자세한 원리는 이전 포스팅에서 설명해놓았다. 참고로 아래 imageView.image = image 라는 부분을 주석 처리 해놓았다. tableView의 리스트 cell에 있는 이미지를 전달해 주었더니 화질이 엄청 떨어지는 썸네일이 출력되었다. 당연히 tableView 에 출력되는 이미지는 손톱만하고, 아래 DetailViewController에 뿌려주는 이미지는 크니깐 이미지가 화질이 떨어 질 수 밖에 없다.

 

DetailViewController.m

 

#import "DetailViewController.h"

@interface DetailViewController ()

@end

@implementation DetailViewController

@synthesize centerLabel , data , image , imageView;

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSLog(@"viewdidload");
    NSLog(@"테이블 뷰에서 넘어어온 data : %@" , data);
    NSLog(@"라벨 타이틀 : %@" , centerLabel.text);
    
    centerLabel.text = data;
    //imageView.image = image;

     
    CGFloat scale = [UIScreen mainScreen].scale;
     
     //3
     NSLog(@"scale : %f" , scale);
     
     //375
     NSLog(@"CGRectGetWidth(self.imageView.bounds) : %f" , CGRectGetWidth(self.imageView.bounds));
     
     
     //678
     NSLog(@"CGRectGetHeight(self.imageView.bounds) : %f" , CGRectGetHeight(self.imageView.bounds));
    
     
     //1125.000000
     NSLog(@"CGRectGetWidth(self.imageView.bounds) * scale: %f" , CGRectGetWidth(self.imageView.bounds) * scale);
     
     //2034.000000
     NSLog(@"CGRectGetHeight(self.imageView.bounds) * scale: %f" , CGRectGetHeight(self.imageView.bounds) * scale);
     
     
     CGSize targetSize =  CGSizeMake(CGRectGetWidth(self.imageView.bounds) * scale, CGRectGetHeight(self.imageView.bounds) * scale);

     //이미지 셋팅
     [[PHImageManager defaultManager] requestImageForAsset:self.asset targetSize:targetSize contentMode:PHImageContentModeAspectFit options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
         if (result) {
             self.imageView.image = result;
         }
     }];
}

@end

 

TableView 코드 작성

마지막으로 TableView 소스를 보자. 사진첩에서 이미지를 TableView cell에 뿌려주기 위해서 PHCachingImageManager 객체와 PHFetchResult를 변수로 선언해놓았다.

 

ViewController.h

 

#import <UIKit/UIKit.h>
#import "DetailViewController.h"
#import "CustomCellTableViewCell.h"


@import Photos;


@interface ViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>

//테이블뷰
@property (strong, nonatomic) IBOutlet UITableView *tableView;

//이미지 관리자
@property (strong) PHCachingImageManager *imageManager;

//PHFetchResult객체
@property (strong) PHFetchResult *assetsFetchResults;

@end

 

viewdidload 부분에서 이미지 관리자를 초기화 해주고, 전체 사진 개수를 조회 해서 PHFetchResult에 담아준다.

 

ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //테이블 뷰 델리게이트 설정
    tableView.delegate = self;
    tableView.dataSource = self;
    
    //이미지 관리자
    imageManager = [[PHCachingImageManager alloc]init];
    
    
    //전체 사진 개수
    PHFetchOptions *option = [[PHFetchOptions alloc]init];
    option.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
    assetsFetchResults = [PHAsset fetchAssetsWithOptions:option];
    NSLog(@"## [results count] 개수 : %d" , (int)[assetsFetchResults count]);
    
    
    
}

 

셀 개수를 assetsFetchResults 를 이용해서 아래와 같이 지정해준다.

 

//셀 개수
//섹션별로 테이블뷰의 셀 개수를 지정해 줄 수 있다.
- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    
    NSInteger numberOfRows = 0;
    if (section == 0) {
        numberOfRows = assetsFetchResults.count;
    }
    return numberOfRows;
}

 

PHCachingImageManager를 이용해서 직접 사진을 cell의 이미지에 할당해 준다.

 

//셀 꾸미기
//테이블 셀은 재사용가능하다. indexPath 안에 section 속성으로 이 cell이 몇번째 section에 속하는 cell 인지 체크하고 cell 구성을 해줄 수 있다.
- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
    
    CustomCellTableViewCell *cell = nil;
    
    if(indexPath.section == 0){
        
        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
        
        //cell의 tag 증가
        NSInteger currentTag = cell.tag + 1;
        cell.tag = currentTag;
        
        //이미지 사이즈
        CGSize size =  cell.imageView.image.size;
        
        //사진의 메타 데이터
        PHAsset *asset = assetsFetchResults[indexPath.item];
        
        [imageManager requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeAspectFill options:nil resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
            
            // 셀 태그가 변경되지 않은 경우에만 썸네일을 업데이트하고 그렇지 않으면 셀이 재사용 된 것
            if (cell.tag == currentTag) {
                
                cell.imageView.image = result;
                
                cell.label.text = [NSString stringWithFormat:@"사진 : %ld" , (long)indexPath.item];
                
            }
           
        }];
        
    }
    
    return cell;
}

 

cell 구성이 완료되었으면, 이제 셀을 클릭했을 때 segue를 이용해서 DetailViewController로 이동시켜준다. 이때 상세화면에서 보여줄 제목과 PHAsset 데이터를 같이 상세화면 변수에 할당해 준다.

 

//셀을 클릭했을 때 화면이동
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{

    //세그먼트 이름 체크 후
    if ([segue.identifier isEqualToString:DetailSegue]) {
        
        NSLog(@"showDetailSegue 이동");
        
        //세그먼트 destinationViewController 속성으로 목적지 Controller 출력
        DetailViewController *detailVC = segue.destinationViewController;
        
        //선택된 테이블 row
        NSIndexPath *indexPath = [tableView indexPathForSelectedRow];
        CustomCellTableViewCell  *cell = [tableView cellForRowAtIndexPath:indexPath];
        
        //상세 ViewController에 데이터 전달.
        
        //detailVC.image = cell.imageView.image;             //1.이미지 전달(x) 이미지가 흐리다..
        detailVC.data = cell.label.text;                     //2.text 전달

        PHAsset *asset = assetsFetchResults[indexPath.item]; //3.asset 전달
        detailVC.asset = asset;
        
 
    }
    
    //세그 참고 : https://0urtrees.tistory.com/45
}

 

테이블 뷰 헤더에는 전체 사진의 총 개수를 표시해 준다. 

 

//테이블 뷰 헤더 설정
//섹션별로 구분해서 헤더를 설정해준다. 색션을 구분하기 위한 값은 section 에 NSInteger 타입으로 들어있다.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
    
    //사진 전체 개수
    NSInteger count = [assetsFetchResults count];
    
    NSString *header = nil;
    if(section == 0){
        header = [NSString stringWithFormat:@"나의 사진리스트 (%d 장)" , (int)count];
    }
    return header;
}

 

완성

아래 사진처럼 Photos Framework에서 사진을 가져와서 테이블 뷰에 뿌려주고, 테이블 뷰를 클릭하면 우측 사진 처럼 상세화면으로 크게 보여진다.

아이폰 사진앱

 

예제파일

 

TableViewTest.zip
0.07MB

 

 

 

photos Framwork 개념

qteveryday.tistory.com/124

 

ios scale 참고

https://marlboroyw.tistory.com/508

https://maskkwon.tistory.com/256

https://m.blog.naver.com/PostView.nhn?blogId=jdub7138&logNo=220935733425&proxyReferer=https:%2F%2Fwww.google.com%2F