আমি কীভাবে সুইফটে দুর্বল উল্লেখগুলির একটি অ্যারে ঘোষণা করব?


179

আমি সুইফটে দুর্বল উল্লেখগুলির একটি অ্যারে সঞ্চয় করতে চাই। অ্যারে নিজেই দুর্বল রেফারেন্স হওয়া উচিত নয় - এর উপাদানগুলি হওয়া উচিত। আমি মনে করি কোকো NSPointerArrayএটির একটি নন-টাইপসেজ সংস্করণ সরবরাহ করে।


1
এমন একটি ধারক বস্তু তৈরির বিষয়ে কী যা দুর্বলভাবে অন্য কোনও বস্তুর উল্লেখ করে, তারপরে একটি অ্যারে তৈরি করে? (যদি আপনি এর চেয়ে ভাল উত্তর না পান)
নিলসবট

1
আপনি এনএসপয়েন্টারআরে ব্যবহার করবেন না কেন?
বাসটিয়ান

@nielsbot এটি একটি পুরানো অবজেক্ট-সি সমাধান :) এটিকে সুইফটি করার জন্য এটি জেনেরিক বস্তু হওয়া উচিত! :) তবে, আসল সমস্যা হ'ল রেফারেন্সযুক্ত অবজেক্টটি সরিয়ে ফেলা হলে অ্যারে থেকে কীভাবে অবজেক্টগুলি সরিয়ে ফেলা যায়।
সুলতান

2
ঠিক আছে, আমি প্যারামিটারাইজড ধরণের কিছু পছন্দ করব। আমি অনুমান করি যে আমি এনএসপয়েন্টারআরেয়ের চারপাশে একটি প্যারামিটারাইজড মোড়ক তৈরি করতে পারতাম, তবে কোনও বিকল্প আছে কিনা তা দেখতে চেয়েছিলাম।
বিল

6
অন্য একটি বিকল্প হিসাবে, এনএসএইচএসটিবল বিদ্যমান। এটি মূলত একটি এনএসএসেট যা আপনাকে এতে অন্তর্ভুক্ত অবজেক্টগুলিকে কীভাবে রেফারেন্স করতে হবে তা নির্দিষ্ট করতে দেয়।
মিক ম্যাককালাম

উত্তর:


154

একটি জেনেরিক মোড়ক তৈরি করুন:

class Weak<T: AnyObject> {
  weak var value : T?
  init (value: T) {
    self.value = value
  }
}

আপনার অ্যারেতে এই শ্রেণীর উদাহরণগুলি যুক্ত করুন।

class Stuff {}
var weakly : [Weak<Stuff>] = [Weak(value: Stuff()), Weak(value: Stuff())]

সংজ্ঞা দেওয়ার সময় Weakআপনি structবা ব্যবহার করতে পারেন class

এছাড়াও, অ্যারের সামগ্রীগুলি কাটাতে সহায়তা করতে আপনি এর লাইন ধরে কিছু করতে পারেন:

extension Array where Element:Weak<AnyObject> {
  mutating func reap () {
    self = self.filter { nil != $0.value }
  }
}

AnyObjectউপরের ব্যবহারটি প্রতিস্থাপন করা উচিত T- তবে আমি মনে করি না বর্তমান সুইফট ভাষাটি এরূপ হিসাবে সংজ্ঞায়িত কোনও এক্সটেনশনের অনুমতি দেয়।


11
আপনি যখন অ্যারে থেকে মোড়কের জিনিসগুলি অপসারণ করবেন যখন তাদের মান হ্রাস করা হয়?
সুলতান

9
হ্যাঁ, এটি সংকলক ক্র্যাশ করেছে।
GoZoner

5
একটি নতুন প্রশ্নে আপনার সমস্যা কোড পোস্ট করুন; আমার উত্তরটি ডাইং করার কোনও কারণ নেই যখন এটি আপনার কোড হতে পারে!
GoZoner

2
@ এডগ্যাম্বল প্রদত্ত কোডটি যেমন হয় তেমন কাজ করে তবে আপনি যদি Stuffপ্রোটোকল দ্বারা ক্লাসটি প্রতিস্থাপন করেন তবে ব্যর্থ হয়; দেখতে এই সম্পর্কিত প্রশ্ন
থিও

2
একটি কাঠামো আরও ভাল হবে, কারণ এটি একটি গাদা আনার পরিবর্তে স্ট্যাকের উপর রাখা হবে।
কেপিএম

60

আপনি দুর্বল ওবজেক্টস হ্যাশ টেবিলের সাথে এনএসএইচএসটিবল ব্যবহার করতে পারেন। NSHashTable<ObjectType>.weakObjectsHashTable()

সুইফ্ট 3 এর জন্য: NSHashTable<ObjectType>.weakObjects()

NSHashTable শ্রেণির রেফারেন্স

ওএস এক্স ভি 10.5 এবং তার পরে পাওয়া যায়।

আইওএস 6.0 এবং তার পরে পাওয়া যায়।


সেরা উত্তর এবং মোড়কের জন্য কোমর করবেন না!
রামিস

1
এটি চতুর, তবে GoZoner এর উত্তরের মতো, এটি প্রোটোকলের মতো Anyনয় তবে নয় এমন ধরণের সাথে কাজ করে না AnyObject
অ্যারন ব্র্যাজার

@ স্টিভিলফোর্ড তবে একটি প্রোটোকল একটি শ্রেণীর দ্বারা প্রয়োগ করা যেতে পারে, যা এটি একটি রেফারেন্স টাইপ হিসাবে তৈরি করবে
অ্যারন ব্র্যাজার

