প্রোটোকলগুলি অ্যারে প্রকার হিসাবে এবং সুইফটে ফাংশন পরামিতিগুলির ব্যবহার


136

আমি এমন একটি শ্রেণি তৈরি করতে চাই যা নির্দিষ্ট প্রোটোকলের সাথে সঙ্গতিপূর্ণ অবজেক্টগুলিকে সঞ্চয় করতে পারে। বস্তুগুলি একটি টাইপযুক্ত অ্যারেতে সংরক্ষণ করা উচিত। সুইফ্ট ডকুমেন্টেশন অনুযায়ী প্রোটোকল প্রকার হিসাবে ব্যবহার করা যেতে পারে: 

কারণ এটি একটি প্রকার, আপনি এমন অনেক জায়গায় প্রোটোকল ব্যবহার করতে পারেন যেখানে অন্যান্য ধরণের অনুমতি রয়েছে, সহ:

  • কোনও ফাংশন, পদ্ধতি বা ইনিশিয়ালাইজারে প্যারামিটারের ধরন বা রিটার্নের ধরণ হিসাবে
  • ধ্রুবক, পরিবর্তনশীল বা সম্পত্তির ধরণ হিসাবে
  • অ্যারে, অভিধান বা অন্য ধারকটিতে আইটেমের ধরণ হিসাবে

তবে নিম্নলিখিতটি সংকলক ত্রুটিগুলি উত্পন্ন করে:

প্রোটোকল 'সোমপ্রোটোকল' কেবল জেনেরিক সীমাবদ্ধতা হিসাবে ব্যবহার করা যেতে পারে কারণ এতে স্ব বা সম্পর্কিত সম্পর্কিত প্রয়োজনীয়তা রয়েছে

আপনি কীভাবে এটি সমাধান করবেন?

protocol SomeProtocol: Equatable {
    func bla()
}

class SomeClass {
    
    var protocols = [SomeProtocol]()
    
    func addElement(element: SomeProtocol) {
        self.protocols.append(element)
    }
    
    func removeElement(element: SomeProtocol) {
        if let index = find(self.protocols, element) {
            self.protocols.removeAtIndex(index)
        }
    }
}

2
সুইফটে একটি বিশেষ শ্রেণীর প্রোটোকল রয়েছে যা এটি প্রয়োগ করে এমন ধরণের উপর দিয়ে বহুবিজ্ঞান সরবরাহ করে না। এই জাতীয় প্রোটোকলগুলি তার সংজ্ঞায় স্ব বা সংযুক্তপ্রকার ব্যবহার করে (এবং এর মধ্যে একটি সমতুল্য)। কিছু ক্ষেত্রে আপনার সংগ্রহকে হোমোমোরফিক তৈরি করতে টাইপ-মোছা মোড়ক ব্যবহার করা সম্ভব। উদাহরণস্বরূপ এখানে দেখুন ।
ওয়েডাইভার

উত্তর:


48

আপনি সুইফটে প্রোটোকল নিয়ে সমস্যার বিভিন্ন রূপ পেয়েছেন যার জন্য এখনও কোনও ভাল সমাধানের উপস্থিতি নেই।

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


1
আমি মনে করি এটি এই মুহুর্তের সঠিক উত্তর। নেটের সমাধান কাজ করছে তবে আমার সমস্যা পুরোপুরি সমাধান করে না।
স্নোড করুন

32

আপনি একটি জেনেরিক ক্লাস তৈরি করতে চান, এমন ধরণের সীমাবদ্ধতার সাথে যার সাথে ব্যবহৃত ক্লাসগুলির সাথে এটি মেনে চলতে হবে SomeProtocol:

class SomeClass<T: SomeProtocol> {
    typealias ElementType = T
    var protocols = [ElementType]()

    func addElement(element: ElementType) {
        self.protocols.append(element)
    }

    func removeElement(element: ElementType) {
        if let index = find(self.protocols, element) {
            self.protocols.removeAtIndex(index)
        }
    }
}

আপনি কীভাবে এই শ্রেণীর কোনও অবজেক্ট ইনস্ট্যান্ট করবেন?
স্নড করুন

হুমম ... এইভাবে আপনাকে একক প্রকারের সাথে SomeProtocollet protocolGroup: SomeClass<MyMemberClass> = SomeClass()
নেট কুক

