সুইফট @ এসকেপিং এবং কমপ্ল্যান্ড হ্যান্ডলার


100

আমি আরও স্পষ্টভাবে সুইফটের 'ক্লোজার' বোঝার চেষ্টা করছি।

কিন্তু @escapingএবং Completion Handlerবুঝতে খুব কঠিন

আমি অনেক সুইফ্ট পোস্টিং এবং অফিসিয়াল ডকুমেন্ট অনুসন্ধান করেছি, কিন্তু আমি অনুভব করেছি যে এটি এখনও পর্যাপ্ত নয়।

এটি সরকারী নথির কোড উদাহরণ

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, executes তারপর someFunctionWithEscapingClosureঅবসান পরামিতি সঙ্গে নির্বাহ করবে এবং যে অবসান বিশ্বব্যাপী পরিবর্তনশীল অ্যারের মধ্যে সংরক্ষণ করা হবে।

আমি মনে করি বন্ধটি {self.x = 100 is

কীভাবে self{স্ব.এক্স = 100} যা বিশ্বব্যাপী ভেরিয়েবলে সংরক্ষণ completionHandlersকরা যায় instanceসেই বস্তুর সাথে সংযুক্ত হতে পারে SomeClass?

দ্বিতীয়ত, আমি someFunctionWithEscapingClosureএই মত বুঝতে ।

স্থানীয় ভেরিয়েবল ক্লোজারকে completionHandlerگلوبل ভেরিয়েবল 'কমপ্লিউশনহ্যান্ডার্স we using@ এস্কেটিং` কীওয়ার্ডে সঞ্চয় করতে!

@escapingকীওয়ার্ড someFunctionWithEscapingClosureরিটার্ন ব্যতীত স্থানীয় ভেরিয়েবল completionHandlerমেমরি থেকে সরিয়ে ফেলবে

@escaping স্মৃতিতে যে বন্ধ রাখা হয়

এটা কী ঠিক?

শেষ অবধি, আমি এই ব্যাকরণের অস্তিত্ব সম্পর্কে আশ্চর্য হয়েছি।

হতে পারে এটি খুব প্রাথমিক প্রশ্ন।

আমরা যদি কিছু নির্দিষ্ট ফাংশন পরে কিছু ফাংশন সম্পাদন করতে চাই। আমরা নির্দিষ্ট ফাংশন কল করার পরে কেন কিছু ফাংশন কল করি না?

উপরের প্যাটার্নটি ব্যবহার করে এবং একটি পালানো কলব্যাক ফাংশন ব্যবহারের মধ্যে পার্থক্যগুলি কী?

উত্তর:


124

সুইফ্ট সমাপ্তি হ্যান্ডলার এসকেপিং এবং নন-এস্কেপিং:

যেমন বব লি তার ব্লগ পোস্টে বব উইথ সুইফটে কমপ্লেশন হ্যান্ডলারগুলি ব্যাখ্যা করেছেন :

ধরুন ব্যবহারকারী কোনও অ্যাপ্লিকেশন ব্যবহার করার সময় আপডেট করছে। এটি সম্পন্ন হয়ে গেলে আপনি অবশ্যই ব্যবহারকারীকে অবহিত করতে চান। আপনি সম্ভবত একটি বাক্স পপ আপ করতে চান যা বলছে, "অভিনন্দন, এখন, আপনি পুরোপুরি উপভোগ করতে পারেন!"

সুতরাং, ডাউনলোডের কাজ শেষ হওয়ার পরে আপনি কীভাবে একটি ব্লক কোড চালাবেন? আরও দেখুন, কেবলমাত্র কোনও নিয়ামককে পরবর্তীটিতে স্থানান্তরিত করার পরে আপনি কীভাবে নির্দিষ্ট কিছু বস্তু সঞ্জীবিত করতে পারেন? ঠিক আছে, আমরা কীভাবে একজন বসের মতো ডিজাইন করব তা খুঁজে বের করতে যাচ্ছি।

আমার বিস্তৃত শব্দভাণ্ডারের তালিকার ভিত্তিতে, সমাপ্তি হ্যান্ডলারের পক্ষে stand

জিনিসগুলি হয়ে গেলে জিনিসগুলি করুন

বব এর পোস্ট সমাপ্তি হ্যান্ডলার সম্পর্কে স্পষ্টতা প্রদান করে (একটি বিকাশকারী দৃষ্টিকোণ থেকে এটি আমাদের কী বুঝতে হবে তা হুবহু সংজ্ঞায়িত করে)।

@ অবরুদ্ধ বন্ধ:

যখন কেউ ফাংশন আর্গুমেন্টে একটি ক্লোজার পাস করে, ফাংশনটির বডি কার্যকর হয়ে যাওয়ার পরে এটি ব্যবহার করে এবং সংকলকটি ফিরে দেয়। যখন ফাংশনটি শেষ হয়, তখন বন্ধ হওয়াটি কার্যকর না হওয়া অবধি পাসের বন্ধের সুযোগ উপস্থিত থাকে এবং স্মৃতিতে অস্তিত্ব থাকে।

ফাংশনটি ধারণ করে বন্ধ হওয়া থেকে বাঁচার বিভিন্ন উপায় রয়েছে:

  • স্টোরেজ: আপনি যখন ক্লোনিং ফাংশনের স্মৃতি অতীতে উপস্থিত বিশ্বব্যাপী ভেরিয়েবল, সম্পত্তি বা অন্য কোনও স্টোরেজে ক্লোজারটি সংরক্ষণ করতে চান তখন সম্পাদন হয়ে যায় এবং সংকলকটি ফিরে ফিরিয়ে দেয়।

  • অ্যাসিঙ্ক্রোনাস এক্সিকিউশন: আপনি যখন প্রেরণকারী সারিটিতে অবিচ্ছিন্নভাবে ক্লোজারটি সম্পাদন করছেন, তখন কিউ আপনার জন্য স্মৃতিতে ক্লোজারটি ধরে রাখবে, ভবিষ্যতে ব্যবহার করা যেতে পারে। এই ক্ষেত্রে কখন বন্ধটি কার্যকর হবে তা আপনার কোনও ধারণা নেই।

আপনি যখন এই পরিস্থিতিতে ক্লোজারটি ব্যবহার করার চেষ্টা করবেন তখন সুইফট সংকলক ত্রুটিটি দেখিয়ে দেবে:

ত্রুটি স্ক্রিনশট

এই বিষয় সম্পর্কে আরও স্পষ্টতার জন্য আপনি এই পোস্টটি মিডিয়ামে দেখতে পারেন

আরও একটি পয়েন্ট যুক্ত করা হচ্ছে, যা প্রতিটি আইওএস বিকাশকারীকে বুঝতে হবে:

  1. এস্কেপিং বন্ধ : একটি পালানো বন্ধ হ'ল এমন একটি ক্লোজার যা ফাংশনটি এটির কাছে ফেরত দেওয়ার পরে বলা হয়। অন্য কথায়, এটি এতে ফাংশনটি বহন করে।
  2. অব্যাহতি না হওয়া বন্ধ : যে ফাংশনটির মধ্যে এটি বলা হয়েছিল এটি বন্ধ হয়ে গেছে, এটি ফিরে আসার আগেই।

@ শাভাকর, আমরা যদি কোনও ক্লোজার সঞ্চয় করি তবে পরে এটি কল না করি। অথবা যদি পদ্ধতিটি দু'বার কল করা হয়ে থাকে তবে আমরা ক্লোজারকে কেবল একবার ডেকেছি। যেহেতু আমরা জানি যে ফলাফল একই।
ব্যবহারকারী1101733

@ ব্যবহারকারী1101733 আমি মনে করি আপনি বন্ধের হাত থেকে রক্ষা পাওয়ার কথা বলছেন, আপনি কল না করলে ক্লোজার কার্যকর হবে না। উপরের উদাহরণে কল করুন ডুমিং কিছু পদ্ধতি 2 বার 2 সমাপ্তি হলে হ্যান্ডলার অবজেক্টটি সংযোজনে যুক্ত হবেহ্যান্ডলারের অ্যারে। যদি আপনি সম্পূর্ণতা হ্যান্ডলারের অ্যারে থেকে প্রথম অবজেক্ট নেন এবং কল করেন তবে এটি কার্যকর হবে তবে সম্পূর্ণতা হ্যান্ডলারের অ্যারে গণনা একই থাকবে (2)।
দীপক

@ প্রদীপ, পালানো বন্ধের বিষয়ে হ্যাঁ। ধরুন আমরা সাম্প্রতিক কলটি কার্যকর করতে হবে সেজন্য আমরা অ্যারে ব্যবহার করি না এবং ক্লোজার রেফারেন্স সঞ্চয় করতে সাধারণ পরিবর্তনশীল ব্যবহার করি। পূর্ববর্তী বন্ধগুলির দ্বারা দখল করা কিছু স্মৃতি যা কখনও কল করবে না?
ব্যবহারকারী1101733

4
@ ব্যবহারকারী1101733 সমাপ্তি হল রেফারেন্স টাইপ (শ্রেণীর মতো), আপনি যখন ভেরিয়েবলটিতে নতুন ক্লোজারগুলি অর্পণ করেন তখন সম্পত্তি / ভেরিয়েবল নতুন বন্ধের দিকে নির্দেশ করবে তাই এআরসি পূর্ববর্তী বন্ধগুলির জন্য মেমরিটিকে কমিয়ে দেবে।
দীপক

28

@ এস্কেপিং কীভাবে কাজ করে তা নিজেকে স্মরণ করিয়ে দেওয়ার জন্য আমি এখানে একটি ছোট্ট উদাহরণের উদাহরণ দিচ্ছি।

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

}

4
এই কোডটি সঠিক নয়। এটি বাছাইপর্বকে হারিয়েছে @escaping
রব

আমি এটি সর্বাধিক পছন্দ করেছিi.e. escape the scope of this function.
গাল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.