4
একটি প্রোটোকল শ্রেণি প্রসারিত করতে পারে এবং তারপরে আপনি এটি দুর্বল হিসাবে ব্যবহার করতে পারেন (যেমন প্রোটোকল মাইপ্রোটোকল: শ্রেণি)
ইয়াসমিন টিওমকিন

1
আমি MyProtocol: classএবং এর সাথে একটি সংকলক ত্রুটি পেয়েছি NSHashTable<MyProtocol>.weakObjects()। "'এনএস হ্যাশ টেবিল' এর জন্য 'মাইপ্রোটোকল' শ্রেণির ধরণের হওয়া দরকার
গ্রেগ

14

পার্টির জন্য এটি একদম দেরি, তবে আমার চেষ্টা করুন। আমি সেট না করে অ্যারে হিসাবে প্রয়োগ করেছি।

WeakObjectSet

class WeakObject<T: AnyObject>: Equatable, Hashable {
    weak var object: T?
    init(object: T) {
        self.object = object
    }

    var hashValue: Int {
        if let object = self.object { return unsafeAddressOf(object).hashValue }
        else { return 0 }
    }
}

func == <T> (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
    return lhs.object === rhs.object
}


class WeakObjectSet<T: AnyObject> {
    var objects: Set<WeakObject<T>>

    init() {
        self.objects = Set<WeakObject<T>>([])
    }

    init(objects: [T]) {
        self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
    }

    var allObjects: [T] {
        return objects.flatMap { $0.object }
    }

    func contains(object: T) -> Bool {
        return self.objects.contains(WeakObject(object: object))
    }

    func addObject(object: T) {
        self.objects.unionInPlace([WeakObject(object: object)])
    }

    func addObjects(objects: [T]) {
        self.objects.unionInPlace(objects.map { WeakObject(object: $0) })
    }
}

ব্যবহার

var alice: NSString? = "Alice"
var bob: NSString? = "Bob"
var cathline: NSString? = "Cathline"

var persons = WeakObjectSet<NSString>()
persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObjects([alice!, cathline!])
print(persons.allObjects) // [Alice, Cathline, Bob]

alice = nil
print(persons.allObjects) // [Cathline, Bob]

bob = nil
print(persons.allObjects) // [Cathline]

সাবধান থাকুন যে WeakObjectSet স্ট্রিং টাইপটি গ্রহণ করবে না তবে এনএসএসস্ট্রিং। কারণ, স্ট্রিং টাইপটি কোনও টাইপ নয়। আমার সুইফ্ট ভার্সনটি হ'ল Apple Swift version 2.2 (swiftlang-703.0.18.1 clang-703.0.29)

কোডটি জিস্টের কাছ থেকে ধরা যেতে পারে। https://gist.github.com/codelynx/30d3c42a833321f17d39

** NOV.2017 এ যুক্ত 7

আমি কোডটি সুইফট 4 এ আপডেট করেছি

// Swift 4, Xcode Version 9.1 (9B55)

class WeakObject<T: AnyObject>: Equatable, Hashable {
    weak var object: T?
    init(object: T) {
        self.object = object
    }

    var hashValue: Int {
        if var object = object { return UnsafeMutablePointer<T>(&object).hashValue }
        return 0
    }

    static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
        return lhs.object === rhs.object
    }
}

class WeakObjectSet<T: AnyObject> {
    var objects: Set<WeakObject<T>>

    init() {
        self.objects = Set<WeakObject<T>>([])
    }

    init(objects: [T]) {
        self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
    }

    var allObjects: [T] {
        return objects.flatMap { $0.object }
    }

    func contains(_ object: T) -> Bool {
        return self.objects.contains(WeakObject(object: object))
    }

    func addObject(_ object: T) {
        self.objects.formUnion([WeakObject(object: object)])
    }

    func addObjects(_ objects: [T]) {
        self.objects.formUnion(objects.map { WeakObject(object: $0) })
    }
}

গোকজি যেমন উল্লেখ করেছেন, আমি বুঝতে পেরেছি যে এনএসএসস্ট্রিং ব্যবহারের কোডের ভিত্তিতে বিঘ্নিত হবে না। আমি আমার মাথা স্ক্র্যাচ করেছি এবং আমি মাই স্ট্রিং ক্লাসটি নীচে লিখেছি।

// typealias MyString = NSString
class MyString: CustomStringConvertible {
    var string: String
    init(string: String) {
        self.string = string
    }
    deinit {
        print("relasing: \(string)")
    }
    var description: String {
        return self.string
    }
}

তারপর প্রতিস্থাপন NSStringসঙ্গে MyStringভালো। তারপরে অদ্ভুতভাবে এটি কাজ করে।

var alice: MyString? = MyString(string: "Alice")
var bob: MyString? = MyString(string: "Bob")
var cathline: MyString? = MyString(string: "Cathline")

var persons = WeakObjectSet<MyString>()

persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObject(bob!)
print(persons.allObjects) // [Bob]

persons.addObjects([alice!, cathline!])
print(persons.allObjects) // [Alice, Cathline, Bob]

alice = nil
print(persons.allObjects) // [Cathline, Bob]

bob = nil
print(persons.allObjects) // [Cathline]

তখন আমি খুঁজে পেলাম একটি অদ্ভুত পৃষ্ঠা এই সমস্যাটির সাথে সম্পর্কিত হতে পারে।

দুর্বল রেফারেন্সটি dellocated NSString ধরে রাখে (এক্সসি 9 + আইওএস সিম কেবল)

https://bugs.swift.org/browse/SR-5511

