objective c block에 대한 이해


block 정의 변수나 데이터 구조안에 담을 수 있다. 

파라미터로 전달 할 수 있다. 반환값(return value)으로 사용할 수 있다. 

할당에 사용된 이름과 관계없이 고유한 구별이 가능하다. 

재사용해야하는 경우에는 클래스 기반의 Delegate을 사용고, 한번 사용할 로직이라면 보통 블럭을 사용 block 은 런타임에 생성되는 다이나믹 함수(Dynamic Function) 이다. 

병렬처리나 비동기처리(Asyncronous Processing), 혹은 '함수형언어(Functional Language)'의 특징과 비슷하다.


예제



#import "SampleClass.h"

#import <Foundation/Foundation.h>


int main(int argc, const char * argv[]) {

    @autoreleasepool {

      

#pragma exam1

        // myBlock은 함수 블럭 변수이고 그 다음에 등장하는 '^(int num)'은 블럭 타입의 함수를 의미한다

        

        int multiplier = 7;

        

        //함수블럭변수 = 블럭타입의 함수;

        

        int (^myBlockVriable)(int) = ^(int myNum) {

            return myNum * multiplier;

        };

        

        //호출

        int result = myBlockVriable(11);

        NSLog(@"result : %d" , result );  //result 77

        

#pragma exam2

        //블럭 내부에서 블럭외부 참조만 할 수 있다. 읽을 수만 있지 쓸 수는 없다.

        //int x = 123;   //블럭 내부에서 쓰겠다하면 오류가 발생한다.

        __block int x = 100; //블럭 내부에서 사용하겠다 선언.

        void (^printXAndY)(int) = ^(int y) {

            x = x + y; // error

            printf(" x: %d , y:%d\n", x, y);

        };


        printXAndY(3);

        

        

#pragma exam3 -  배열에 블락삽입, 블락은 객체타입이다.

        

        NSMutableArray *temArray = [[NSMutableArray alloc]init];

        [temArray addObject:^(int i){

            NSLog(@"결과는  %d 입니다." , i);

        }

         ];

        

        void (^c)(int) = ^(int i ){

            NSLog(@"두번째 결과는  %d 입니다." , i);

        };

        [temArray addObject:c];

        

        void (^b)(int) = temArray[0];

        void (^d)(int) = temArray[1];

        

        b(5);   //결과는  5 입니다.


        d(2);  //두번째 결과는  2 입니다.



#pragma exam4 - 델리게이트 처럼 사용하기 (특정 작업이 끝났을때 자동으로 호출)

        SampleClass *sampleClass = [[SampleClass alloc]init];

        [sampleClass performActionWithCompletion:^{

            NSLog(@"performActionWithCompletion 메소드가 호출 완료된 후 후처리 메소드 작동");

        }];

        

/*

 결과:

 수행. ...   ...   ...

 performActionWithCompletion 메소드가 호출 완료된 후 후처리 메소드 작동

 */

        

        

    }

    return 0;

    

    

}




sampleclass

#import <Foundation/Foundation.h>


//블록을 쉽게 사용하기위해서 타입 설정

typedef void (^CompletionBlock)(void);


@interface SampleClass : NSObject


-(void) performActionWithCompletion : (CompletionBlock)CompletionBlock;


@end





#import "SampleClass.h"


@implementation SampleClass


- (void)performActionWithCompletion:(CompletionBlock)CompletionBlock{

    

    NSLog(@"수행 ... .... ... ");

    //이 메소드가 호출된 후 후 처리 메소드가 자동으로 호출된 곳에서 실행이 된다.

    CompletionBlock();

}


@end





UIImagePickerController를 이용한 비디오





뷰컨트롤러



#import <UIKit/UIKit.h>

#import "ImagePickerController.h"

#import "ListTableViewController.h"




@interface ViewController : UIViewController


@property(nonatomic,strong) ImagePickerController *imagePickerController;


- (IBAction)cameraBtn:(id)sender;


- (IBAction)librayBtn:(id)sender;


@end




#import "ViewController.h"


@interface ViewController ()


@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

}



- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


//카메라 띄우기

- (IBAction)cameraBtn:(id)sender {

    NSLog(@"ViewController - UIImagePickerController 선택되었습니다.");

    //UIImagePickerController 생성 + 초기화 하고

    self.imagePickerController = [ImagePickerController new];

    ImagePickerController *myCameraInstance = [_imagePickerController getCameraVC];

    

    [self presentViewController: myCameraInstance animated:YES completion:nil];

    

}


