সাম্যের জন্য আপনি কীভাবে কার্যকারিতা এবং সমাপনী পরীক্ষা করেন?


88

বইটি বলেছে যে "ফাংশন এবং ক্লোজারগুলি হল রেফারেন্স টাইপ"। সুতরাং, উল্লেখগুলি সমান কিনা আপনি কীভাবে আবিষ্কার করবেন? == এবং === কাজ করে না।

func a() { }
let å = a
let b = å === å // Could not find an overload for === that accepts the supplied arguments

4
আমি যতদূর বলতে পারি, আপনি MyClass.self
মেটাচ্লাসের সমতাও

পরিচয়ের জন্য দুটি বন্ধের তুলনা করা প্রয়োজন হবে না। আপনি যেখানে এটি করতেন তার উদাহরণ দিতে পারেন? বিকল্প সমাধান হতে পারে।
বিল

4
মাল্টিকাস্ট ক্লোজার, একটি লা সি #। এগুলি অগত্যা সুইফটে কৃপণতাযুক্ত, কারণ আপনি (টি, ইউ) "অপারেটর" ওভারলোড করতে পারবেন না, তবে আমরা সেগুলি নিজেরাই তৈরি করতে পারি। রেফারেন্স দ্বারা একটি অনুরোধের তালিকা থেকে ক্লোজারগুলি সরাতে সক্ষম না হয়ে তবে, আমাদের নিজস্ব র্যাপার ক্লাস তৈরি করা দরকার। এটি একটি টানা এবং এটি প্রয়োজন হবে না।
জেসি

4
দুর্দান্ত প্রশ্ন, তবে সম্পূর্ণ পৃথক জিনিস: আপনার åরেফারেন্সে ডায়রিটিকের ব্যবহার aসত্যই আকর্ষণীয়। এখানে কোন কনভেনশন আপনি সন্ধান করছেন? (আমি আসলে জানি না আমি জানি না; তবে এটি সম্ভবত খুব শক্তিশালী হতে পারে, বিশেষত খাঁটি কার্যকরী প্রোগ্রামিংয়ে in)
রব নেপিয়ার