এটি বলছে যে সমস্যাটি RESOLVEDকিন্তু আমি এখনও ভাবছি যে এটি এখনও এই সমস্যার সাথে সম্পর্কিত কিনা। যাইহোক, মাইস্ট্রিং বা এনএসএস স্ট্রিংয়ের মধ্যে আচরণগত পার্থক্যগুলি এই প্রসঙ্গে নয়, তবে কেউ যদি এই বিষয়টি খুঁজে পেয়ে থাকে তবে আমি প্রশংসা করব।


আমি আমার প্রকল্পের জন্য এই সমাধানটি গ্রহণ করেছি। দারূন কাজ! কেবল একটি পরামর্শ, এই সমাধানটি nilঅভ্যন্তরীণ থেকে মানগুলি সরিয়ে ফেলবে বলে মনে হয় না Set। সুতরাং আমি reap()শীর্ষের উত্তরে উল্লিখিত একটি ফাংশন যুক্ত করেছি এবং reap()যতবার WeakObjectSetঅ্যাক্সেস করা হবে ততবার কল করা নিশ্চিত করেছি ।
gokeji

হুম অপেক্ষা করুন, কোনও কারণে এটি সুইফট 4 / আইওএস 11 তে কাজ করে না 11 মনে হচ্ছে দুর্বল উল্লেখটি যখন মানটি হয়ে যায় ঠিক তখনই তা হ্রাস পাবে nilনা
gokeji

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

@ কাজযোশিকাওয়া এটি দেখার জন্য, এবং উত্তরটি আপডেট করার জন্য আপনাকে অনেক ধন্যবাদ! আমি পরে বুঝতে পারি যে একটি কাস্টম ক্লাস কাজ করে, যেখানে NSStringহয় না।
gokeji

2
আমি অভিজ্ঞতাটি দিয়েছি যে যে পয়েন্টারটি ফিরে এসেছে তা UnsafeMutablePointer<T>(&object)এলোমেলোভাবে পরিবর্তিত হতে পারে (এর সাথে একই withUnsafePointer)। আমি এখন একটি সংস্করণ দ্বারা একটি ব্যাক ব্যবহার NSHashTable: gist.github.com/simonseyer/cf73e733355501405982042f760d2a7d
সিমোনসিয়ার

12

এটি আমার সমাধান নয়। আমি এটি অ্যাপল বিকাশকারী ফোরামে পেয়েছি

@ গুজোনারের একটি ভাল উত্তর রয়েছে তবে এটি সুইফ্ট সংকলকটি ক্র্যাশ করেছে।

এখানে দুর্বল-অবজেক্ট কনটেইনারটির একটি সংস্করণ বর্তমান প্রকাশিত সংকলক ক্রাশ হয় না।

struct WeakContainer<T where T: AnyObject> {
    weak var _value : T?

    init (value: T) {
        _value = value
    }

    func get() -> T? {
        return _value
    }
}

তারপরে আপনি এই ধারকগুলির একটি অ্যারে তৈরি করতে পারেন:

let myArray: Array<WeakContainer<MyClass>> = [myObject1, myObject2]

1
আজব, তবে আর স্ট্রাক্ট নিয়ে কাজ করে না। EXC_BAD_ACCESSআমার জন্য বলে । বর্গ সঙ্গে মাত্র কাজ করে জরিমানা
mente

6
স্ট্রাক্টগুলি মান ধরণের, এটি তাদের সাথে কাজ করা উচিত নয়। এটি সংকলন-সময় ত্রুটি হওয়ার পরিবর্তে রানটাইমের সময় ক্র্যাশ হয়ে গেছে এটি একটি সংকলক বাগ।
ডেভিড গুডাইন

10

আপনি দুর্বল পয়েন্টার ধরে রাখতে একটি মোড়কের বস্তু তৈরি করে এটি করতে পারেন।

struct WeakThing<T: AnyObject> {
  weak var value: T?
  init (value: T) {
    self.value = value
  }
}

এবং তারপরে অ্যারে ব্যবহার করে

var weakThings = WeakThing<Foo>[]()

বারগুলি classব্যবহারের জন্য হতে হবেweak
বিল

3
বল কে? উপরের কোডটি আমার পক্ষে কাজ করে। কেবলমাত্র প্রয়োজনটি হ'ল দুর্বল হয়ে যাওয়া বস্তুর একটি শ্রেণি হওয়া দরকার, দুর্বল রেফারেন্সটি ধারণ করে রাখা বস্তুটি নয়
জোশুয়া ওয়েইনবার্গ

দুঃখিত। আমি শপথ করতে পারি আমি সবেমাত্র একটি সংকলক বার্তা পেয়েছি যাতে বলা হয়েছে "স্ট্রাক্টগুলিতে দুর্বল ভেরিয়েবল ব্যবহার করা যায় না"। আপনি সঠিক - এটি সংকলন করে।
বিল

5
@ জোশুয়াউইনবার্গ যদি ফু প্রোটোকল হয় তবে কি হবে?
onmyway133

@ onmyway133 AFAIK যদি প্রোটোকলটি কেবল শ্রেণি দ্বারা প্রয়োগ করা হয় বলে ঘোষণা করা হয় তবে তা কার্যকর হবে। protocol Protocol : class { ... }
ওলেজনাক

8

ফাংশনাল স্টাইল র‌্যাপার সম্পর্কে কীভাবে?

class Class1 {}

func captureWeakly<T> (_ target:T) -> (() -> T?) where T: AnyObject {
    return { [weak target] in
        return target
    }
}

let obj1 = Class1()
let obj2 = Class1()
let obj3 = Class1()
let captured1 = captureWeakly(obj1)
let captured2 = captureWeakly(obj2)
let captured3 = captureWeakly(obj3)