//라이브러리 띄우기

- (IBAction)librayBtn:(id)sender {

    

    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

    ListTableViewController *viewController = [[ListTableViewController alloc]init];

    [self presentViewController:viewController animated:YES completion:nil];

    

}


@end


카메라컨트롤러

/*

 앱에서 비디오 캡쳐를 하는 가장 쉬운 방법은 UIImagePickerController 이용하는 것

 UIImagePickerController를 사용하려면

 <UINavigationControllerDelegate, UIImagePickerControllerDelegate>를 구현해야한다.

 */



#import <Foundation/Foundation.h>

#import <MobileCoreServices/MobileCoreServices.h>

#import <AssetsLibrary/AssetsLibrary.h>     //사진첩 관련 api

#import <UIKit/UIKit.h>                                 //카메라 api 관련 라이브러리


@interface ImagePickerController : NSObject <UINavigationControllerDelegate,UIImagePickerControllerDelegate,UIAlertViewDelegate>



@property(strong, nonatomic) NSURL* videoRecodUrl;



//UIImagePickerController 맴버 변수

@property (strong,nonatomic) UIImagePickerController *camera;



//UIImagePickerController리턴 해주는 메소드

-(UIImagePickerController *) getCameraVC;


@end


#import "ImagePickerController.h"


@implementation ImagePickerController




//초기화

-(id)init

{

    self = [super init];

    if (self) {

        NSLog(@"ImagePickerController 초기화 시작");

        _camera = [self setupImagePickController];

        NSLog(@"ImagePickerController 초기화 완료");

    }

    return self;

}





//초기화된 UIImagePickerController객체 던져주기

-(UIImagePickerController *) getCameraVC{

    return _camera;

}



/*

* UIImagePickerController객체를 만들고

* 카메라 롤에 카메라를 저장하고 카메라를 닫는 기능 등.. 기록 된 비디오를 추가로 처리하는 델리게이트를 정의

*/


//UIImagePickerController 객체 생성 및 초기화

-(UIImagePickerController *)setupImagePickController{

    NSLog(@"ImagePickerController - setupImagePickController 진입");

    UIImagePickerController *camera;

    //비디오 레코딩을 지원하는지 확인하고

    if ([self canVideoRecoding]) {

        camera = [UIImagePickerController new];

        camera.sourceType = UIImagePickerControllerSourceTypeCamera;

        camera.mediaTypes = @[(NSString *)kUTTypeMovie];

        camera.delegate = self;

        NSLog(@"ImagePickerController - UIImagePickerController 객체 생성 + 소스타입 + 미디어 타입 + 델리게이트 설정");

    }

    return camera;

}





//카메라를 인스턴스화 하기 전에 먼저 장치에서 비디오 녹화가 지원되는지 확인


-(BOOL)canVideoRecoding

{

     NSLog(@"ImagePickerController : canVideoRecoding - 진입");

 BOOL checkCamera =  [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];

    

    NSLog(@"ImagePickerController : checkCamera : %s", checkCamera ? "true" : "false");

    //true

    

    if (checkCamera) {

       

        NSArray *canMediaType =  [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];

    

        NSLog(@"ImagePickerController : canMediaType : %@ " , canMediaType);

        //("public.image","public.movie")


        

        if ([canMediaType containsObject:(NSString *)kUTTypeMovie]) {

            NSLog(@"ImagePickerController : canVideoRecoding - 비디오 레코딩 지원됩니다.");

            return YES;

        }

        

    }

    return NO;

}



#pragma camera config Method -  참고

//카메라 구성(cameraDevice속성 을 설정)

//설정하려는 카메라가 사용가능한지 확인

- (BOOL)checkFrontCameraPicker:(UIImagePickerController *)picker

{

    NSLog(@"ImagePickerController - checkFrontCameraPicker 카메라 구성(cameraDevice속성 을 설정");

    if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]){

        [picker setCameraDevice:UIImagePickerControllerCameraDeviceFront];

        return YES;

    }

    return NO;

}


//UIImagePickerController는 완벽한 카메라 ui가 제공된다.

//하지만 기본 컨트롤러 위에 자신이 만든 커스텀 컨트롤러를 사용하기 원할때

- (void)configureCustomPicker:(UIImagePickerController *)picker