4
আমি একজন অ্যারের মধ্যে বন্ধ সংরক্ষণকারী করছি @Bill শৃঙ্খলা খুঁজে পেতে এবং তাদের সরিয়ে indexOf মধ্যে ({$ 0 == অবসান} ব্যবহার করতে পারবেন না এখন আমি পুনর্বিন্যাস অপ্টিমাইজেশান যা আমি দরিদ্র ভাষা নকশা বলে মনে করেন কারণে আমার কোড
জ্যাক মরিস

উত্তর:


72

ক্রিস ল্যাটনার বিকাশকারী ফোরামে লিখেছেন:

এটি এমন একটি বৈশিষ্ট্য যা আমরা ইচ্ছাকৃতভাবে সমর্থন করতে চাই না। বিভিন্ন ধরণের জিনিস রয়েছে যা অপ্টিমাইজেশনের উপর নির্ভর করে ফাংশনগুলির (প্যারাফাইটি টাইপ সিস্টেমের অর্থে, যেখানে বিভিন্ন ধরণের ক্লোজার অন্তর্ভুক্ত) পয়েন্টার সমতা তৈরি করবে। যদি "===" ফাংশনগুলিতে সংজ্ঞায়িত করা হয়, তবে সংকলকটিকে অভিন্ন পদ্ধতিতে সংশ্লেষ করার, অংশগুলি ভাগ করার এবং ক্লোজারগুলিতে নির্দিষ্ট ক্যাপচার অপ্টিমাইজেশান সম্পাদনের অনুমতি দেওয়া হবে না। আরও কিছু জেনেরিক প্রসঙ্গে এই ধরণের সাম্যতা অত্যন্ত আশ্চর্যজনক হবে, যেখানে আপনি পুনরায় সংক্ষিপ্তকরণ পেতে পারেন যা ফাংশনের ধরণের প্রত্যাশা অনুযায়ী কোনও ফাংশনের আসল স্বাক্ষর সামঞ্জস্য করে।

https://devforums.apple.com/message/1035180#1035180

এর অর্থ হ'ল সমতার জন্য বন্ধের তুলনা করার চেষ্টাও আপনার করা উচিত নয় কারণ অপ্টিমাইজেশান ফলাফলকে প্রভাবিত করতে পারে।


19
এই মাত্র আমাকে বিট, যা আমি এক ধরণের ধ্বংসাত্মক ছিল কারণ আমি একটি অ্যারেতে ক্লোজারগুলি সংরক্ষণ করেছিলাম এবং এখন এগুলি সূচিপত্রের সাহায্যে মুছে ফেলতে পারি না ($ $ 0 == বন্ধ} তাই আমাকে রিফ্যাক্টর করতে হবে IM আইএমএইচও অপ্টিমাইজেশানটি ভাষা নকশাকে প্রভাবিত করবে না, সুতরাং ম্যাট এর উত্তরে এখন অবনতিযুক্ত @objc_ block এর মতো দ্রুতগতি ছাড়াই আমি যুক্তি দেব যে সুইফট এই মুহুর্তে ক্লোজারগুলি সঠিকভাবে সঞ্চয় করতে এবং পুনরুদ্ধার করতে পারে না So সুতরাং আমি কলব্যাক ভারী কোডে সুইফ্টের ব্যবহারের পক্ষে সমর্থন করা উপযুক্ত মনে করি না ওয়েব বিকাশে যেমন ধরণের মুখোমুখি হয়েছিল। যা পুরো কারণেই আমরা সুইফটে প্রথম স্থানে চলে এসেছি ...
জ্যাক মরিস

4
@ জ্যাকমরিস বন্ধের সাথে কোনও ধরণের সনাক্তকারী সংরক্ষণ করুন যাতে আপনি এটি পরে মুছে ফেলতে পারেন। আপনি যদি রেফারেন্সের ধরণগুলি ব্যবহার করে থাকেন তবে আপনি কেবলমাত্র অবজেক্টের জন্য একটি রেফারেন্স সঞ্চয় করতে পারেন অন্যথায় আপনি নিজের আইডেন্টিফায়ার সিস্টেমটি নিয়ে আসতে পারেন। এমনকি আপনি এমন ধরণের ডিজাইন করতে পারেন যাতে ক্লোজার রয়েছে এবং একটি অনন্য শনাক্তকারী যা আপনি সরল বন্ধের পরিবর্তে ব্যবহার করতে পারেন।
21:38

4
@ ড্রুয়াগ হ্যাঁ, কার্যকার্য রয়েছে, তবে জ্যাক ঠিক আছে। এটা সত্যিই খোঁড়া। আমি বুঝতে পারছি যে অপ্টিমাইজেশন থাকা চাই, তবে যদি কোডের কোথাও এমন কিছু থাকে যে বিকাশকারীকে কিছু বন্ধের তুলনা করা দরকার তবে কেবল সংকলকটি সেই বিশেষ বিভাগগুলিকে অপ্টিমাইজ না করে। অথবা সংকলকটির কিছু প্রকারের অতিরিক্ত ক্রিয়াকলাপ তৈরি করুন যা এটি সাম্যতার স্বাক্ষরগুলি তৈরি করতে সক্ষম করে যা ফ্রিকিং অপ্টিমাইজেশানগুলির সাথে ভেঙে যায় না। এটি এই অ্যাপল আমরা এখানেই কথা বলছি ... তারা যদি আইওম্যাকের সাথে একটি শিওন ফিট করতে পারে তবে তারা অবশ্যই বন্ধগুলি তুলনীয় করে তুলতে পারে। আমাকে একটু বিরতি দাও!
২৪

10

আমি অনেক খোঁজাখুঁজি করেছি। ফাংশন পয়েন্টার তুলনার কোনও উপায় নেই বলে মনে হয়। আমার কাছে সবচেয়ে ভাল সমাধানটি হ'ল কোনও হ্যাশযোগ্য অবজেক্টে ফাংশনটি বন্ধ করা বা বন্ধ করা। পছন্দ:

var handler:Handler = Handler(callback: { (message:String) in
            //handler body
}))