লক্ষ্যটি যাচাই করতে কেবল কলটি রিটার্ন ক্লোজার এখনও বেঁচে আছে।

let isAlive = captured1() != nil
let theValue = captured1()!

এবং আপনি এই ক্লোজারগুলি একটি অ্যারেতে সঞ্চয় করতে পারেন।

let array1 = Array<() -> (Class1?)>([captured1, captured2, captured3])

এবং আপনি ক্লোজারগুলিকে ম্যাপিংয়ের মাধ্যমে দুর্বলভাবে ক্যাপচারিত মানগুলি পুনরুদ্ধার করতে পারেন।

let values = Array(array1.map({ $0() }))

আসলে, বন্ধ করার জন্য আপনার কোনও ক্রিয়াকলাপের দরকার নেই। কেবল কোনও অবজেক্টকে সরাসরি ক্যাপচার করুন।

let captured3 = { [weak obj3] in return obj3 }

3
প্রশ্নটি কীভাবে দুর্বল অবজেক্টগুলির একটি অ্যারে (বা সেট বলুন) তৈরি করবেন।
ডেভিড এইচ

এই সমাধানের সাহায্যে আপনি এমনকি একাধিক মান সহ একটি অ্যারে তৈরি করতে পারেন var array: [(x: Int, y: () -> T?)]। ঠিক আমি খুঁজছেন ছিল কি.
jboi

1
@ ডেভিড এই প্রশ্নের উত্তর দেওয়ার জন্য আমি আমার উত্তর আপডেট করেছি। আশা করি এটা কাজে লাগবে.
eonil

আমি এই পদ্ধতিটি পছন্দ করেছিলাম এবং আমি মনে করি এটি অত্যন্ত চালাক। আমি এই কৌশলটি ব্যবহার করে একটি শ্রেণি বাস্তবায়ন করেছি। ধন্যবাদ!
আলে রাবাসিও

সম্পর্কে খুব নিশ্চিত না let values = Array(array1.map({ $0() })) part। যেহেতু এটি দুর্বল রেফারেন্স সহ বন্ধের অ্যারে আর নেই, এই অ্যারেটি অবনমিত না হওয়া পর্যন্ত মানগুলি বজায় থাকবে। আমি যদি সঠিক হয়ে থাকি তবে এটি লক্ষ্য করা জরুরী যে আপনি কখনই এই অ্যারেটি ধরে রাখবেন না self.items = Array(array1.map({ $0() }))কারণ এটি উদ্দেশ্যটিকে আঘাত করে।
ম্যাটিক ওব্লাক

7

জেনেরিকগুলি সহ দুর্বল ধারক তৈরি করার জন্য আমার একই ধারণা ছিল।
ফলস্বরূপ আমি এর জন্য মোড়ক তৈরি করেছি NSHashTable:

class WeakSet<ObjectType>: SequenceType {

    var count: Int {
        return weakStorage.count
    }

    private let weakStorage = NSHashTable.weakObjectsHashTable()

    func addObject(object: ObjectType) {
        guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
        weakStorage.addObject(object as? AnyObject)
    }

    func removeObject(object: ObjectType) {
        guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
        weakStorage.removeObject(object as? AnyObject)
    }

    func removeAllObjects() {
        weakStorage.removeAllObjects()
    }

    func containsObject(object: ObjectType) -> Bool {
        guard object is AnyObject else { fatalError("Object (\(object)) should be subclass of AnyObject") }
        return weakStorage.containsObject(object as? AnyObject)
    }

    func generate() -> AnyGenerator<ObjectType> {
        let enumerator = weakStorage.objectEnumerator()
        return anyGenerator {
            return enumerator.nextObject() as! ObjectType?
        }
    }
}

ব্যবহার:

protocol MyDelegate : AnyObject {
    func doWork()
}

class MyClass: AnyObject, MyDelegate {
    fun doWork() {
        // Do delegated work.
    }
}

var delegates = WeakSet<MyDelegate>()
delegates.addObject(MyClass())

for delegate in delegates {
    delegate.doWork()
}

এটি সর্বোত্তম সমাধান নয়, কারণ যে WeakSetকোনও প্রকারের সাথে আরম্ভ করা যেতে পারে, এবং যদি এই ধরণের সাথে সামঞ্জস্য হয় নাAnyObject প্রোটোকলের তবে অ্যাপ্লিকেশন বিস্তারিত কারণে ক্রাশ হবে। তবে আমি এখনই এর চেয়ে ভাল সমাধান দেখতে পাচ্ছি না।

আসল সমাধানটি এইভাবে সংজ্ঞায়িত করা ছিল WeakSet:

class WeakSet<ObjectType: AnyObject>: SequenceType {}

তবে WeakSetএক্ষেত্রে প্রোটোকল দিয়ে আরম্ভ করা যাবে না:

protocol MyDelegate : AnyObject {
    func doWork()
}

let weakSet = WeakSet<MyDelegate>()

বর্তমানে উপরের কোডটি সংকলন করা যায় না (সুইফট ২.১, এক্সকোড .1.১)
এজন্য আমি মেনে চললাম AnyObjectএবং জোর দিয়ে অতিরিক্ত গার্ড যুক্ত করেছি fatalError()



6

বিস্তারিত

  • সুইফ্ট 5.1, এক্সকোড 11.3.1

সমাধান

struct WeakObject<Object: AnyObject> { weak var object: Object? }

বিকল্প 1

@propertyWrapper
struct WeakElements<Collect, Element> where Collect: RangeReplaceableCollection, Collect.Element == Optional<Element>, Element: AnyObject {
    private var weakObjects = [WeakObject<Element>]()

