অব্যাহতিহীন পরামিতিগুলির বন্ধ ব্যবহার এড়াতে অনুমতি দিতে পারে


139

আমার একটি প্রোটোকল রয়েছে:

enum DataFetchResult {
    case success(data: Data)
    case failure
}

protocol DataServiceType {
    func fetchData(location: String, completion: (DataFetchResult) -> (Void))
    func cachedData(location: String) -> Data?
}

উদাহরণ প্রয়োগের সাথে:

    /// An implementation of DataServiceType protocol returning predefined results using arbitrary queue for asynchronyous mechanisms.
    /// Dedicated to be used in various tests (Unit Tests).
    class DataMockService: DataServiceType {

        var result      : DataFetchResult
        var async       : Bool = true
        var queue       : DispatchQueue = DispatchQueue.global(qos: .background)
        var cachedData  : Data? = nil

        init(result : DataFetchResult) {
            self.result = result
        }

        func cachedData(location: String) -> Data? {
            switch self.result {
            case .success(let data):
                return data
            default:
                return nil
            }
        }

        func fetchData(location: String, completion: (DataFetchResult) -> (Void)) {

            // Returning result on arbitrary queue should be tested,
            // so we can check if client can work with any (even worse) implementation:

            if async == true {
                queue.async { [weak self ] in
                    guard let weakSelf = self else { return }

                    // This line produces compiler error: 
                    // "Closure use of non-escaping parameter 'completion' may allow it to escape"
                    completion(weakSelf.result)
                }
            } else {
               completion(self.result)
            }
        }
    }

উপরের কোডটি সংকলিত হয়েছে এবং সুইফট 3 (এক্সকোড 8-বিটা 5) এ কাজ করেছে তবে বিটা 6 দিয়ে আর কাজ করে না। আপনি কি আমাকে অন্তর্নিহিত কারণের দিকে নির্দেশ করতে পারেন?


5
এটি সুইফট 3
হানি

1
এটি আমাদের বুঝতে হবে যে কোনও ধারণা নেই। অন্য কোনও ভাষার প্রয়োজন নেই।
অ্যান্ড্রু কোস্টার

উত্তর:


243

এটি ফাংশন ধরণের পরামিতিগুলির জন্য ডিফল্ট আচরণের পরিবর্তনের কারণে ঘটে। সুইফ্ট 3 এর পূর্বে (বিশেষত এক্সকোড 8 বিটা 6 সহ জাহাজগুলি তৈরি করুন) তারা পালানোর আগে ডিফল্ট হয়ে যেত - তাদের @noescapeসংরক্ষণ বা ক্যাপচার হতে আটকাতে আপনাকে সেগুলি চিহ্নিত করতে হবে , এটি গ্যারান্টি দেয় যে তারা সময়কালকে ছাড়িয়ে যাবে না guaran ফাংশন কল।

যাইহোক, এখন @noescapeফাংশন-টাইপ পরামিতি জন্য ডিফল্ট। আপনি যদি এই জাতীয় ক্রিয়াকলাপ সংরক্ষণ বা ক্যাপচার করতে চান তবে আপনার এখন সেগুলি চিহ্নিত করা দরকার @escaping:

protocol DataServiceType {
  func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void)
  func cachedData(location: String) -> Data?
}

func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void) {
  // ...
}

দেখুন সুইফট বিবর্তন প্রস্তাব এই পরিবর্তন সম্পর্কে আরও তথ্যের জন্য।


2
তবে, কীভাবে আপনি কোনও ক্লোজার ব্যবহার করবেন যাতে এটি পালাতে দেয় না?
এনেকো অ্যালোনসো

6
@ এনেকো অ্যালোনসো আপনি যা জিজ্ঞাসা করছেন তা সম্পূর্ণরূপে নিশ্চিত নয় - আপনি হয় সরাসরি ফাংশনটিতেই একটি নন-এস্কেটিং ফাংশন প্যারামিটারটি কল করতে পারেন, বা অ-এস্কেটিং ক্লোজারে ধরা পড়লে আপনি ফোন করতে পারেন। এই ক্ষেত্রে, আমরা অ্যাসিঙ্ক্রোনাস কোড সঙ্গে লেনদেন করছেন, কোন গ্যারান্টি নেই যে asyncফাংশন প্যারামিটার (এবং সেইজন্য completionফাংশন) সামনে ডাকা হবে fetchDataএবং সেইজন্য হতে হবে - প্রস্থানের @escaping
হামিশ

কুরুচিপূর্ণ মনে হচ্ছে যে আমরা প্রোটোকলের জন্য @ এস্কেপিংকে পদ্ধতি স্বাক্ষর হিসাবে নির্দিষ্ট করতে হবে ... আমাদের কি করা উচিত? প্রস্তাবটি বলে না! : এস
Sajjon

1
@ সাজ্জোন বর্তমানে, আপনার প্রয়োজনীয়তা বাস্তবায়নের ক্ষেত্রে @escapingএকটি @escapingপ্যারামিটারের সাথে একটি প্রোটোকল প্রয়োজনীয়তার সাথে একটি পরামিতি মেলে নেওয়া দরকার (এবং বিচ্ছিন্ন পরামিতিগুলির বিপরীতে)। এটি সুইফট 2-তে একই ছিল @noescape
হামিশ


30

যেহেতু @ ননস্কেপ ডিফল্ট, ত্রুটিটি সমাধানের জন্য 2 টি বিকল্প রয়েছে:

1) @ হামিশ তার উত্তরে উল্লেখ করেছেন যে, আপনি যদি ফলাফলটির বিষয়ে চিন্তা করেন এবং সত্যই এটি থেকে বাঁচতে চান তবে এই সম্পূর্ণতাটিকে কেবল @ এস্কেপিং হিসাবে চিহ্নিত করুন (এটি সম্ভবত ইউনিট টেস্টগুলির সাথে @ লুকাশের প্রশ্নের উদাহরণ এবং async এর সম্ভাবনা হিসাবে উদাহরণস্বরূপ সমাপ্তির)

func fetchData(location: String, completion: @escaping (DataFetchResult) -> Void)

অথবা

2) আপনি যখন ফলাফলটির বিষয়ে চিন্তা করেন না তখন ক্ষেত্রে সম্পূর্ণরূপে ফলাফলগুলি বাতিল করে দিয়ে ডিফল্ট @ ননস্কেপ আচরণ রাখুন। উদাহরণস্বরূপ যখন ব্যবহারকারী ইতিমধ্যে "দূরে চলে গেছেন" এবং কলিং ভিউ কন্ট্রোলারকে কেবল কিছু অযত্ন নেটওয়ার্ক কল থাকার কারণে স্মৃতিতে ঝুলতে হবে না। ঠিক যেমনটি আমার ক্ষেত্রে যেমন ছিল আমি যখন উত্তর খুঁজতে চেয়েছি এবং নমুনা কোডটি আমার পক্ষে খুব প্রাসঙ্গিক ছিল না, তেমনি @ ননস্কেপ চিহ্নিত করা সবচেয়ে ভাল বিকল্প ছিল না, যদিও এটি প্রথম নজরে একমাত্র হিসাবে মনে হয়েছিল।

func fetchData(location: String, completion: ((DataFetchResult) -> Void)?) {
   ...
   completion?(self.result)
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.