4
এটি এখন পর্যন্ত সর্বোত্তম পন্থা। এটি বন্ধ করে মোড়ক এবং আন-মোড়ক করতে ব্যর্থ হয় তবে এটি অ-সংজ্ঞা, অসমর্থিত ভঙ্গুর চেয়ে ভাল।

8

সবচেয়ে সহজ উপায় হ'ল ব্লক প্রকারটি হিসাবে চিহ্নিত করা যায় @objc_blockএবং এখন আপনি এটিকে যেকোনওবজেক্টে কাস্ট করতে পারেন যা এর সাথে তুলনীয় ===। উদাহরণ:

    typealias Ftype = @objc_block (s:String) -> ()

    let f : Ftype = {
        ss in
        println(ss)
    }
    let ff : Ftype = {
        sss in
        println(sss)
    }
    let obj1 = unsafeBitCast(f, AnyObject.self)
    let obj2 = unsafeBitCast(ff, AnyObject.self)
    let obj3 = unsafeBitCast(f, AnyObject.self)

    println(obj1 === obj2) // false
    println(obj1 === obj3) // true

আরে, আমি চেষ্টা করছি যদি অনিরাপদ বিটকাস্ট (শ্রোতা, যিনি) ধারণাটি একটি ইভেন্ট ভিত্তিক সিস্টেম বানাতে হবে তবে সরানোEventListener পদ্ধতিটি ফাংশন পয়েন্টারগুলি পরীক্ষা করতে সক্ষম হবে।
জমে

4
সুইফট ২.x এ @objc_ block এর পরিবর্তে @ কনভেনশন (ব্লক) ব্যবহার করুন দুর্দান্ত উত্তর!
গ্যাব্রিয়েল.মাসানা

6

আমি উত্তরটিও খুঁজছিলাম। এবং আমি এটি শেষ পেয়েছি।

আপনার যা প্রয়োজন তা হ'ল আসল ফাংশন পয়েন্টার এবং এর প্রসঙ্গটি ফাংশন অবজেক্টে লুকানো।

func peekFunc<A,R>(f:A->R)->(fp:Int, ctx:Int) {
    typealias IntInt = (Int, Int)
    let (hi, lo) = unsafeBitCast(f, IntInt.self)
    let offset = sizeof(Int) == 8 ? 16 : 12
    let ptr  = UnsafePointer<Int>(lo+offset)
    return (ptr.memory, ptr.successor().memory)
}
@infix func === <A,R>(lhs:A->R,rhs:A->R)->Bool {
    let (tl, tr) = (peekFunc(lhs), peekFunc(rhs))
    return tl.0 == tr.0 && tl.1 == tr.1
}

এবং এখানে ডেমো:

// simple functions
func genericId<T>(t:T)->T { return t }
func incr(i:Int)->Int { return i + 1 }
var f:Int->Int = genericId
var g = f;      println("(f === g) == \(f === g)")
f = genericId;  println("(f === g) == \(f === g)")
f = g;          println("(f === g) == \(f === g)")
// closures
func mkcounter()->()->Int {
    var count = 0;
    return { count++ }
}
var c0 = mkcounter()
var c1 = mkcounter()
var c2 = c0
println("peekFunc(c0) == \(peekFunc(c0))")
println("peekFunc(c1) == \(peekFunc(c1))")
println("peekFunc(c2) == \(peekFunc(c2))")
println("(c0() == c1()) == \(c0() == c1())") // true : both are called once
println("(c0() == c2()) == \(c0() == c2())") // false: because c0() means c2()
println("(c0 === c1) == \(c0 === c1)")
println("(c0 === c2) == \(c0 === c2)")