{

    NSLog(@"ImagePickerController - configureCustomPicker 커스텀 컨트롤러를 사용");

    

    UIView *cameraOverlay = [[UIView alloc] init];

    picker.showsCameraControls = NO;

    picker.cameraOverlayView = cameraOverlay;

}



#pragma mark - UIImagePickerControllerDelegateMethod - 카메라 델리게이트 메소드


//*참고*

//1. videoAtPathIsCompatibleWithSavedPhotosAlbum : 내가 지정한 동영상 소스의 포토 앨범에 저장 가능 여부

//2. writeVideoAtPathToSavedPhotosAlbum : 지정된 동영상 소스를 포토 앨범으로 복사

//3. completionBlock 메소드의 실행이 완료되고나서 성공 여부를 알려주는 콜백


//4.iOS 내에서 동영상 인코딩하고 포토앨범에 저장할때 사용한다.

//5.iOS 4.0 이상에서 사용 가능하다.

//6.반드시 AssetsLibrary framework 추가해야 한다.


//*저장할때 참고*

//UIImagePickerController 는 앨범열고 하나 선택해서 array 추가 다시 앨범열고 array 추가

// ALAssetsLibrary 통째로 다 가져올 수 있음



//카메라 촬영하고 자장을 눌렀을때 호출

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{

    NSLog(@"ImagePickerController - didFinishPickingMediaWithInfo 진입");

    

    //저장 위치와 카메라 객체는 맴버변수로 할당

    _videoRecodUrl = [info objectForKey:UIImagePickerControllerMediaURL];

    _camera = picker;

    

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"저장위치" message:@"문서에 저장하시겠습니까?" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:@"NO", nil];

    [alert show];


}



//취소

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{

    NSLog(@"ImagePickerController - imagePickerControllerDidCancel");

     [picker dismissViewControllerAnimated:YES completion:nil];

}




//얼러트

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex

{

    if (buttonIndex == 0)

    {

        //Code for OK button - 문서에 저장하기

        //문서위치

       NSString*documentdirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

        NSLog(@"ImagePickerController documentdirectory : %@ ", documentdirectory);

        

        //데이트 포멧으로 파일명 지정

       NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];

        [dateFormatter setDateFormat:@"yyyy-MM-dd_HH-mm-ss"];

         NSString *destinationPath= [documentdirectory stringByAppendingFormat:@"/my_test_video_%@.mov",[dateFormatter stringFromDate:[NSDate date]]];

        

        NSLog(@"ImagePickerController destinationPath : %@ ", destinationPath);

        

         NSError *error;

        

         //넘어온 url 위치에 있는 파일을 -> 새로 지정한 url 위치로 복사해라

        [[NSFileManager defaultManager] copyItemAtURL: _videoRecodUrl toURL:[NSURL fileURLWithPath:destinationPath] error:&error];

       

        if(error){

            NSLog(@"복사중에 에러가 발생했습니다! error copying file: %@", [error localizedDescription]);

        }

        

        //종료

         [_camera dismissViewControllerAnimated:YES completion:nil];

        

        

        

    }

    //사진첩에 저장하기

    if (buttonIndex == 1)

    {

        

        ALAssetsLibrary *libray = [[ALAssetsLibrary alloc]init];

        

        NSLog(@"ImagePickerController - videoRecodUrl  : %@" ,_videoRecodUrl);

        

        //내가 지정한 동영상 소스의 포토 앨범에 저장 가능 여부

        BOOL checkSaveVideo = [libray videoAtPathIsCompatibleWithSavedPhotosAlbum:_videoRecodUrl];

        NSLog(@"ImagePickerController : checkSaveVideo : %s", checkSaveVideo ? "true" : "false");

        

        if (checkSaveVideo) {

            [libray writeVideoAtPathToSavedPhotosAlbum:_videoRecodUrl completionBlock:^(NSURL *assetURL, NSError *error) {

                NSLog(@"assetURL : %@" , assetURL);

                

            }];

        }

        [_camera dismissViewControllerAnimated:YES completion:nil];

    }

}




@end

파일리스트


#import <UIKit/UIKit.h>

#import "VideoCell.h"

#import <MediaPlayer/MediaPlayer.h>


@interface ListTableViewController : UITableViewController{

MPMoviePlayerController *mp;

}

@property(strong,nonatomic) NSMutableArray * videoList;


@end



