क्या स्विफ्ट में संबद्ध वस्तुओं को सेट करने का एक तरीका है?


82

ऑब्जेक्टिव C से आकर आप objc_setAssociatedObject2 ऑब्जेक्ट्स के बीच फंक्शन को कॉल कर सकते हैं ताकि उन्हें एक रेफरेंस मेंटेन किया जा सके, जो तब संभव हो सकता है जब रनटाइम के दौरान आप किसी ऑब्जेक्ट को तब तक नष्ट नहीं करना चाहते जब तक कि उसका रेफरेंस भी न निकाल दिया जाए। क्या स्विफ्ट के पास भी ऐसा ही कुछ है?


3
आप objc_setAssociatedObjectस्विफ्ट से उपयोग कर सकते हैं : developer.apple.com/library/prerelease/ios/documentation/Swift/…
jtbandes

कट और पेस्ट करने के लिए पूर्ण कोड के साथ लंबी परीक्षा: stackoverflow.com/documentation/swift/1085/associated-objects/…
Fattie

जवाबों:


131

यहां एक सरल लेकिन संपूर्ण उदाहरण दिया गया है जो कि जेकटर के उत्तर से लिया गया है ।

यह दिखाता है कि एक मौजूदा वर्ग में एक नई संपत्ति कैसे जोड़ें। यह विस्तार ब्लॉक में गणना की गई संपत्ति को परिभाषित करके करता है। गणना की गई संपत्ति को संबंधित वस्तु के रूप में संग्रहीत किया जाता है:

import ObjectiveC

// Declare a global var to produce a unique address as the assoc object handle
private var AssociatedObjectHandle: UInt8 = 0