এইভাবে আপনি কেবল MyMemberClassঅ্যারেতে শ্রেণীর অবজেক্টগুলি যুক্ত করতে পারেন ?
14-18 এ স্নোড করুন

বাlet foo = SomeClass<MyMemberClass>()
ডার্কডাস্ট

@ স্নোদ হ্যাঁ, যা আপনি খুঁজছেন তা নয়। সমস্যাটি Equatableসামঞ্জস্যপূর্ণ - এটি ছাড়া আপনি আপনার সঠিক কোডটি ব্যবহার করতে পারেন। সম্ভবত একটি বাগ / বৈশিষ্ট্য অনুরোধ ফাইল করবেন?
নেট কুক

15

সুইফটে একটি বিশেষ শ্রেণীর প্রোটোকল রয়েছে যা এটি প্রয়োগ করে এমন ধরণের উপর দিয়ে বহুবিজ্ঞান সরবরাহ করে না। এই ধরনের প্রোটোকল ব্যবহার Selfবা associatedtypeকিওয়ার্ড সংজ্ঞাইত (এবং Equatableতাদের একজন)।

কিছু ক্ষেত্রে আপনার সংগ্রহকে হোমোমোরফিক তৈরি করতে টাইপ-মোছা মোড়ক ব্যবহার করা সম্ভব। নীচে একটি উদাহরণ দেওয়া আছে।

// This protocol doesn't provide polymorphism over the types which implement it.
protocol X: Equatable {
    var x: Int { get }
}

// We can't use such protocols as types, only as generic-constraints.
func ==<T: X>(a: T, b: T) -> Bool {
    return a.x == b.x
}

// A type-erased wrapper can help overcome this limitation in some cases.
struct AnyX {
    private let _x: () -> Int
    var x: Int { return _x() }

    init<T: X>(_ some: T) {
        _x = { some.x }
    }
}

// Usage Example

struct XY: X {
    var x: Int
    var y: Int
}

struct XZ: X {
    var x: Int
    var z: Int
}

let xy = XY(x: 1, y: 2)
let xz = XZ(x: 3, z: 4)

//let xs = [xy, xz] // error
let xs = [AnyX(xy), AnyX(xz)]
xs.forEach { print($0.x) } // 1 3

12

আমি যে সীমাবদ্ধ সমাধানটি পেয়েছি তা হ'ল প্রোটোকলটিকে কেবলমাত্র ক্লাস-কেবল প্রোটোকল হিসাবে চিহ্নিত করা। এটি আপনাকে '===' অপারেটর ব্যবহার করে বস্তুর তুলনা করতে অনুমতি দেবে। আমি বুঝতে পারি এটি স্ট্রাক ইত্যাদির জন্য কাজ করবে না, তবে এটি আমার ক্ষেত্রে যথেষ্ট ভাল ছিল।

protocol SomeProtocol: class {
    func bla()
}

class SomeClass {

    var protocols = [SomeProtocol]()

    func addElement(element: SomeProtocol) {
        self.protocols.append(element)
    }

    func removeElement(element: SomeProtocol) {
        for i in 0...protocols.count {
            if protocols[i] === element {
                protocols.removeAtIndex(i)
                return
            }
        }
    }

}

protocolsযদি addElementএকই বস্তুটির সাথে একাধিকবার বলা হয় তবে এটি কি সদৃশ প্রবেশগুলিতে মঞ্জুরি দেয় না ?
টম হ্যারিংটন

হ্যাঁ, দ্রুতগামী অ্যারেগুলিতে সদৃশ এন্ট্রি থাকতে পারে। আপনি যদি ভাবেন যে এটি আপনার কোডে ঘটতে পারে, তবে হয় অ্যারের পরিবর্তে সেট ব্যবহার করুন, বা নিশ্চিত করুন যে অ্যারেটিতে ইতিমধ্যে অবজেক্টটি নেই।
আলমাস

আপনি removeElement()যদি নকলগুলি এড়াতে চান তবে আপনি নতুন উপাদান সংযোজন করার আগে কল করতে পারেন।
জর্জিওস

আমি বলতে চাইছি আপনি কীভাবে আপনার অ্যারে নিয়ন্ত্রণ করছেন বাতাসে আছে, তাই না? উত্তরের জন্য আপনাকে ধন্যবাদ
রেমন্ড হিল

9

সমাধানটি বেশ সহজ:

protocol SomeProtocol {
    func bla()
}

class SomeClass {
    init() {}

