Program Tip

Swift @escaping 및 완료 처리기

programtip 2020. 10. 12. 08:05
반응형

Swift @escaping 및 완료 처리기


Swift의 'Closure'를 좀 더 정확하게 이해하려고 노력하고 있습니다.

그러나 @escaping하고 Completion Handler이해하기 너무 어렵다

많은 Swift 게시물과 공식 문서를 검색했지만 여전히 충분하지 않다고 느꼈습니다.

이것은 공식 문서의 코드 예제입니다

var completionHandlers: [()->Void] = []

func someFunctionWithEscapingClosure(completionHandler: @escaping ()->Void){
    completionHandlers.append(completionHandler)
}

func someFunctionWithNoneescapingClosure(closure: ()->Void){
    closure()
}

class SomeClass{
    var x:Int = 10
    func doSomething(){
        someFunctionWithEscapingClosure {
            self.x = 100
            //not excute yet
        }
        someFunctionWithNoneescapingClosure {
            x = 200
        }
    }
}

let instance = SomeClass()
instance.doSomething()
print(instance.x)

completionHandlers.first?() 
print(instance.x)

두 가지 방법과 이유가 있다고 들었습니다. @escaping

첫 번째는 클로저를 저장하기위한 것이고 두 번째는 비동기 운영을위한 것입니다.

다음은 내 질문입니다 .

첫째로, 만약 doSomething이 실행 후 someFunctionWithEscapingClosure고정 파라미터로 실행되며, 그 폐쇄 전역 변수 어레이에 저장한다.

클로저는 {self.x = 100}이라고 생각합니다.

self전역 변수에 저장된 {self.x = 100}에서 어떻게 그 객체에 completionHandlers연결할 수 있습니까?instanceSomeClass

둘째, 이렇게 이해 someFunctionWithEscapingClosure합니다.

completionHandler전역 변수 'completionHandlers we using@escaping ' 키워드에 지역 변수 클로저를 저장하려면 !

@escaping키워드 someFunctionWithEscapingClosure반환이 없으면 지역 변수 completionHandler가 메모리에서 제거됩니다.

@escaping 그 폐쇄를 기억에 유지하는 것입니다.

이게 옳은 거니?

마지막으로이 문법의 존재가 궁금합니다.

아마도 이것은 매우 초보적인 질문 일 것입니다.

특정 기능 후에 일부 기능을 실행하려는 경우. 특정 함수 호출 후에 그냥 함수를 호출하지 않는 이유는 무엇입니까?

위의 패턴을 사용하는 것과 이스케이프 콜백 함수를 사용하는 것의 차이점은 무엇입니까?


먼저 "매우 좋은 질문 :)"이라고 말하고 싶어요

완료 핸들러 :

사용자가 앱을 사용하는 동안 업데이트한다고 가정합니다. 완료되면 사용자에게 확실히 알리고 싶습니다. "축하합니다. 이제 완전히 즐길 수 있습니다!"라는 상자를 표시 할 수 있습니다.

그렇다면 다운로드가 완료된 후에 만 ​​코드 블록을 어떻게 실행합니까? 또한 뷰 컨트롤러를 다음 컨트롤러로 이동 한 후에 만 ​​특정 개체를 어떻게 애니메이션합니까? 음, 우리는 보스처럼 디자인하는 방법을 알아볼 것입니다. 내 방대한 어휘 목록을 기반으로 완료 핸들러는

일이 끝나면 물건을

자세한 내용은 이 블로그 게시물을 참조하십시오 .

이 링크는 완료 핸들러에 대한 완전한 명확성을 제공합니다 (개발자 관점에서 우리가 이해해야하는 것을 정확히 정의합니다).

@escaping 클로저 :

함수의 인수에 클로저를 전달할 때 함수의 본문이 실행 된 후이를 사용하고 컴파일러를 다시 반환합니다. 함수가 종료되면 전달 된 클로저의 범위가 존재하고 클로저가 실행될 때까지 메모리에 존재합니다.

함수 포함에서 클로저를 이스케이프하는 방법에는 여러 가지가 있습니다.

  • 저장소 : 전역 변수, 속성 또는 호출 함수 이전의 메모리에 존재하는 다른 저장소에 클로저를 저장해야 할 때 실행되고 컴파일러를 다시 반환합니다.

  • 비동기 실행 : despatch 큐에서 비동기식으로 클로저를 실행할 때 큐는 클로저를 메모리에 보관하고 나중에 사용할 수 있습니다. 이 경우 클로저가 언제 실행되는지 알 수 없습니다.

이러한 시나리오에서 클로저를 사용하려고하면 Swift 컴파일러가 오류를 표시합니다.

오류 스크린 샷

이 주제에 대한 자세한 내용 은 Medium에 대한이 게시물을 확인하십시오 .

이 링크에서 잘 이해하시기 바랍니다.

여전히 질문이있는 경우 (하지만이 링크를 먼저 한 줄씩 읽어야합니다. 매우 잘 설명되어 있음) 언제든지 의견을 공유하십시오.

감사합니다.이 답변을 업데이트해야하는 경우 계속 게시


다음은 @escaping이 어떻게 작동하는지 상기시키기 위해 사용하는 몇 가지 예제입니다.