#import "ListTableViewController.h"


@interface ListTableViewController ()


@end


@implementation ListTableViewController

@synthesize videoList;




- (id)init

{

    self = [super initWithStyle:UITableViewStylePlain];

    

    if (self) {

        NSFileManager *fm = [NSFileManager defaultManager];

        //다큐먼트 폴더가 존재하는지 확인

        NSArray *DocumentDrectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

        NSLog(@"DocumentDrectory : %@" , DocumentDrectory[0]);

        

        NSError *error;

        [fm contentsOfDirectoryAtPath:@"/" error:&error];

        NSLog(@"디렉토리 내용 : %@ ",   [fm contentsOfDirectoryAtPath: DocumentDrectory[0] error:&error]);

        

        videoList = [[NSMutableArray alloc]initWithArray: [fm contentsOfDirectoryAtPath: DocumentDrectory[0] error:&error]];

        

        NSLog(@"초기화 완료, 개수 : %lu" , [videoList count]);

        

    }

    

    return self;

}


- (void)viewDidLoad {

    [super viewDidLoad];

    NSLog(@"ListTableViewController -  viewDidLoad");

}


- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


#pragma mark - Table view data source


- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

#warning Incomplete implementation, return the number of sections

    return 1;

}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

#warning Incomplete implementation, return the number of rows

    return [videoList count];

}




- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    

    static NSString *CellIdentifier = @"VideoCell";

    

    // make a video cell object or reuse one

    VideoCell *cell = (VideoCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    

    if (cell == nil) {

        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"VideoCell" owner:self options:nil];

        cell = (VideoCell *)[nib objectAtIndex:0];

        

    }

    

    NSString *name  = [self.videoList objectAtIndex:indexPath.row];

    NSLog(@"file name: %@" , name);

    

    cell.textLabel.text = name;

    

    return cell;

}



//눌렀을때 재생

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{

     NSString *name = [self.videoList objectAtIndex:indexPath.row];

     NSString *slash = @"/";

    

    NSString *newName= [slash stringByAppendingString:name];

    

    NSLog(@"newName : %@" , newName);

    

    //파일이 존재하는지 확인1

    NSFileManager *fm = [NSFileManager defaultManager];

    NSArray *DocumentDrectory2 = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

    NSString *path2 = DocumentDrectory2[0];

    NSString *videoFilePath = [path2 stringByAppendingString:newName];

    

    NSLog(@"오픈할 파일 경로 :  %@" , videoFilePath );

    //파일이 존재하는 지 확인2

    if ([fm fileExistsAtPath: videoFilePath]) {

        NSLog(@"파일이 존재합니다.");


        NSURL *videoURL = [NSURL fileURLWithPath:videoFilePath];

        mp = [[MPMoviePlayerViewController alloc] initWithContentURL: videoURL];

        [self presentMoviePlayerViewControllerAnimated:mp];

    }else{

        NSLog(@"파일이 존재하지 않습니다.");

    }

    

}


@end


테이블셀


#import <UIKit/UIKit.h>


@interface VideoCell : UITableViewCell


@end



#import "VideoCell.h"


@implementation VideoCell