    init(wrappedValue value: Collect) { save(collection: value) }

    private mutating func save(collection: Collect) {
        weakObjects = collection.map { WeakObject(object: $0) }
    }

    var wrappedValue: Collect {
        get { Collect(weakObjects.map { $0.object }) }
        set (newValues) { save(collection: newValues) }
    }
}

বিকল্প 1 ব্যবহার

class Class1 { // or struct
    @WeakElements var weakObjectsArray = [UIView?]() // Use like regular array. With any objects

    func test() {
        weakObjectsArray.append(UIView())
        weakObjectsArray.forEach { print($0) }
    }
}

বিকল্প 2

struct WeakObjectsArray<Object> where Object: AnyObject {
    private var weakObjects = [WeakObject<Object>]()
}

extension WeakObjectsArray {
    typealias SubSequence = WeakObjectsArray<Object>
    typealias Element = Optional<Object>
    typealias Index = Int
    var startIndex: Index { weakObjects.startIndex }
    var endIndex: Index { weakObjects.endIndex }
    func index(after i: Index) -> Index { weakObjects.index(after: i) }
    subscript(position: Index) -> Element {
        get { weakObjects[position].object }
        set (newValue) { weakObjects[position] = WeakObject(object: newValue) }
    }
    var count: Int { return weakObjects.count }
    var isEmpty: Bool { return weakObjects.isEmpty }
}

extension WeakObjectsArray: RangeReplaceableCollection {
    mutating func replaceSubrange<C : Collection>( _ subrange: Range<Index>, with newElements: C) where Element == C.Element {
        weakObjects.replaceSubrange(subrange, with: newElements.map { WeakObject(object: $0) })
    }
}

বিকল্প 2 ব্যবহার

class Class2 { // or struct
    var weakObjectsArray = WeakObjectsArray<UIView>() // Use like regular array. With any objects

    func test() {
        weakObjectsArray.append(UIView())
        weakObjectsArray.forEach { print($0) }
    }
}

সম্পূর্ণ নমুনা

সমাধান কোড পেস্ট করতে ভুলবেন না

import UIKit

class ViewController: UIViewController {

    @WeakElements var weakObjectsArray = [UIView?]()
    //var weakObjectsArray = WeakObjectsArray<UIView>()

    override func viewDidLoad() {
        super.viewDidLoad()
        addSubviews()
    }

    private func printArray(title: String) {
        DispatchQueue.main.async {
            print("=============================\n\(title)\ncount: \(self.weakObjectsArray.count)")
            self.weakObjectsArray.enumerated().forEach { print("\($0) \(String(describing: $1))") }
        }
    }
}

extension ViewController {

    private func createRandomRectangleAndAdd(to parentView: UIView) -> UIView {
        let view = UIView(frame: CGRect(x: Int.random(in: 0...200),
                                        y: Int.random(in: 60...200),
                                        width: Int.random(in: 0...200),
                                        height: Int.random(in: 0...200)))
        let color = UIColor(red: CGFloat.random(in: 0...255)/255,
                            green: CGFloat.random(in: 0...255)/255,
                            blue: CGFloat.random(in: 0...255)/255,
                            alpha: 1)
        view.backgroundColor = color
        parentView.addSubview(view)
        return view
    }

    private func addSubviews() {
        (0...1).forEach { _ in addView() }
        addButtons()
    }

    private func createButton(title: String, frame: CGRect, action: Selector) -> UIButton {
        let button = UIButton(frame: frame)
        button.setTitle(title, for: .normal)
        button.addTarget(self, action: action, for: .touchUpInside)
        button.setTitleColor(.blue, for: .normal)
        return button
    }