    var protocols = [SomeProtocol]()

    func addElement<T: SomeProtocol where T: Equatable>(element: T) {
        protocols.append(element)
    }

    func removeElement<T: SomeProtocol where T: Equatable>(element: T) {
        protocols = protocols.filter {
            if let e = $0 as? T where e == element {
                return false
            }
            return true
        }
    }
}

4
আপনি গুরুত্বপূর্ণ জিনিসটি মিস করেছেন: ওপি প্রোটোকলটি প্রোটোকলের উত্তরাধিকার সূত্রে চায় Equatable। এটি বিশাল পার্থক্য করে।
ওয়েডাইভার 13

@ উত্তরদাতা আমাকে এমনটা মনে হয় না তিনি SomeProtocolটাইপ করা অ্যারে অনুসারে অবজেক্টগুলি সঞ্চয় করতে চান । Equatableকনফারেন্স কেবল অ্যারে থেকে উপাদানগুলি অপসারণের জন্য প্রয়োজন। আমার সমাধানটি @almas সমাধানের একটি উন্নত সংস্করণ কারণ এটি Equatableপ্রোটোকলের সাথে সঙ্গতিপূর্ণ যে কোনও সুইফট টাইপের সাথে ব্যবহার করা যেতে পারে ।
বিজেড

2

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

যেহেতু যাই হোক না কেন, আপনার আপত্তিগুলি পৃথক করতে আপনার কিছু পৃথক সম্পত্তি প্রয়োজন, আমি ধরে নিয়েছি এটি "নাম"। আপনি যখন একটি নতুন সোমপ্রোটোকল দৃষ্টান্ত তৈরি করবেন তখন দয়া করে তা নিশ্চিত করুন যে আপনার do عنصرের নাম = "foo"। যদি নামটি সেট না করা থাকে, আপনি এখনও উদাহরণটি তৈরি করতে পারেন তবে এটি সংগ্রহের সাথে যুক্ত হবে না এবং অ্যাডিমেন্ট () "মিথ্যা" প্রত্যাবর্তন করবে।

protocol SomeProtocol {
    var name:String? {get set} // Since elements need to distinguished, 
    //we will assume it is by name in this example.
    func bla()
}

class SomeClass {

    //var protocols = [SomeProtocol]() //find is not supported in 2.0, indexOf if
     // There is an Obj-C function index, that find element using custom comparator such as the one below, not available in Swift
    /*
    static func compareProtocols(one:SomeProtocol, toTheOther:SomeProtocol)->Bool {
        if (one.name == nil) {return false}
        if(toTheOther.name == nil) {return false}
        if(one.name ==  toTheOther.name!) {return true}
        return false
    }
   */

    //The best choice here is to use dictionary
    var protocols = [String:SomeProtocol]()


    func addElement(element: SomeProtocol) -> Bool {
        //self.protocols.append(element)
        if let index = element.name {
            protocols[index] = element
            return true
        }
        return false
    }

    func removeElement(element: SomeProtocol) {
        //if let index = find(self.protocols, element) { // find not suported in Swift 2.0


        if let index = element.name {
            protocols.removeValueForKey(index)
        }
    }

    func getElements() -> [SomeProtocol] {
        return Array(protocols.values)
    }
}

0

আমি একটি পাওয়া না যে ব্লগ পোস্টে বিশুদ্ধ-বিশুদ্ধ সুইফট সমাধান: http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/

কৌশলটি NSObjectProtocolএটি পরিচিত হিসাবে মেনে চলতে হয় isEqual()। অতএব Equatableপ্রোটোকল এবং এর ডিফল্ট ব্যবহার ব্যবহারের পরিবর্তে ==উপাদানটি খুঁজে পেতে এবং এটি সরাতে আপনার নিজের ফাংশনটি লিখতে পারে।

আপনার find(array, element) -> Int?ফাংশন বাস্তবায়ন এখানে :

protocol SomeProtocol: NSObjectProtocol {

}

func find(protocols: [SomeProtocol], element: SomeProtocol) -> Int? {
    for (index, object) in protocols.enumerated() {
        if (object.isEqual(element)) {
            return index
        }
    }

    return nil
}

দ্রষ্টব্য: এই ক্ষেত্রে আপনার অবজেক্টগুলি SomeProtocolঅবশ্যই উত্তরাধিকার সূত্রে প্রাপ্ত হতে হবে NSObject

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