এটি কেন এবং কীভাবে কাজ করে তা জানতে নীচের URL গুলি দেখুন:

আপনি দেখতে পান যে এটি কেবল পরিচয় যাচাই করতে সক্ষম (দ্বিতীয় পরীক্ষার ফলন false)। তবে এটি যথেষ্ট ভাল হওয়া উচিত।


4
এই পদ্ধতি কম্পাইলার অপ্টিমাইজেশন সঙ্গে নির্ভরযোগ্য হবে না devforums.apple.com/message/1035180#1035180
drewag

8
এটি অনির্ধারিত বাস্তবায়ন বিশদের উপর ভিত্তি করে একটি হ্যাক। তারপরে এটি ব্যবহার করার অর্থ আপনার প্রোগ্রাম একটি অপরিজ্ঞাত ফলাফল এনে দেবে।
eonil

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

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

... এবং ক্রিস ল্যাটারার ঠিক এই পদ্ধতির বিরুদ্ধে পরামর্শ করেছেন (শীর্ষের উত্তরটি দেখুন)।
পাইপ্যাক্স

4

এটি একটি দুর্দান্ত প্রশ্ন এবং ক্রিস ল্যাটনার যখন ইচ্ছাকৃতভাবে এই বৈশিষ্ট্যটি সমর্থন করতে চান না তখন আমি অনেক বিকাশকারীদের মতো অন্যান্য ভাষা থেকেও আমার অনুভূতিগুলি ছেড়ে দিতে পারি না যেখানে এটি একটি তুচ্ছ কাজ। এখানে প্রচুর unsafeBitCastউদাহরণ রয়েছে, তাদের বেশিরভাগই পুরো ছবিটি দেখায় না, এখানে আরও বিশদ বিবরণ রয়েছে :

typealias SwfBlock = () -> ()
typealias ObjBlock = @convention(block) () -> ()

func testSwfBlock(a: SwfBlock, _ b: SwfBlock) -> String {
    let objA = unsafeBitCast(a as ObjBlock, AnyObject.self)
    let objB = unsafeBitCast(b as ObjBlock, AnyObject.self)
    return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}

func testObjBlock(a: ObjBlock, _ b: ObjBlock) -> String {
    let objA = unsafeBitCast(a, AnyObject.self)
    let objB = unsafeBitCast(b, AnyObject.self)
    return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}

func testAnyBlock(a: Any?, _ b: Any?) -> String {
    if !(a is ObjBlock) || !(b is ObjBlock) {
        return "a nor b are ObjBlock, they are not equal"
    }
    let objA = unsafeBitCast(a as! ObjBlock, AnyObject.self)
    let objB = unsafeBitCast(b as! ObjBlock, AnyObject.self)
    return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)"
}

class Foo
{
    lazy var swfBlock: ObjBlock = self.swf
    func swf() { print("swf") }
    @objc func obj() { print("obj") }
}

let swfBlock: SwfBlock = { print("swf") }
let objBlock: ObjBlock = { print("obj") }
let foo: Foo = Foo()