    private func addButtons() {
        view.addSubview(createButton(title: "Add",
                                     frame: CGRect(x: 10, y: 20, width: 40, height: 40),
                                     action: #selector(addView)))

        view.addSubview(createButton(title: "Delete",
                                     frame: CGRect(x: 60, y: 20, width: 60, height: 40),
                                     action: #selector(deleteView)))

        view.addSubview(createButton(title: "Remove nils",
                                     frame: CGRect(x: 120, y: 20, width: 100, height: 40),
                                     action: #selector(removeNils)))
    }

    @objc func deleteView() {
        view.subviews.first { view -> Bool in return !(view is UIButton) }?
            .removeFromSuperview()

        printArray(title: "First view deleted")
    }

    @objc func addView() {
        weakObjectsArray.append(createRandomRectangleAndAdd(to: view))
        printArray(title: "View addded")
    }

    @objc func removeNils() {
        weakObjectsArray = weakObjectsArray.filter { $0 != nil }
        printArray(title: "Remove all nil elements in weakArray")
    }
}

উভয় বিকল্পের (এবং অন্যান্য অনেকগুলি) সাথে আমার সমস্যা হ'ল এই ধরণের অ্যারে প্রোটোকলগুলির সাথে ব্যবহারযোগ্য নয়। উদাহরণস্বরূপ এটি সংকলন করবে না:protocol TP: class { } class TC { var a = WeakArray<TP>() var b = WeakObjectsArray<TP>() }
ম্যাটিক ওব্লাক

@ ম্যাটিক ওবলাক জেনেরিক ব্যবহার সম্পর্কে কী? protocol TP: class { } class TC<TYPE> where TYPE: TP { var a = WeakObjectsArray<TYPE>() // Use like regular array. With any objects var weakObjectsArray = [TYPE?]() }
ভ্যাসিলি বোদনারচুক

ধারণাটি হ'ল এই অ্যারে বিভিন্ন ধরণের অবজেক্টগুলিকে ধারণ করতে পারে যা একই শ্রেণীর প্রোটোকল প্রয়োগ করে। জেনেরিক ব্যবহার করে আপনি এটিকে একক প্রকারে লক করে রাখেন। উদাহরণস্বরূপ যেমন একটি অ্যারে ধারণ করে এমন একটি সিঙ্গলটন থাকার কল্পনা করুন delegates। তারপরে আপনার কাছে এমন কয়েকটি ভিউ কন্ট্রোলার রয়েছে যা এই কার্যকারিতাটি ব্যবহার করতে চাই। আপনি কল করতে আশা করবে MyManager.delegates.append(self)। তবে যদি MyManagerকিছু জেনেরিক টাইপে লক থাকে তবে এটি খুব ব্যবহারযোগ্য নয়।
ম্যাটিক ওব্লাক

পছন্দ করুন এটি চেষ্টা করুন: protocol TP: class { } class MyManager { typealias Delegate = AnyObject & TP static var delegates = [Delegate?]() } class A: TP { } class B: TP { } //MyManager.delegates.append(A()) //MyManager.delegates.append(B())
ভ্যাসিলি বোদনারুকুক

আপনি এখন অ্যারের সাথে জেনেরিক অংশটি হারিয়েছেন যা কিছুটা গুরুত্বপূর্ণ) আমার একটি অনুভূতি আছে যে এটি কেবলমাত্র কার্যকর নয়। আপাতত সুইফটের একটি সীমাবদ্ধতা ...
ম্যাটিক ওব্লাক

4

WeakContainer এর বিদ্যমান উদাহরণটি সহায়ক, তবে এটি তালিকাগুলি এবং অভিধানের মতো বিদ্যমান সুইফ্ট পাত্রে দুর্বল উল্লেখগুলি ব্যবহার করতে সত্যই সহায়তা করে না।

আপনি যদি তালিকার পদ্ধতিগুলি যেমন ব্যবহার করতে চান তবে WeakContainer এর সাথে সমতুল্য প্রয়োগ করতে হবে। সুতরাং আমি উইককন্টেইনারকে সমতুল্য হতে দেওয়ার জন্য কোডটি যুক্ত করেছি।

আপনি যদি অভিধানগুলিতে WeCContainer ব্যবহার করতে চেয়েছিলেন তবে আমি এটিকে হ্যাশ করতে সক্ষম করেছিলাম যাতে এটি অভিধান কী হিসাবে ব্যবহৃত হতে পারে।

আমি এটি WeakObject এর নাম পরিবর্তন করে জোর দিয়েছি যে এটি কেবল শ্রেণীর ধরণের এবং WeakContainer উদাহরণ থেকে পৃথক করার জন্য:

struct WeakObject<TYPE where TYPE:AnyObject> : Equatable, Hashable
{
    weak var _value : TYPE?
    let _originalHashValue : Int

    init (value: TYPE)
    {
        _value = value

        // We keep around the original hash value so that we can return it to represent this
        // object even if the value became Nil out from under us because the object went away.
        _originalHashValue = ObjectIdentifier(value).hashValue
    }

    var value : TYPE?
    {
        return _value
    }

    var hashValue: Int
    {
        return _originalHashValue
    }
}

func ==<T>(lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool
{
    if lhs.value == nil  &&  rhs.value == nil {
        return true
    }
    else if lhs.value == nil  ||  rhs.value == nil {
        return false
    }

    // If the objects are the same, then we are good to go
    return lhs.value! === rhs.value!
}

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

private var m_observerDict : Dictionary<WeakObject<AnyObject>,FLObservationBlock> = Dictionary()

func addObserver( observer:AnyObject, block:FLObservationBlock )
{
    let weakObserver = WeakObject(value:observer)
    m_observerDict[weakObserver] = block
}


func removeObserver( observer:AnyObject )
{
    let weakObserver = WeakObject(value:observer)
    m_observerDict.removeValueForKey(weakObserver)
}

3

এখানে @ GoZoner এর মহান উত্তর করতে সাথে সামঞ্জস্য করতে হয় তা দেখুন Hashable:, তাই এটি সূচীবদ্ধ করা যাবে মত কনটেইনার বস্তু Set, Dictionary, Array, ইত্যাদি

private class Weak<T: AnyObject>: Hashable {
    weak var value : T!
    init (value: T) {
       self.value = value
    }

    var hashValue : Int {
       // ObjectIdentifier creates a unique hashvalue for objects.
       return ObjectIdentifier(self.value).hashValue
    }
}

// Need to override so we can conform to Equitable.
private func == <T>(lhs: Weak<T>, rhs: Weak<T>) -> Bool {
    return lhs.hashValue == rhs.hashValue
}

3

যেহেতু NSPointerArrayইতিমধ্যে এর বেশিরভাগটি স্বয়ংক্রিয়ভাবে পরিচালিত হয়, তাই আমি এর জন্য একটি টাইপ-নিরাপদ মোড়ক তৈরি করে সমস্যার সমাধান করেছি, যা অন্যান্য উত্তরে অনেকগুলি বয়লারপ্লেট এড়ানো হয়:

class WeakArray<T: AnyObject> {
    private let pointers = NSPointerArray.weakObjects()

    init (_ elements: T...) {
        elements.forEach{self.pointers.addPointer(Unmanaged.passUnretained($0).toOpaque())}
    }

    func get (_ index: Int) -> T? {
        if index < self.pointers.count, let pointer = self.pointers.pointer(at: 0) {
            return Unmanaged<T>.fromOpaque(pointer).takeUnretainedValue()
        } else {
            return nil
        }
    }
    func append (_ element: T) {
        self.pointers.addPointer(Unmanaged.passUnretained(element).toOpaque())
    }
    func forEach (_ callback: (T) -> ()) {
        for i in 0..<self.pointers.count {
            if let element = self.get(i) {
                callback(element)
            }
        }
    }
    // implement other functionality as needed
}

ব্যবহারের উদাহরণ:

class Foo {}
var foo: Foo? = Foo()
let array = WeakArray(foo!)
print(array.get(0)) // Optional(Foo)
foo = nil
DispatchQueue.main.async{print(array.get(0))} // nil

এটি সামনের দিকে কাজ করে, তবে আপনার কোডের বাকী অংশে ব্যবহার অনেকটাই ক্লিনার আইএমও। আপনি যদি এটিকে আরও অ্যারে-জাতীয় করতে চান তবে আপনি সাবস্ক্রিপশনও প্রয়োগ করতে পারেন, এটিকে তৈরি করতে পারেন SequenceTypeইত্যাদি। (তবে আমার প্রকল্পটির কেবল প্রয়োজন appendএবং forEachতাই আমার হাতে সঠিক কোড নেই)।


2

তবুও একই সমস্যার আরেকটি সমাধান ... এইটির ফোকাসটি কোনও অবজেক্টের দুর্বল রেফারেন্স সংরক্ষণ করে তবে আপনাকে স্ট্রাক্টও সঞ্চয় করতে দেয়।

[এটি কতটা কার্যকর তা আমি নিশ্চিত নই, তবে সিনট্যাক্সটি সঠিকভাবে পেতে কিছুটা সময় নিয়েছে]

class WeakWrapper : Equatable {
    var valueAny : Any?
    weak var value : AnyObject?

    init(value: Any) {
        if let valueObj = value as? AnyObject {
            self.value = valueObj
        } else {
            self.valueAny = value
        }
    }

    func recall() -> Any? {
        if let value = value {
            return value
        } else if let value = valueAny {
            return value
        }
        return nil
    }
}


func ==(lhs: WeakWrapper, rhs: WeakWrapper) -> Bool {
    return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
}



class Stuff {}
var weakArray : [WeakWrapper] = [WeakWrapper(value: Stuff()), WeakWrapper(value: CGRectZero)]

extension Array where Element : WeakWrapper  {

    mutating func removeObject(object: Element) {
        if let index = self.indexOf(object) {
            self.removeAtIndex(index)
        }
    }

    mutating func compress() {
        for obj in self {
            if obj.recall() == nil {
                self.removeObject(obj)
            }
        }
    }


}

weakArray[0].recall()
weakArray[1].recall() == nil
weakArray.compress()
weakArray.count


1

অন্যান্য উত্তর জেনেরিক কোণটি কভার করেছে। ভেবেছি আমি nilকোণটি coveringেকে কিছু সাধারণ কোড ভাগ করব ।

আমি Labelবর্তমানে অ্যাপটিতে বিদ্যমান সমস্তগুলির একটি স্ট্যাটিক অ্যারে (মাঝেমধ্যে পড়ুন) চেয়েছিলাম , তবে nilপুরানোগুলি যেখানে ব্যবহৃত হত তা দেখতে চাইনি ।

কিছুই অভিনব নয়, এটি আমার কোড ...

public struct WeakLabel {
    public weak var label : Label?
    public init(_ label: Label?) {
        self.label = label
    }
}

public class Label : UILabel {
    static var _allLabels = [WeakLabel]()
    public static var allLabels:[WeakLabel] {
        get {
            _allLabels = _allLabels.filter{$0.label != nil}
            return _allLabels.filter{$0.label != nil}.map{$0.label!}
        }
    }
    public required init?(coder: NSCoder) {
        super.init(coder: coder)
        Label._allLabels.append(WeakLabel(self))
    }
    public override init(frame: CGRect) {
        super.init(frame: frame)
        Label._allLabels.append(WeakLabel(self))
    }
}

& এর flatMapপরিবর্তে ব্যবহার সম্পর্কে কী ? filtermap
Lukas Kubanek

0

আমি এটি ইউনিলের কাজের উপর ভিত্তি করে তৈরি করেছি, যেহেতু আমি ক্লোজারকে দুর্বল-বাঁধাইয়ের কৌশলটি পছন্দ করেছি, তবে আমি কোনও ভেরিয়েবলের জন্য কোনও ফাংশন অপারেটরটি ব্যবহার করতে চাইনি, কারণ এটি চূড়ান্ত স্বাক্ষরিত মনে হয়েছিল

পরিবর্তে আমি যা করেছি তা হ'ল:

class Weak<T> where T: AnyObject {
    fileprivate var storedWeakReference: ()->T? = { return nil }

    var value: T? {
        get {
            return storedWeakReference()
        }
    }

    init(_ object: T) {
        self.storedWeakReference = storeWeakReference(object)
    }

    fileprivate func storeWeakReference<T> (_ target:T) -> ()->T? where T: AnyObject {
        return { [weak target] in
            return target
        }
    }
}

এইভাবে আপনি কিছু করতে পারেন যেমন:

var a: UIViewController? = UIViewController()
let b = Weak(a)
print(a) //prints Optional(<UIViewController: 0xSomeAddress>)
print(b.value) //prints Optional(<UIViewController: 0xSomeAddress>)
a = nil
print(a) //prints nil
print(b.value) //prints nil

0

এটি আমার সমাধান:

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

-

// MARK: - WeakObjectSet 

public class WeakObject<T: AnyObject>: Equatable, Hashable {

    // MARK: Public propreties

    public weak var object: T?
    public var hashValue: Int {
        return self.identifier.hashValue
    }

    // MARK: Private propreties

    private let identifier: ObjectIdentifier

    // MARK: Initializer

    public init(object: T) {
        self.identifier = ObjectIdentifier(object)
        self.object = object
    }

    public static func == (lhs: WeakObject<T>, rhs: WeakObject<T>) -> Bool {
        return lhs.identifier == rhs.identifier
    }
}

// MARK: - WeakObjectSet

public class WeakObjectSet<T: AnyObject> {

    // MARK: Public propreties

    public var allObjects: [T] {
        return allSetObjects.compactMap { $0.object }
    }

    // MARK: Private propreties

    private var objects: Set<WeakObject<T>>
    private var allSetObjects: Set<WeakObject<T>> {
        get {
            objects = self.objects.filter { $0.object != nil }
            return objects
        }
        set {
            objects.formUnion(newValue.filter { $0.object != nil })
        }
    }

    // MARK: Initializer

    public init() {
        self.objects = Set<WeakObject<T>>([])
    }

    public init(objects: [T]) {
        self.objects = Set<WeakObject<T>>(objects.map { WeakObject(object: $0) })
    }

    // MARK: Public function

    public func contains(_ object: T) -> Bool {
        return self.allSetObjects.contains(WeakObject(object: object))
    }

    public func addObject(_ object: T) {
        self.allSetObjects.insert(WeakObject(object: object))
    }

    public func addObjects(_ objects: [T]) {
        objects.forEach { self.allSetObjects.insert(WeakObject(object: $0)) }
    }
}

0

এটি এমন এক ধরণের নিরাপদ সংগ্রহ যা দুর্বল বস্তুর ধারক ধারণ করে। এটি অ্যাক্সেস করা হলে পাত্রে / মোড়কগুলি স্বয়ংক্রিয়ভাবে সরিয়ে দেয়।

উদাহরণ:

protocol SomeDelegate: class {
    func doSomething()
}

class SomeViewController: UIViewController {
    var delegates: WeakCollection<SomeDelegate> = []

    func someFunction(delegate: SomeDelegate) {
        delegates.append(delegate)
    }

    func runDelegates() {
        delegates.forEach { $0.doSomething() }
    }
}

কাস্টম সংগ্রহ https://gist.github.com/djk12587/46d85017fb3fad6946046925f36cefdc

import Foundation

/**
 Creates an array of weak reference objects.
 - Important:
    Because this is an array of weak objects, the objects in the array can be removed at any time.
    The collection itself will handle removing nil objects (garbage collection) via the private function cleanUpNilContainers()
 */

class WeakCollection<T>: RangeReplaceableCollection, ExpressibleByArrayLiteral {
    typealias Index = Int
    typealias Element = T
    typealias Iterator = IndexingIterator<[Element]>

    private var weakContainers: [WeakReferenceContainer]

    required convenience init(arrayLiteral: Element...) {
        self.init()
        self.weakContainers = WeakCollection.createWeakContainers(from: arrayLiteral)
    }

    required init() {
        weakContainers = []
    }

    required init<S>(_ elements: S) where S: Sequence, WeakCollection.Element == S.Element {
        self.weakContainers = WeakCollection.createWeakContainers(from: elements)
    }

    static private func createWeakContainers<S>(from weakCollection: S) -> [WeakReferenceContainer] where S: Sequence,
        WeakCollection.Element == S.Element {
            return weakCollection.compactMap { WeakReferenceContainer(value: $0 as AnyObject) }
    }

    func append<S>(contentsOf newElements: S) where S: Sequence, WeakCollection.Element == S.Element {
        self.weakContainers.append(contentsOf: WeakCollection.createWeakContainers(from: newElements))
    }

    var startIndex: Index {
        return references.startIndex
    }

    var endIndex: Index {
        return references.endIndex
    }

    func replaceSubrange<C, R>(_ subrange: R, with newElements: C) where
        C: Collection, R: RangeExpression, WeakCollection.Element == C.Element, WeakCollection.Index == R.Bound {
            weakContainers.replaceSubrange(subrange, with: WeakCollection.createWeakContainers(from: newElements))
    }

    func index(after i: Int) -> Int {
        return references.index(after: i)
    }

    func makeIterator() -> IndexingIterator<[Element]> {
        return references.makeIterator()
    }

    subscript(index: Int) -> Element {
        get {
            return references[index]
        }
        set {
            weakContainers[index] = WeakReferenceContainer(value: newValue as AnyObject)
        }
    }
}

extension WeakCollection {
    private class WeakReferenceContainer {
        private(set) weak var value: AnyObject?

        init(value: AnyObject?) {
            self.value = value
        }
    }

    private func cleanUpNilContainers() {
        weakContainers = weakContainers.compactMap { $0.value == nil ? nil : $0 }
    }

    private var references: [Element] {
        cleanUpNilContainers()
        return weakContainers.compactMap { $0.value as? T }
    }
}

0

একটি কার্যকরী পদ্ধতির সম্পর্কে কী ?

let observers = [() -> Observer?]()

observers.append({ [weak anObserver] in return anObserver })

এটি মূল ধারণা, তারপরে অ্যারেতে কী রয়েছে তার ট্র্যাক রাখতে কোনও সুবিধা যুক্তি যুক্ত করুন। উদাহরণস্বরূপ, কেউ কী ব্যবহার করে অভিধানের সাথে একই পন্থা বিবেচনা করতে পারে সেখানে কী রয়েছে তা খুঁজে বের করার উপায় হিসাবে।

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