SwiftTask(Promise Extension) 사용

14520 단어 Swift
지난번
  • Swift로 유한 오토매틱(상태기)-Qiita 만들기
  • Swift+ 제한된 자동 그래픽 확장 Promise
  • 계속이번에 소개한 것은 나의 졸작인 《SwiftTask》의 프로그램 라이브러리다.
    SwiftTask
    https://github.com/inamiy/SwiftTask

    SwiftTask 정보


    SwiftTask는 PromiseKitBolts-iOS와 마찬가지로 Promise가 쓴 흐름 제어 라이브러리입니다.
    주로 다음과 같은 특징이 있다.
  • Progress, Pause/Resume, Cancel의 새로운 커넥터(Promise 고기능화)
  • Generix를 활용하여 Pure Swift(Cocoa Framework)
  • 에 의존하지 않음
  • SwiftTask 단일 비동기식(스레드, 비동기식) 프로세싱이 없는 얇은 나팔구 클래스
  • 기본적으로 비동기 처리는 작업 내부(클론 초기화)에서 진행된다(뒤에 설명된 Alam ofire의 예시 참조)
  • 여러 임무를 뛰어넘는 조율 처리(Task.all() 등)에서 최소한의 배타 제어만 한다
  • 매개 변수를 사용하는trailing closure의 간단한method chaining
  • 다른 프로그램 라이브러리와 비교했을 때 SwiftTask 자체는 비동기 처리가 없기 때문에 간단하지 않지만 참고로 표를 만들어 보겠습니다.(2014/08/30 지금. 개인적인 소감입니다)
    프로그램 라이브러리
    progress
    pause
    cancel
    직렬 처리
    조화 처리
    NSOperation/Queue
    ×
    △실행 중 중단 없음

    ×매우 고통스럽다
    ×매우 고통스럽다
    PromiseKit
    ×
    ×
    ×
    ○then의 설치가 충분하지 않다?
    △when
    Bolts-iOS
    ×
    ×
    ○외부token 방식

    △all만
    SwiftTask
    △인터페이스만
    △인터페이스만
    △인터페이스만

    all,any,some 등

    사용 예


    SwiftTask에서 작업을 정의할 때(클론 내 초기화) Grand Central Dispatch 등을 사용하여 비동기적으로 처리할 수도 있습니다.
    Alamofire(네트워크 라이브러리)로 구성
  • obj.setProgressHandler() (callback)
  • obj.setCompletionHandler() (callback)
  • obj.pause()
  • obj.resume()
  • obj.cancel()
  • 의 API 형식에서 "일단 다른 범주로 패키지를 사용"은 보다 간단하게 구현할 수 있습니다.

    Alamofire 사용 예

    typealias Progress = (bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
    
    // define task
    let task = Task<Progress, NSData?, NSError> { (progress, fulfill, reject, configure) in
    
        let request = Alamofire.download(.GET, "http://httpbin.org/stream/100", destination: somewhere)
    
        request.progress { (bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) in
    
            progress((bytesWritten, totalBytesWritten, totalBytesExpectedToWrite) as Progress)
    
        }.response { (request, response, data, error) in
    
            if let error = error {
                reject(error)
                return
            }
    
            fulfill(data as NSData?)
    
        }
    
        configure.pause  = { request.suspend() }
        configure.resume = { request.resume() }
        configure.cancel = { request.cancel() }
    
        return
    }
    
    위 코드는 내부용NSURLSessionDownloadTask의 간단한 다운로드 처리 샘플입니다.
    초기화task할 때 먼저 열네크스로 표시된Progress,Value (fulfilled),Error (rejected)의 유형(Progress가 반드시 0.0~1.0의 플랫형이 필요하지는 않다)을 결정해야 한다.
    Task<Progress, Value, Error>
    
    이어 초기화 옷장을 사용하여 내부에서 파라미터 전달progress,fulfill,reject,configure,fulfill를 실행한다.이때
  • rejectprogress의 호출 방법은 이전의 Promise 때와 같다
  • fulfill 또는 reject를 호출하기 전에 여러 번 실행할 수 있음(optional)
  • configure에서 실현pause,resume,canceltask.progress(progressClosure)(optional)
  • 또 알람오페어가 코코아가 델리 방법에서 준비했던 프로그레스 부분을 호출 형태로 전환했기 때문에 알람오페라→스위프트 Task로의 프로그레스로 전파는 위에서 설명한 대로 간단하다.

    Method Chaining


    Promise처럼 method chaining을 진행하는 방법은 다음과 같습니다.
    task.progress { progress in
    
        println("bytesWritten = \(progress.bytesWritten)")
        println("totalBytesWritten = \(progress.totalBytesWritten)")
        println("totalBytesExpectedToWrite = \(progress.totalBytesExpectedToWrite)")
    
    }.then { (value: NSData?) -> Void in 
    
        println("fulfilled: \(value)")
    
    }.catch { (errorInfo: ErrorInfo) -> Void in
    
        println("rejected: \(errorInfo.error) \(errorInfo.isCancelled)")
    
    }
    

    progress


    우선task을 집행한 후progressClosure에 등록progress한다.
    또한 아까 초기화 옷장 안의 매개 변수progressClosure 처리 프로그램이 실행될 때마다 초기화 옷장 바깥쪽 위치task.progress()에서 실행되는 구조입니다.
    참고로 task의 반환값은 같기 때문then이므로 후속catch/task.then(closure)에 직접 연결할 수 있다.

    then

    closure는 하나의 task 매개 변수만 받아들이고 새로운task로 돌아가는 방법입니다.
    기본적으로 closure가fulfilled라면 promise.then(onFulfilled)라고 불러야 한다.
    참, JavaScript Promise의 경우
  • promise.then(onFulfilled, onRejected) (fulfilled only)
  • task.then {...}.then {...} (fulfilled & rejected)
  • 이렇게 하면 최대 두 개의 매개 변수를 취하여 둘을 구분할 수 있으며, SwiftTask에서 매개 변수를 하나의closure+과부하+형 추론으로 제한하여 구분할 수 있다.이 장점으로
  • 언제든지 () 형식으로 쓸 수 있음onFulfilled

  • 분할onRejected/completionHandler보다 Apple 흐름으로 통일then이 API 디자인에 더 좋다
  • 참조: Stop Using Success/Failure Blocks | Collin Donnell
  • 네.closure수신then의 유형에 대한 자세한 내용은 README.md를 보십시오.

    catch

    task.catch(closure)와 마찬가지로 closuretask 매개 변수를 수신하고 새로운task를 되돌려줍니다.closure가rejected일 때만 closure라고 부른다.
    여기에 Error의 매개 변수는 Task.ErrorInfo 대상이 아니라 (error: Error?, isCancelled: Bool)의 Tuple형이다.
    보기errorInfo.isCancelled를 통해 취소 여부를 판단할 수 있다.

    Pause/Resume/Cancel


    외부에서 대상을 직접 호출하는 각종 방법을 통해 초기화 옷장configure에 설치된pause/resume를 실행할 수 있다.
    task.pause()
    task.resume()
    task.cancel() // task.cancel(error)もできる
    
    취소된cancel은 내부reject와 거의 같아 task 등으로 포착할 수 있다.

    번외: Custom Operator 사용


    아직 시험적인 실현에 불과하지만 task,catch,progress,then도 사용자 정의 연산자로 대체할 수 있다.
  • catch = task ~ {...}
  • task.progress { progress in ...} = task >>> {...} (fulfilled & rejected)
  • task.then { value, errorInfo in ...} = task *** {...} (fulfilled only)
  • task.then { value in ...} = task !!! {...} (rejected only)
  • 바로 해보세요.
    task ~ { progress in
        ...
    } *** { (value: NSData?) -> String in 
        ...
    } !!! { (errorInfo: ErrorInfo) -> String in
        ...
    } >>> { (value, errorInfo) -> Void in
        ...
    }
    
    Ship it! task.catch { errorInfo in ...}의 처리 차이가 더욱 뚜렷해졌다.
    이것도 편할 것 같으니 꼭 써 보세요.
    (더 좋은 기법이 있으면 알려주세요.)

    좋은 웹페이지 즐겨찾기