class EscapingExamples: NSObject {

    var closure: (() -> Void)?

    func storageExample(with completion: (() -> Void)) {
        //This will produce a compile-time error because `closure` is outside the scope of this
        //function - it's a class-instance level variable - and so it could be called by any other method at
        //any time, even after this function has completed. We need to tell `completion` that it may remain in memory, i.e. `escape` the scope of this
        //function.
        closure = completion
        //Run some function that may call `closure` at some point, but not necessary for the error to show up.
        //runOperation()
    }

    func asyncExample(with completion: (() -> Void)) {
        //This will produce a compile-time error because the completion closure may be called at any time
        //due to the async nature of the call which precedes/encloses it.  We need to tell `completion` that it should
        //stay in memory, i.e.`escape` the scope of this function.
        DispatchQueue.global().async {
            completion()
        }
    }

    func asyncExample2(with completion: (() -> Void)) {
        //The same as the above method - the compiler sees the `@escaping` nature of the
        //closure required by `runAsyncTask()` and tells us we need to allow our own completion
        //closure to be @escaping too. `runAsyncTask`'s completion block will be retained in memory until
        //it is executed, so our completion closure must explicitly do the same.
        runAsyncTask {
            completion()
        }
    }





    func runAsyncTask(completion: @escaping (() -> Void)) {
        DispatchQueue.global().async {
            completion()
        }
    }

}

함수

func키워드 로 함수를 정의합니다 . 함수는 많은 매개 변수를 사용할 수 있으며 하나 또는 여러 매개 변수를 반환하지 않습니다.

폐쇄

클로저는 코드에서 전달 및 사용할 수있는 자체 포함 된 기능 블록입니다. ClosuresSwift의 경우 blocksC 및 Objective-C 및 다른 프로그래밍 언어의 람다와 유사합니다 .

함수와 클로저는 swift의 일급 유형입니다.

  • 지역 변수에 기능 / 폐쇄 할당
  • 함수 / 클로저를 인수로 전달
  • 함수 / 클로저 반환

이스케이프 클로저 대 비 이스케이프 클로저

  • A non-escaping closure @noescape는 전달 된 함수 내에서 즉 반환되기 전에 호출되는 클로저입니다.

    좋은 예 non-escaping closure이다 sort function같은 배열 sorted(by: (Element, Element) -> Bool). 클로저는 두 개의 매개 변수를 취하고 정렬 함수의 결과를 결정하는 Bool을 반환합니다. 클로저는 정렬 계산을 실행하는 동안 호출됩니다.

    * @noescape는의 속성입니다 swift 2. 이것은 @noescape Swift 3 non-escaping @ escaping` 속성 에서 더 이상 사용되지 않습니다 .swift 3 . Theattribute is applied by default in. Because closures are by defaultin Swift 3, escaping closures need to be marked as such. And the

  • An escaping closure @escaping is a closure that’s called after the function it was passed to returns. In other words, it outlives the function it was passed to. Because an owner function just save it in a property field and call when it necessary. Common use cases for this are:

    • Asynchronous calls; networking.
    • Functions stored as variables; think actions and supplied callbacks.
    • Scheduling tasks on a dispatch queue.


    A good example of an escaping closure is a completion handler. Many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn’t called until the operation is completed—the closure needs to escape, to be called later.

Read more here, here, here


import UIKit
import Alamofire

// Model

class ShortlistCountResponse : Decodable {
    var response : String?
    var data : ShortlistcountData?

}
class ShortlistcountData : Decodable {

    var totalpropFavcount : Int?
    var totalprojFavcount : Int?

}

// 일반 클래스 정의 ......

static func fetchGenericData<T: Decodable>(urlString: String,params : [String:Any], completion: @escaping (T) -> ()) {
        let url = urlString
        let headers = ["Content-Type": "application/x-www-form-urlencoded", "Accept":"application/json"]
        Alamofire.request(url, method: .post, parameters:params, encoding: URLEncoding.default, headers: headers).responseJSON { response in
            print(response.request?.urlRequest ?? "")
            print(params)
            print(response.data ?? "")
            print(response.value ?? "")
            switch(response.result) {
            case .success(_):
                if let data = response.data{
                    do {
                        let gotData = try JSONDecoder().decode(T.self, from: data)
                        completion(gotData)

                    }
                    catch let jsonErr {
                        print("Error serializing json:", jsonErr)
                        ActivityIndicator.dismissActivityView()

                    }
                    DispatchQueue.main.async {
                        ActivityIndicator.dismissActivityView()
                    }
                }
                break
            case .failure(_):
                print(response.result.error ?? "")
                ActivityIndicator.dismissActivityView()


                break

            }
        }
}

// 재미있는 전화

override func viewDidLoad() {
    super.viewDidLoad()

            let userID = ""
            let languageID = ""
            let params = ["userID":userID,"languageID":languageID]
            var appDelegate: AppDelegate?
            Service.fetchGenericData(urlString: "your url...", params: params) { (shortlistCountResponse : ShortlistCountResponse) in
             print(shortListCountResponse.data.totalprojFavcount ?? 0)

            }
}

참고 URL : https://stackoverflow.com/questions/46245517/swift-escaping-and-completion-handler

반응형