- (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


로그


1. 뷰컨트롤러에 버튼 두개 만들기


2. info.plist 에 카메라, 오디오 녹음, 사진 라이브러리 관련 권한 주기


3. 라이브러리 추가하기 AssetsLibray, MobileCoreService, AVFoundation,MediaPlayer


4.이미지 피커 컨트롤러 생성


- 필요한 라이브러리 임포트

-델리게이트 상속


5. 뷰컨트롤러에서 버튼 만들고 카메라 컨트롤러 띄우기







**********************작동별 로그**************


<카메라를 열었을때>


ViewController - UIImagePickerController 선택되었습니다.



ImagePickerController 초기화 시작

ImagePickerController : canVideoRecoding - 진입 - 초기화 시작전 카메라 권한체크!


ImagePickerController : checkCamera : true

ImagePickerController : canMediaType : (

"public.image",

"public.movie"

)


ImagePickerController : canVideoRecoding - 비디오 레코딩 지원됩니다.


ImagePickerController - setupImagePickController 진입


ImagePickerController - UIImagePickerController의 객체 생성 + 소스타입 + 미디어 타입 + 델리게이트 설정


ImagePickerController 초기화 완료



<취소했을때>


ImagePickerController - imagePickerControllerDidCancel





<녹화후 저장했을 때>


ImagePickerController - didFinishPickingMediaWithInfo 진입


magePickerController - videoRecodUrl  : file:///private/var/mobile/Containers/Data/Application/3B7B8C2A-0432-4101-8D20-417999ED8AA8/tmp/56584213032__5440B498-E9B0-4A26-BB1F-5E6A489C1FD8.MOV


ImagePickerController : checkSaveVideo : true


assetURL : assets-library://asset/asset.MOV?id=DDFBBA97-C0F6-45B8-96A8-C7BB46ED031D&ext=MOV

UIImagePickerControllerExample.zip

예제파일



ios filemanager 관련 모듈



#import <Foundation/Foundation.h>


@interface IDFileManager : NSObject


- (NSURL *) tempFileURL;

- (void) removeFile:(NSURL *)outputFileURL;

- (void) copyFileToDocuments:(NSURL *)fileURL;

- (void) copyFileToCameraRoll:(NSURL *)fileURL;


@end





#import "IDFileManager.h"

#import <AssetsLibrary/AssetsLibrary.h>


@implementation IDFileManager


//현재 파일 위치

- (NSURL *)tempFileURL

{

    NSString *path = nil;

    NSFileManager *fm = [NSFileManager defaultManager];

    NSInteger i = 0;

    while(path == nil || [fm fileExistsAtPath:path]){

        path = [NSString stringWithFormat:@"%@output%ld.mov", NSTemporaryDirectory(), (long)i];

        i++;

    }

    return [NSURL fileURLWithPath:path];

}


//파일 삭제

- (void) removeFile:(NSURL *)fileURL

{

    NSString *filePath = [fileURL path];

    NSFileManager *fileManager = [NSFileManager defaultManager];

    if ([fileManager fileExistsAtPath:filePath]) {

        NSError *error;

        [fileManager removeItemAtPath:filePath error:&error];

        if(error){

            NSLog(@"error removing file: %@", [error localizedDescription]);

        }

    }

}


//다큐먼트에 기록

- (void) copyFileToDocuments:(NSURL *)fileURL

{

    NSLog(@"IDFileManager copyFileToDocuments - 다큐먼트에 기록시작");

    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];

    

    NSLog(@"IDFileManager documentsDirectory : %@ ", documentsDirectory);

    

    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

    

    [dateFormatter setDateFormat:@"yyyy-MM-dd_HH-mm-ss"];

    

    NSString *destinationPath = [documentsDirectory stringByAppendingFormat:@"/output_%@.mov", [dateFormatter stringFromDate:[NSDate date]]];

    

    NSLog(@"IDFileManager destinationPath : %@ ", destinationPath);

    

    

    NSError *error;

    

    //넘어온 url 위치에 있는 파일을 -> 새로 지정한 url 위치로 복사해라

    [[NSFileManager defaultManager] copyItemAtURL:fileURL toURL:[NSURL fileURLWithPath:destinationPath] error:&error];

    

    

    if(error){

        NSLog(@"error copying file: %@", [error localizedDescription]);

    }

}


//카메로 롤로 파일 저장

- (void)copyFileToCameraRoll:(NSURL *)fileURL

{

    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

    if(![library videoAtPathIsCompatibleWithSavedPhotosAlbum:fileURL]){

        NSLog(@"video incompatible with camera roll");

    }

    

    NSLog(@"IDFileManager copyFileToCameraRoll - 사진첩에 기록 시작");

    [library writeVideoAtPathToSavedPhotosAlbum:fileURL completionBlock:^(NSURL *assetURL, NSError *error) {

        

        if(error){

            NSLog(@"Error: Domain = %@, Code = %@", [error domain], [error localizedDescription]);

        } else if(assetURL == nil){

            

            //It's possible for writing to camera roll to fail, without receiving an error message, but assetURL will be nil

            //Happens when disk is (almost) full

            NSLog(@"Error saving to camera roll: no error message, but no url returned");

            

        } else {

            //remove temp file

            NSError *error;

             NSLog(@"IDFileManager copyFileToCameraRoll - 파일 매니져 removeItemAtURL-remove temp file ");

            [[NSFileManager defaultManager] removeItemAtURL:fileURL error:&error];

            

            if(error){

                NSLog(@"error: %@", [error localizedDescription]);

            }

            

        }

    }];


}



@end








+ Recent posts

티스토리 툴바