extension MyClass {
    var stringProperty:String {
        get {
            return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! String
        }
        set {
            objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

संपादित करें:

यदि आपको एक असंवैधानिक संपत्ति के मूल्य प्राप्त करने और त्रुटि से बचने के लिए समर्थन करने की आवश्यकता है unexpectedly found nil while unwrapping an Optional value, तो आप इस तरह से गेटर को संशोधित कर सकते हैं:

    get {
        return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? String ?? ""
    }

क्या आप एक फ़ंक्शन सेट करने में सक्षम हैं जो इस प्रकार से टाइपेलियास के अनुरूप है?
मॉर्क्रोम

1
@PHHoan Int एक स्विफ्ट देशी प्रकार है। इसके बजाय NSNumber का उपयोग करने का प्रयास करें।
कालस

1
@PHHoan मैंने एक असंगठित वस्तु प्राप्त करने के लिए एक समाधान जोड़ा।
कलस

1
@ जव्वाद मुझे लगता है, इससे कोई फर्क नहीं पड़ता। UInt8लिंक किए गए वास्तविक थ्रेड से आता है।
कलस

1
हे @ जॅकी - क्या कहता है आपको यह कॉपी होना चाहिए .. कृपया हमें बताएं!
फेटी

31

समाधान सभी मूल्य प्रकारों का समर्थन करता है , और न केवल वे जो स्वचालित रूप से पाले जाते हैं , जैसे स्ट्रिंग, इंट, डबल, आदि।

रैपर

import ObjectiveC

final class Lifted<T> {
    let value: T
    init(_ x: T) {
        value = x
    }
}

private func lift<T>(x: T) -> Lifted<T>  {
    return Lifted(x)
}

func setAssociatedObject<T>(object: AnyObject, value: T, associativeKey: UnsafePointer<Void>, policy: objc_AssociationPolicy) {
    if let v: AnyObject = value as? AnyObject {
        objc_setAssociatedObject(object, associativeKey, v,  policy)
    }
    else {
        objc_setAssociatedObject(object, associativeKey, lift(value),  policy)
    }
}

func getAssociatedObject<T>(object: AnyObject, associativeKey: UnsafePointer<Void>) -> T? {
    if let v = objc_getAssociatedObject(object, associativeKey) as? T {
        return v
    }
    else if let v = objc_getAssociatedObject(object, associativeKey) as? Lifted<T> {
        return v.value
    }
    else {
        return nil
    }
}

एक संभावित कक्षा विस्तार (उपयोग का उदाहरण)

extension UIView {

    private struct AssociatedKey {
        static var viewExtension = "viewExtension"
    }

    var referenceTransform: CGAffineTransform? {
        get {
            return getAssociatedObject(self, associativeKey: &AssociatedKey.viewExtension)
        }

        set {
            if let value = newValue {
                setAssociatedObject(self, value: value, associativeKey: &AssociatedKey.viewExtension, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }
}

क्या आप मुझे समझा सकते हैं कि उन झंडों का क्या मतलब है? मैं वास्तव में स्क्रॉल बार के साथ नेवी बार स्क्रॉल बनाने की कोशिश कर रहा हूं इसलिए स्क्रॉलव्यू को विस्तार से स्टोर कर रहा हूं। मुझे कौन से झंडे का उपयोग करना चाहिए?
उल्का

1
इसके अलावा, मैं इस विधि का उपयोग करके [AnyObject] की एक सरणी को संग्रहीत करने की कोशिश कर रहा हूं, लेकिन पाने वाला मुझे हमेशा शून्य देता है। किसी और तरह का अगर सही मूल्य नहीं मिल रहा है।
उल्का

आपके द्वारा उपयोग की जाने वाली सहानुभूति नीति आपके ऊपर निर्भर है, यह आपके कार्यक्रम पर निर्भर करता है। अधिक जानकारी के लिए, मैं आपको इस लेख, nshipster.com/associated-objects , बाहर की जाँच करने का सुझाव देता हूं । मैंने सरणियों को संग्रहीत करने की कोशिश की है, ऐसा लगता है कि यह ठीक काम कर रहा है। आप किस स्विफ्ट संस्करण का उपयोग कर रहे हैं?
HepaKKes

ये जबरदस्त है। 2.3 स्विफ्ट के लिए मैंने लिफ्ट से जेनरिक को स्थानांतरित करना और Anyइसके बजाय उपयोग करना समाप्त कर दिया। मैं इस बारे में एक ब्लॉग लेख करूँगा, मुझे लगता है
डैन रोसेनस्टार्क

5
स्विफ्ट 3 में यह बहुत आसान हो गया। लेकिन वैसे भी, यहाँ आपके जवाब के आधार पर यहाँ myarticle है: yar2050.com/2016/11/associated-object-support-for-swift-23.html
Dan Rosenstark

5

जाहिर है, यह केवल उद्देश्य-सी वस्तुओं के साथ काम करता है। इस के साथ थोड़ा चक्कर लगाने के बाद, यहां स्विफ्ट में कॉल कैसे करें:

import ObjectiveC

// Define a variable whose address we'll use as key.
// "let" doesn't work here.
var kSomeKey = "s"func someFunc() {
    objc_setAssociatedObject(target, &kSomeKey, value, UInt(OBJC_ASSOCIATION_RETAIN))

    let value : AnyObject! = objc_getAssociatedObject(target, &kSomeKey)
}

मैंने इस पद्धति को आजमाया है, लेकिन मेरी वैल्यू ऑब्जेक्ट तुरंत डील-डौल प्रतीत होती है जब स्विफ्ट कोड से इसका कोई अन्य संदर्भ नहीं होता है। मेरी लक्ष्य वस्तु एक SKNode है और मेरा मान ऑब्जेक्ट एक स्विफ्ट क्लास है जो NSObject का विस्तार करता है। क्या यह काम करना चाहिए?
nacross

वास्तव में डिनीट को objc_setAssociatedObject के दौरान कहा जाता है, भले ही ऑब्जेक्ट सिर्फ बनाया गया हो और आगे विधि में नीचे उपयोग किया जाता है।
23

4

स्विफ्ट 3.0 में अद्यतन उदाहरण के लिए यह एक UITextField है

import Foundation
import UIKit
import ObjectiveC

// Declare a global var to produce a unique address as the assoc object handle
var AssociatedObjectHandle: UInt8 = 0

extension UITextField
{
    var nextTextField:UITextField {
    get {
        return objc_getAssociatedObject(self, &AssociatedObjectHandle) as! UITextField
    }
    set {
        objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

3

मैंने एक आधुनिक सहायक लिखा जिसके लिए स्विफ्ट 5.1 की आवश्यकता है।

/*
 AssociatedObject.swift

 Copyright © 2020 RFUI.
 https://github.com/BB9z/iOS-Project-Template

 The MIT License
 https://opensource.org/licenses/MIT
 */

import Foundation

/**
 Objective-C associated value wrapper.

 Usage

 ```
 private let fooAssociation = AssociatedObject<String>()
 extension SomeObject {
     var foo: String? {
         get { fooAssociation[self] }
         set { fooAssociation[self] = newValue }
     }
 }
 ```
 */
public final class AssociatedObject<T> {
    private let policy: objc_AssociationPolicy

    /// Creates an associated value wrapper.
    /// - Parameter policy: The policy for the association.
    public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {
        self.policy = policy
    }

    /// Accesses the associated value.
    /// - Parameter index: The source object for the association.
    public subscript(index: AnyObject) -> T? {
        get { objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as? T }
        set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
    }
}

आपको आश्चर्य हो सकता है कि यह मुफ्त में स्विफ्ट संरचनाओं का भी समर्थन करता है।

स्विफ्ट स्ट्रक्चर एसोसिएशन


2

Klaas का जवाब सिर्फ स्विफ्ट 2.1 के लिए:

import ObjectiveC

let value = NSUUID().UUIDString
var associationKey: UInt8 = 0

objc_setAssociatedObject(parentObject, &associationKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)

let fetchedValue = objc_getAssociatedObject(parentObject, &associationKey) as! String

0

बस #import <objc/runtime.h>तेज कोड के तहत objc_setAssociatedObject का उपयोग करने के लिए अपने ब्रिडिंग हेडर फ़ाइल पर जोड़ें


18
या आप import ObjectiveCस्विफ्ट में बस कर सकते हैं
newacct

0

उपरोक्त मित्र ने आपके प्रश्न का उत्तर दिया है, लेकिन यदि यह क्लोजर गुणों से संबंधित है, तो कृपया ध्यान दें:

`` `

import UIKit
public extension UICollectionView {

typealias XYRearrangeNewDataBlock = (_ newData: [Any]) -> Void
typealias XYRearrangeOriginaDataBlock = () -> [Any]

// MARK:- associat key
private struct xy_associatedKeys {
    static var originalDataBlockKey = "xy_originalDataBlockKey"
    static var newDataBlockKey = "xy_newDataBlockKey"
}


private class BlockContainer {
    var rearrangeNewDataBlock: XYRearrangeNewDataBlock?
    var rearrangeOriginaDataBlock: XYRearrangeOriginaDataBlock?
}


private var newDataBlock: BlockContainer? {
    get {
        if let newDataBlock = objc_getAssociatedObject(self, &xy_associatedKeys.newDataBlockKey) as? BlockContainer {
            return newDataBlock
        }
        return nil
    }

    set(newValue) {
        objc_setAssociatedObject(self, xy_associatedKeys.newDataBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
    }
}
convenience init(collectionVewFlowLayout : UICollectionViewFlowLayout, originalDataBlock: @escaping XYRearrangeOriginaDataBlock, newDataBlock:  @escaping XYRearrangeNewDataBlock) {
    self.init()


    let blockContainer: BlockContainer = BlockContainer()
    blockContainer.rearrangeNewDataBlock = newDataBlock
    blockContainer.rearrangeOriginaDataBlock = originalDataBlock
    self.newDataBlock = blockContainer
}

`` `

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.