print(testSwfBlock(swfBlock, swfBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false
print(testSwfBlock(objBlock, objBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false

print(testObjBlock(swfBlock, swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false
print(testObjBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true

print(testAnyBlock(swfBlock, swfBlock)) // a nor b are ObjBlock, they are not equal
print(testAnyBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true

print(testObjBlock(foo.swf, foo.swf)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false
print(testSwfBlock(foo.obj, foo.obj)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false
print(testAnyBlock(foo.swf, foo.swf)) // a nor b are ObjBlock, they are not equal
print(testAnyBlock(foo.swfBlock, foo.swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true

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

আমি এখনও এই পুরো বিষয়টি বুঝতে পেরেছি, তবে একটি জিনিস যা আমি ইচ্ছা করে রেখেছিলাম তা হল @convention(block)শ্রেণি / কাঠামো পদ্ধতিতে ব্যবহারের দক্ষতা , তাই আমি একটি বৈশিষ্ট্য অনুরোধ দায়ের করেছি যাতে আপ-ভোটিং প্রয়োজন বা এটি কেন খারাপ ধারণা তা ব্যাখ্যা করার জন্য request আমি একটি ধারণাও পেয়েছি যে এই পদ্ধতিটি সমস্ত একসাথে খারাপ হতে পারে, যদি তাই হয় তবে কেন কেউ ব্যাখ্যা করতে পারেন?


4
আমি কেন মনে করি না যে আপনি ক্রিস ল্যাটনার এর যুক্তিটি বুঝতে পারেন তা কেন এটি সমর্থন করে না (এবং হওয়া উচিত নয়)। "আমি একটি ধারণাও পেয়েছি যে এই পদ্ধতিটি সমস্ত একসাথে খারাপ হতে পারে, যদি তাই হয় তবে কেন কেউ ব্যাখ্যা করতে পারেন?" কারণ একটি অপ্টিমাইজড বিল্ডে, সংকলকটি বিভিন্নভাবে কোড মঙ্গলে মুক্ত যা ফাংশনগুলির পয়েন্ট সমতার ধারণা ভাঙ্গায়। একটি মৌলিক উদাহরণের জন্য, যদি কোনও ফাংশনটির দেহ একইভাবে অন্য ফাংশনটি শুরু করে, সংকলকটি সম্ভবত দুটি পৃথক প্রস্থান পয়েন্ট রেখে মেশিন কোডে দুটিকে ওভারল্যাপ করবে। এটি
আলেকজান্ডার

4
মৌলিকভাবে, ক্লোজারগুলি বেনাম শ্রেণীর অবজেক্টগুলি সূচনা করার উপায় (যেমন জাভার মতো, তবে এটি আরও স্পষ্ট।)। এই ক্লোজারগুলির অবজেক্টগুলি হ'ল বরাদ্দ, এবং ক্লোজারের দ্বারা ক্যাপচারিত ডেটা সংরক্ষণ করে, যা ক্লোজারের কার্যকরীতে অন্তর্ভুক্ত পরামিতিগুলির মতো কাজ করে। ক্লোজার অবজেক্টটি এমন কোনও ফাংশনটির একটি রেফারেন্স ধারণ করে যা স্পষ্টত (ফানক আরগগুলির মাধ্যমে) এবং অন্তর্নিহিত (ক্যাপচার বন্ধের প্রসঙ্গে) আর্গকে পরিচালনা করে। ফাংশন বডিটি একটি একক অনন্য পয়েন্ট হিসাবে ভাগ করা যায়, তবে ক্লোজার অবজেক্টের পয়েন্টারটি হতে পারে না , কারণ বদ্ধমূল্যের সেটগুলির জন্য প্রতি ক্লোজার অবজেক্ট রয়েছে।
আলেকজান্ডার

4
সুতরাং আপনি যখন Struct S { func f(_: Int) -> Bool }, আপনার আসলে টাইপ S.fআছে টাইপ একটি ফাংশন আছে (S) -> (Int) -> Bool। এই ফাংশনটি করতে ভাগ করা। এটি সম্পূর্ণরূপে এর সুস্পষ্ট পরামিতি দ্বারা প্যারামিটারাইজড। আপনি যখন এটি একটি উদাহরণ পদ্ধতি হিসাবে ব্যবহার করেন (হয় selfকোনও বস্তুর উপর পদ্ধতিটি কল দিয়ে S().fস্পষ্ট করে প্যারামিটারকে আবদ্ধ করে , উদাহরণস্বরূপ , বা স্পষ্টভাবে এটি আবদ্ধ করে, যেমন S.f(S())) আপনি একটি নতুন ক্লোজার অবজেক্ট তৈরি করেন। এই অবজেক্টটি একটি পয়েন্টার সঞ্চয় করে S.f(যা ভাগ করা যায়) , but also to your instance (স্ব , the এস () stores)।
আলেকজান্ডার

4
এই ক্লোজর অবজেক্টটি অবশ্যই প্রতিটি ক্ষেত্রে অনন্য হতে হবে S। যদি ক্লোজার পয়েন্টার সমতাটি সম্ভব হত, তবে আপনি অবাক হয়ে অবাক হবেন যে s1.fএটি একই পয়েন্টার নয় s2.f(কারণ একটি ক্লোজার অবজেক্ট যা রেফারেন্স s1এবং fঅন্যটি ক্লোজার অবজেক্ট যা রেফারেন্স s2এবং f)।
আলেকজান্ডার

এটি উজ্জ্বল, আপনাকে ধন্যবাদ! হ্যাঁ, এখনই আমার কাছে কী চলছে তার একটি ছবি ছিল এবং এটি সবকিছুকে একটি দৃষ্টিকোণে ফেলে দেয়! 👍
ইয়ান বাইচেক

4

এখানে একটি সম্ভাব্য সমাধান রয়েছে (ধারণাগতভাবে 'টিউনচে' উত্তর হিসাবে একই)। মুল বক্তব্যটি এমন কোনও শ্রেণীর সংজ্ঞা দেওয়া যা কিছু কার্যকারিতা (যেমন কমান্ড) মোড়ানো:

দ্রুত:

typealias Callback = (Any...)->Void
class Command {
    init(_ fn: @escaping Callback) {
        self.fn_ = fn
    }

    var exec : (_ args: Any...)->Void {
        get {
            return fn_
        }
    }
    var fn_ :Callback
}

let cmd1 = Command { _ in print("hello")}
let cmd2 = cmd1
let cmd3 = Command { (_ args: Any...) in
    print(args.count)
}

cmd1.exec()
cmd2.exec()
cmd3.exec(1, 2, "str")

cmd1 === cmd2 // true
cmd1 === cmd3 // false

জাভা:

interface Command {
    void exec(Object... args);
}
Command cmd1 = new Command() {
    public void exec(Object... args) [
       // do something
    }
}
Command cmd2 = cmd1;
Command cmd3 = new Command() {
   public void exec(Object... args) {
      // do something else
   }
}

cmd1 == cmd2 // true
cmd1 == cmd3 // false

আপনি যদি এটিকে জেনেরিক তৈরি করেন তবে এটি আরও ভাল।
আলেকজান্ডার

2

ঠিক ২ দিন কেটে গেছে এবং কেউই সমাধানের বিষয়ে চেষ্টা করে নি, তাই আমি আমার মন্তব্যে একটি উত্তরে পরিবর্তন করব:

আমি যতদূর বলতে পারি, আপনি সমতা বা ফাংশনগুলির পরিচয় (আপনার উদাহরণের মতো) এবং মেটাচ্লাসগুলি (যেমন, MyClass.self) পরীক্ষা করতে পারবেন না :

তবে - এবং এটি কেবল একটি ধারণা - আমি সাহায্য করতে পারছি না তবে লক্ষ্য করুন যে whereজেনেরিকের ধারাটি ধরণের ধরণের সাম্যগুলি পরীক্ষা করতে সক্ষম হয়েছে বলে মনে হয়। সুতরাং আপনি অন্তত পরিচয় যাচাই করার জন্য, যে উত্তোলন করতে পারেন?


2

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

সুতরাং এর মতো কিছু:

class OfflineManager {
    var networkChangedListeners = [String:((Bool) -> Void)]()

    func registerOnNetworkAvailabilityChangedListener(_ listener: @escaping ((Bool) -> Void)) -> String{
        let listenerId = UUID().uuidString;
        networkChangedListeners[listenerId] = listener;
        return listenerId;
    }
    func unregisterOnNetworkAvailabilityChangedListener(_ listenerId: String){
        networkChangedListeners.removeValue(forKey: listenerId);
    }
}

এখন আপনাকে কেবল key"রেজিস্টার" ফাংশন দ্বারা ফেরত সংগ্রহ করতে হবে এবং নিবন্ধনবিহীন অবস্থায় পাস করতে হবে।


0

আমার সমাধানটি ছিল ক্লাসে ফাংশন মোড়ানো যা এনএসবজেক্টকে প্রসারিত করে

class Function<Type>: NSObject {
    let value: (Type) -> Void

    init(_ function: @escaping (Type) -> Void) {
        value = function
    }
}

আপনি যখন এটি করেন, কিভাবে তাদের তুলনা করবেন? আসুন আমরা বলি যে আপনি তাদের একটিকে আপনার মোড়কের একটি অ্যারে থেকে সরাতে চান, আপনি কীভাবে এটি করেন? ধন্যবাদ
রিকার্ডো

0

আমি জানি আমি এই প্রশ্নের উত্তর ছয় বছর দেরিতে দিচ্ছি, তবে আমি মনে করি এটি প্রশ্নের পিছনে প্রেরণার দিকে তাকানো উপযুক্ত। প্রশ্নকর্তা মন্তব্য করেছেন:

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

সুতরাং আমার ধারণা, প্রশ্নকর্তা কলব্যাকের তালিকাটি বজায় রাখতে চান, এটির মতো:

class CallbackList {
    private var callbacks: [() -> ()] = []

    func call() {
        callbacks.forEach { $0() }
    }

    func addCallback(_ callback: @escaping () -> ()) {
        callbacks.append(callback)
    }

    func removeCallback(_ callback: @escaping () -> ()) {
        callbacks.removeAll(where: { $0 == callback })
    }
}

তবে আমরা removeCallbackসেভাবে লিখতে পারি না , কারণ ==ফাংশনের জন্য কাজ করে না। (না হয় ===।)

আপনার কলব্যাক তালিকা পরিচালনা করার জন্য এখানে একটি আলাদা উপায়। থেকে কোনও রেজিস্ট্রেশন অবজেক্টটি ফিরিয়ে দিন addCallbackএবং কলব্যাক সরাতে নিবন্ধকরণ অবজেক্টটি ব্যবহার করুন। এখানে ২০২০ সালে, আমরা কম্বাইনের AnyCancellableনিবন্ধকরণ হিসাবে ব্যবহার করতে পারি ।

সংশোধিত এপিআই এর মত দেখাচ্ছে:

class CallbackList {
    private var callbacks: [NSObject: () -> ()] = [:]

    func call() {
        callbacks.values.forEach { $0() }
    }

    func addCallback(_ callback: @escaping () -> ()) -> AnyCancellable {
        let key = NSObject()
        callbacks[key] = callback
        return .init { self.callbacks.removeValue(forKey: key) }
    }
}

এখন, আপনি যখন কলব্যাক যুক্ত করেন, removeCallbackপরে এটিকে পাস করার জন্য আপনার এটিকে প্রায় রাখার প্রয়োজন হয় না । কোন removeCallbackপদ্ধতি নেই। পরিবর্তে, আপনি সংরক্ষণ করুন AnyCancellable, এবং cancelকলব্যাক অপসারণ করতে এর পদ্ধতিটি কল করুন । আরও ভাল, আপনি যদি AnyCancellableকোনও উদাহরণ সম্পত্তিতে সঞ্চয় করেন তবে উদাহরণটি নষ্ট হয়ে গেলে এটি স্বয়ংক্রিয়ভাবে বাতিল হয়ে যাবে।


আমাদের এটির সর্বাধিক সাধারণ কারণ হ'ল প্রকাশকদের একাধিক গ্রাহককে পরিচালনা করা। সম্মিলন এই সমস্ত কিছু ছাড়াই সমাধান করে। সি # যা মঞ্জুরি দেয় এবং সুইফট তা দেয় না তা হ'ল দুটি ক্লোজার একই নামকৃত ফাংশনটিকে রেফারেন্স করে কিনা। এটি দরকারী, তবে প্রায়শই কম।
জেসি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.