ওবিজেক্টিভ-সি তে একইভাবে আমি কীভাবে সুইফটে সম্পত্তি সঞ্চয় করব?


132

আমি অবজেক্টিভ-সি থেকে সুইফটে একটি অ্যাপ্লিকেশন স্যুইচ করছি, যা আমার কাছে সঞ্চিত বৈশিষ্ট্য সহ কয়েকটি বিভাগ রয়েছে, উদাহরণস্বরূপ:

@interface UIView (MyCategory)

- (void)alignToView:(UIView *)view
          alignment:(UIViewRelativeAlignment)alignment;
- (UIView *)clone;

@property (strong) PFObject *xo;
@property (nonatomic) BOOL isAnimating;

@end

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

যেমন জউ বলেছিলেন, আমি যা খুঁজছিলাম তা আসলে যুক্ত জিনিসগুলি ব্যবহার করছিলাম, তাই আমি (অন্য প্রসঙ্গে) করেছি:

import Foundation
import QuartzCore
import ObjectiveC

extension CALayer {
    var shapeLayer: CAShapeLayer? {
        get {
            return objc_getAssociatedObject(self, "shapeLayer") as? CAShapeLayer
        }
        set(newValue) {
            objc_setAssociatedObject(self, "shapeLayer", newValue, UInt(OBJC_ASSOCIATION_RETAIN))
        }
    }

    var initialPath: CGPathRef! {
        get {
            return objc_getAssociatedObject(self, "initialPath") as CGPathRef
        }
        set {
            objc_setAssociatedObject(self, "initialPath", newValue, UInt(OBJC_ASSOCIATION_RETAIN))
        }
    }
}

তবে এটি করার সময় আমি একটি EXC_BAD_ACCESS পাই:

class UIBubble : UIView {
    required init(coder aDecoder: NSCoder) {
        ...
        self.layer.shapeLayer = CAShapeLayer()
        ...
    }
}

কোন ধারনা?


11
উদ্দেশ্য-সি শ্রেণীর বিভাগগুলি উদাহরণের ভেরিয়েবলগুলি সংজ্ঞায়িত করতে পারে না, সুতরাং আপনি কীভাবে এই বৈশিষ্ট্যগুলি অনুধাবন করলেন?
মার্টিন আর

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

উত্তর:


50

অ্যাসোসিয়েটেড অবজেক্টস এপিআই ব্যবহার করা কিছুটা জটিল। আপনি কোনও সহায়ক শ্রেণীর সাহায্যে বেশিরভাগ বয়লারপ্লেট সরিয়ে ফেলতে পারেন।

public final class ObjectAssociation<T: AnyObject> {

    private let policy: objc_AssociationPolicy

    /// - Parameter policy: An association policy that will be used when linking objects.
    public init(policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN_NONATOMIC) {

        self.policy = policy
    }

    /// Accesses associated object.
    /// - Parameter index: An object whose associated object is to be accessed.
    public subscript(index: AnyObject) -> T? {

        get { return objc_getAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque()) as! T? }
        set { objc_setAssociatedObject(index, Unmanaged.passUnretained(self).toOpaque(), newValue, policy) }
    }
}

আপনি যদি আরও বেশি পাঠযোগ্য উপায়ে উদ্দেশ্য-সি শ্রেণিতে একটি সম্পত্তি "যুক্ত" করতে পারেন তবে

extension SomeType {

    private static let association = ObjectAssociation<NSObject>()

    var simulatedProperty: NSObject? {

        get { return SomeType.association[self] }
        set { SomeType.association[self] = newValue }
    }
}

সমাধান হিসাবে:

extension CALayer {

    private static let initialPathAssociation = ObjectAssociation<CGPath>()
    private static let shapeLayerAssociation = ObjectAssociation<CAShapeLayer>()

    var initialPath: CGPath! {
        get { return CALayer.initialPathAssociation[self] }
        set { CALayer.initialPathAssociation[self] = newValue }
    }

    var shapeLayer: CAShapeLayer? {
        get { return CALayer.shapeLayerAssociation[self] }
        set { CALayer.shapeLayerAssociation[self] = newValue }
    }
}

ঠিক আছে আমি কী করতে চাই ইনট, বুল এবং ইত্যাদি?
ভাইচাস্লাভ গের্চিকভ

1
সরাসরি অবজেক্ট অ্যাসোসিয়েশনের মাধ্যমে সুইফট প্রকারগুলি সঞ্চয় করা সম্ভব নয়। আপনি যেমন সংরক্ষণ পারে NSNumberবা NSValueএবং accessors যে ধরনের আপনি চেয়েছিলেন (int, bool, ইত্যাদি) অন্তর্ভুক্ত হয়ে যেতাম অতিরিক্ত যুগল লিখুন।
ওয়াজেসিচ নাগ্রোডস্কি 21

1
সতর্কতা এটি স্ট্রাক্টগুলির জন্য কাজ করে না, কারণ উদ্দেশ্য-সি রানটাইম লাইব্রেরি কেবল এমন ক্লাসগুলিকে সমর্থন করে যা মেনে চলেNSObjectProtocol
চার্লটন Provatas

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

@ ভাইচাস্লাভ জের্চিকভ [String]?একটি কাঠামো, এটি ইন্টার , বুলের মতো একই ঘটনা। আপনি উদাহরণগুলির NSArrayসংগ্রহ রাখতে ব্যবহার করতে পারেন NSString
ভোজসিচ নাগরডজকি

184

অবজেক্টিভ-সি এর মতো, আপনি বিদ্যমান ক্লাসে সঞ্চিত সম্পত্তি যুক্ত করতে পারবেন না। যদি আপনি কোনও উদ্দেশ্য-সি শ্রেণি প্রসারিত করেন ( UIViewঅবশ্যই এটি এক) তবে আপনি সঞ্চিত বৈশিষ্ট্যগুলি অনুকরণ করতে এখনও অ্যাসোসিয়েটেড অবজেক্টগুলি ব্যবহার করতে পারেন :

সুইফট 1 এর জন্য

import ObjectiveC

private var xoAssociationKey: UInt8 = 0

extension UIView {
    var xo: PFObject! {
        get {
            return objc_getAssociatedObject(self, &xoAssociationKey) as? PFObject
        }
        set(newValue) {
            objc_setAssociatedObject(self, &xoAssociationKey, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN))
        }
    }
}

সমিতি কী এমন একটি পয়েন্টার যা প্রতিটি সংঘের জন্য অনন্য হওয়া উচিত। তার জন্য, আমরা একটি ব্যক্তিগত গ্লোবাল ভেরিয়েবল তৈরি করি এবং &অপারেটরের সাথে কী হিসাবে এটির মেমরি ঠিকানা ব্যবহার করি । কোকো এবং অবজেক্টিভ-সি এর সাহায্যে ব্যবহারের সুইফটটি দেখুন আরো বিস্তারিত জানার কিভাবে পয়েন্টার সুইফট পরিচালিত হয়।

সুইফট 2 এবং 3 এর জন্য আপডেট করা

import ObjectiveC

private var xoAssociationKey: UInt8 = 0

extension UIView {
    var xo: PFObject! {
        get {
            return objc_getAssociatedObject(self, &xoAssociationKey) as? PFObject
        }
        set(newValue) {
            objc_setAssociatedObject(self, &xoAssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
        }
    }
}

সুইফট 4-এর জন্য আপডেট

সুইফ্ট 4-এ, এটি আরও অনেক সহজ। ধারক স্ট্রাক্টটিতে এমন ব্যক্তিগত মূল্য থাকবে যা আমাদের গণিত সম্পত্তি বিশ্বে প্রকাশ করবে, পরিবর্তে সঞ্চিত সম্পত্তি আচরণের বিভ্রম দেয়।

উৎস

extension UIViewController {
    struct Holder {
        static var _myComputedProperty:Bool = false
    }
    var myComputedProperty:Bool {
        get {
            return Holder._myComputedProperty
        }
        set(newValue) {
            Holder._myComputedProperty = newValue
        }
    }
}

2
@ ইয়ার সম্পর্কে জানতেন না objc_AssociationPolicy, ধন্যবাদ! আমি উত্তর আপডেট করেছি
jou

2
সুইফট 2 এ আপনাকে অবজেক্ট_আসোসিয়েশন পলিসি ব্যবহার করতে হবে O ওবিজেসি_এএসএসসিআইএটিএইচটিএএন
টম

1
@ সিম্পলজি আপনি অন্যের উত্তরে আপনার কোড সম্পাদনা করার চেয়ে আপনার সম্পাদনাটিকে একটি অতিরিক্ত উত্তর হিসাবে যুক্ত করুন।
জাল

11
আপনি যদি ইউআইভিউউকন্ট্রোলারের 1 টিরও বেশি উদাহরণ থাকতে চান যা প্রসারণ থেকে সম্পত্তিটি ব্যবহার করে তবে সুইফট 4 সমাধানটি কাজ করে না। উত্স আপডেট আপডেট করুন।
iur

9
সুইফট 4 উদাহরণটি একাধিক উদাহরণ সহ কাজ করে না এবং সম্ভবত এটি এখানে থাকা উচিত নয়।
কলিন কর্ণবি

36

সুতরাং আমি মনে করি যে আমি এমন একটি পদ্ধতি খুঁজে পেয়েছি যা উপরেরগুলির চেয়ে পরিষ্কার পরিশ্রম করে কারণ এটির জন্য কোনও বৈশ্বিক ভেরিয়েবলের প্রয়োজন হয় না। আমি এটি এখান থেকে পেয়েছি: http://nshipster.com/swift-objc-runtime/

সংক্ষিপ্তসারটি হ'ল আপনি যেমন কাঠামো ব্যবহার করেন:

extension UIViewController {
    private struct AssociatedKeys {
        static var DescriptiveName = "nsh_DescriptiveName"
    }

    var descriptiveName: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.DescriptiveName) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.DescriptiveName,
                    newValue as NSString?,
                    UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC)
                )
            }
        }
    }
}

সুইফট 2 এর জন্য আপডেট

private struct AssociatedKeys {
    static var displayed = "displayed"
}

//this lets us check to see if the item is supposed to be displayed or not
var displayed : Bool {
    get {
        guard let number = objc_getAssociatedObject(self, &AssociatedKeys.displayed) as? NSNumber else {
            return true
        }
        return number.boolValue
    }

    set(value) {
        objc_setAssociatedObject(self,&AssociatedKeys.displayed,NSNumber(bool: value),objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

@ AKWeblS আমি আপনার মতো কোডটি প্রয়োগ করেছি তবে সুইফট ২.০-তে আপডেট করার সময়, ত্রুটিটি পাচ্ছি যে 'ইউজেন্ট' টাইপের 'ইজেক্ট_অ্যাসোসিয়েশনপলিসি' টাইপের তালিকার সাথে ইনিশিয়ালাইজারের কাছে প্রার্থনা করা যাবে না। পরবর্তী মন্তব্যে কোড
ব্যবহারকারী 2363025

সুইফট ২.০-এর জন্য কীভাবে আপডেট করবেন? var পোস্টডেস্ক্রিপশন: স্ট্রিং? obj{ obj obj{ obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj obj ?ssssssssssococociatediatedOObbbjectject ((self (স্ব, এবং অ্যাসোসিয়েটেডকিস.পোস্টডেসক্রিপশন) হিসাবে? স্ট্রিং} সেট {যদি দিন newValue = newValue {objc_setAssociatedObject (স্ব, & AssociatedKeys.postDescription, NSString ?, UInt যেমন newValue (objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC))}}}
user2363025

1
কাজ করে না: স্ট্যাটিক Var মানে যে সম্পত্তির মান সব উদাহরণস্বরূপ একই
ভেজে

@ ফ্রাই - এটি আমার পক্ষে কাজ করে চলেছে। হ্যাঁ, কীটি স্থিতিশীল, তবে এটি একটি নির্দিষ্ট অবজেক্টের সাথে সম্পর্কিত, অবজেক্টটি নিজে গ্লোবাল নয়।
অ্যালেক্সেকে

15

জউ দ্বারা নির্দেশিত সমাধানটি মান ধরণেরগুলিকে সমর্থন করে না , এটি তাদের সাথে ভাল কাজ করে

চাদরে

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

এটি সত্যিই এত দুর্দান্ত সমাধান, আমি অন্য ব্যবহারের উদাহরণ যুক্ত করতে চেয়েছিলাম যাতে স্ট্রাক্ট এবং মানগুলি includedচ্ছিক নয়। এছাড়াও, অ্যাসোসিয়েটেডকি মানগুলি সরল করা যায়।

struct Crate {
    var name: String
}

class Box {
    var name: String

    init(name: String) {
        self.name = name
    }
}

extension UIViewController {

    private struct AssociatedKey {
        static var displayed:   UInt8 = 0
        static var box:         UInt8 = 0
        static var crate:       UInt8 = 0
    }

    var displayed: Bool? {
        get {
            return getAssociatedObject(self, associativeKey: &AssociatedKey.displayed)
        }

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

    var box: Box {
        get {
            if let result:Box = getAssociatedObject(self, associativeKey: &AssociatedKey.box) {
                return result
            } else {
                let result = Box(name: "")
                self.box = result
                return result
            }
        }

        set {
            setAssociatedObject(self, value: newValue, associativeKey: &AssociatedKey.box, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }

    var crate: Crate {
        get {
            if let result:Crate = getAssociatedObject(self, associativeKey: &AssociatedKey.crate) {
                return result
            } else {
                let result = Crate(name: "")
                self.crate = result
                return result
            }
        }

        set {
            setAssociatedObject(self, value: newValue, associativeKey: &AssociatedKey.crate, policy: objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

এবং আমি কীভাবে লিফ্ট ক্লাস ব্যবহার করব?
3lvis

তোমার এতো দরকার কেন? কিসের জন্য?
HepaKKes

আমি বোঝাতে চেয়েছি আপনি কীভাবে এটি সাধারণভাবে ব্যবহার করেন, আপনার সহায়তার জন্য ধন্যবাদ :) দয়া করে একটি "কীভাবে ব্যবহার করবেন" উদাহরণটি যুক্ত করতে পারেন?
3lvis

1
"কীভাবে ব্যবহার করবেন" উদাহরণটি নীচে "সম্ভাব্য শ্রেণিবদ্ধকরণ" শিরোনামের নীচে শুরু হবে। আমি মনে করি না যে liftপদ্ধতিগুলি এবং Liftedক্লাসটি কীভাবে ব্যবহার করতে হবে তা ব্যবহারকারীদের জানা দরকার , তবে তাদের getAssociatedObjectএবং setAssociatedObjectক্রিয়াকলাপগুলি ব্যবহার করা উচিত । স্পষ্টতার স্বার্থে আমি শিরোনামের পাশে প্রথম বন্ধনীর মধ্যে "ব্যবহারের উদাহরণ" যুক্ত করব।
হেপাকেস

1
এটি অবশ্যই সেরা সমাধান, খুব খারাপ এটি খুব ভাল ব্যাখ্যা করা হয়নি। এটি ক্লাস, স্ট্রাক্ট এবং অন্যান্য মান ধরণের সাথে কাজ করে। বৈশিষ্ট্যগুলিও বিকল্প হতে হবে না। চমৎকার কাজ.
পিক্কিয়ানো

13

আপনি নতুন স্টোরেজ সহ বিভাগগুলি (সুইফট এক্সটেনশন) সংজ্ঞায়িত করতে পারবেন না; কোনও অতিরিক্ত বৈশিষ্ট্য সংরক্ষণের পরিবর্তে গণনা করতে হবে । বাক্য গঠনটি উদ্দেশ্য সি এর জন্য কাজ করে কারণ @propertyএকটি বিভাগে মূলত "আমি গেটর এবং সেটার সরবরাহ করব" এর অর্থ। সুইফটে, একটি গণনা করা সম্পত্তি পেতে আপনাকে এগুলি নিজেকে সংজ্ঞায়িত করতে হবে; কিছুটা এইরকম:

extension String {
    public var Foo : String {
        get
        {
            return "Foo"
        }

        set
        {
            // What do you want to do here?
        }
    }
}

ভাল কাজ করা উচিত। মনে রাখবেন, আপনি সেটারে নতুন মান সংরক্ষণ করতে পারবেন না, কেবল বিদ্যমান উপলব্ধ শ্রেণি রাষ্ট্রের সাথে কাজ করুন।


7

আমার $ 0.02। এই কোডটি সুইফট ২.০ তে লেখা আছে

extension CALayer {
    private struct AssociatedKeys {
        static var shapeLayer:CAShapeLayer?
    }

    var shapeLayer: CAShapeLayer? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.shapeLayer) as? CAShapeLayer
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(self, &AssociatedKeys.shapeLayer, newValue as CAShapeLayer?, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            }
        }
    }
}

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


আকর্ষণীয় দেখায়, তবে প্রোটোকল নিয়ে কাজ করে না, type 'AssociatedKeys' cannot be defined within a protocol extension
ইয়ান বাইচেক

6

অবজেক্ট রানটাইমের উপর ভরসা কেন? আমি পয়েন্ট পাই না। নীচের মতো কিছু ব্যবহার করে আপনি কেবল বিশুদ্ধ সুইফট পদ্ধতির সাহায্যে সঞ্চিত সম্পত্তির প্রায় একইরকম আচরণ অর্জন করতে পারবেন :

extension UIViewController {
    private static var _myComputedProperty = [String:Bool]()

    var myComputedProperty:Bool {
        get {
            let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self))
            return UIViewController._myComputedProperty[tmpAddress] ?? false
        }
        set(newValue) {
            let tmpAddress = String(format: "%p", unsafeBitCast(self, to: Int.self))
            UIViewController._myComputedProperty[tmpAddress] = newValue
        }
    }
}

1
চতুর! এই পদ্ধতির সাথে একটি সম্ভাব্য খারাপ দিক হ'ল মেমরি পরিচালনা। হোস্ট অবজেক্টটি নির্বিঘ্ন হওয়ার পরে, এর সম্পত্তিটি অভিধানে এখনও বিদ্যমান থাকবে যা মেমরির ব্যবহারে সম্ভবত ব্যয়বহুল হতে পারে যদি এটি প্রচুর অবজেক্টের সাথে ব্যবহার করা হয়।
চার্লটন প্রোভাতাস

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

5

আমি খাঁটি সুইফটে কোড করা পছন্দ করি এবং উদ্দেশ্য-সি heritageতিহ্যের উপর নির্ভর করি না। এই কারণে আমি দুটি সুবিধা এবং দুটি অসুবিধা সহ খাঁটি সুইফট সমাধান লিখেছিলাম।

সুবিধাদি:

  1. খাঁটি সুইফ্ট কোড

  2. ক্লাস এবং সম্পূর্ণকরণ বা আরও নির্দিষ্টভাবে Anyঅবজেক্টে কাজ করে

অসুবিধা:

  1. willDeinit()কোডটিকে মেমরির ফাঁস এড়াতে নির্দিষ্ট শ্রেণীর উদাহরণের সাথে যুক্ত লিখিত বস্তুগুলি প্রকাশের জন্য পদ্ধতি কল করা উচিত should

  2. আপনি এই সঠিক উদাহরণের জন্য সরাসরি ইউআইভিউতে এক্সটেনশন করতে পারবেন না কারণ var frameইউআইভিউ-তে এক্সটেনশন, শ্রেণির অংশ নয়।

সম্পাদনা করুন:

import UIKit

var extensionPropertyStorage: [NSObject: [String: Any]] = [:]

var didSetFrame_ = "didSetFrame"

extension UILabel {

    override public var frame: CGRect {

        get {
            return didSetFrame ?? CGRectNull
        }

        set {
            didSetFrame = newValue
        }
    }

    var didSetFrame: CGRect? {

        get {
            return extensionPropertyStorage[self]?[didSetFrame_] as? CGRect
        }

        set {
            var selfDictionary = extensionPropertyStorage[self] ?? [String: Any]()

            selfDictionary[didSetFrame_] = newValue

            extensionPropertyStorage[self] = selfDictionary
        }
    }

    func willDeinit() {
        extensionPropertyStorage[self] = nil
    }
}

4
এক্সটেনশনপ্রোটারি স্টোরেজ সমস্ত দৃষ্টান্তের মধ্যে ভাগ করা হওয়ায় এটি কাজ করে না। আপনি যদি একটি উদাহরণের জন্য কোনও মান সেট করেন, আপনি সমস্ত দৃষ্টান্তের জন্য মানটি সেট করছেন।
পিক্সিয়ানো

এটি যুদ্ধ ভাল নয় কারণ ফাংশনগুলির সাথে বিশৃঙ্খলা। এখন এটি আরও ভাল এবং উদ্দেশ্য হিসাবে কাজ করে।
vedrano

@ পাইকিয়ানো ডিজাইনের extensionPropertyStorage মাধ্যমে সমস্ত দৃষ্টান্তের সাথে ভাগ করে নেওয়া হয়েছে। এটি গ্লোবাল ভেরিয়েবল (অভিধান) যা প্রথমে ইউআইএলবেল উদাহরণ ( NSObject) এবং এর পরে তার সম্পত্তি ( [String: Any]) উল্লেখ করে।
vedrano

@ পিক্সিয়ানো আমি অনুমান করি যে এটি classসম্পত্তিগুলির জন্য কাজ করে;)
নিকোলাস মিয়ারি

frameএকটি উদাহরণ সম্পত্তি। শ্রেণীর সম্পত্তি কোথা থেকে আসে?
বেদরানো

3

ওবজ-সি বিভাগের সাহায্যে আপনি কেবল পদ্ধতিগুলি যোগ করতে পারেন, উদাহরণের ভেরিয়েবলগুলি নয়।

উদাহরণস্বরূপ আপনি গিটার এবং সেটার পদ্ধতি ঘোষণার যোগ করতে শর্টকাট হিসাবে @ প্রপার্টি ব্যবহার করেছেন। আপনার এখনও সেই পদ্ধতিগুলি প্রয়োগ করতে হবে।

একইভাবে সুইফ্টে আপনি উদাহরণ পদ্ধতি, গণিত বৈশিষ্ট্য ইত্যাদি যোগ করতে ব্যবহার এক্সটেনশন যুক্ত করতে পারেন তবে সঞ্চিত বৈশিষ্ট্যগুলি নয়।


2

আমি একটি EXC_BAD_ACCESS সমস্যাও পাই The মানটি objc_getAssociatedObject()objc_setAssociatedObject()একটি অবজেক্ট হওয়া উচিত। এবং objc_AssociationPolicyঅবজেক্টের সাথে ম্যাচ করা উচিত।


3
এটি আসলে প্রশ্নের উত্তর দেয় না। আপনি কি অন্য কিছু প্রশ্ন থাকে, তাহলে আপনি এটি ক্লিক করে অনুরোধ করতে পারেন প্রশ্ন জিজ্ঞাসা করুন । আপনি এটিও করতে পারেন একটি খয়রাত যোগ একবার আপনি যথেষ্ট আছে এই প্রশ্নের আরো দৃষ্টি আকর্ষণ করতে খ্যাতি । - পর্যালোচনা থেকে
নাস্তিকপি 3ace

@ এথিস্টপি 3এস সম্পর্কে আমি দুঃখিত। আমি প্রশ্নটিতে একটি মন্তব্য যুক্ত করার চেষ্টা করি ut তবে আমার যথেষ্ট খ্যাতি নেই। তাই আমি প্রশ্নের উত্তর দেওয়ার চেষ্টা করি।
রুইকিউ

2

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

class MyClass {
    var a = 1
    init(a: Int)
    {
        self.a = a
    }
}

extension UIView
{
    static var extraData = [UIView: MyClass]()

    var myClassData: MyClass? {
        get {
            return UIView.extraData[self]
        }
        set(value) {
            UIView.extraData[self] = value
        }
    }
}

// Test Code: (Ran in a Swift Playground)
var view1 = UIView()
var view2 = UIView()

view1.myClassData = MyClass(a: 1)
view2.myClassData = MyClass(a: 2)
print(view1.myClassData?.a)
print(view2.myClassData?.a)

অতিরিক্ত ডেটা স্বয়ংক্রিয়ভাবে সাফ করবেন কীভাবে আপনার কী ধারণা আছে যাতে এটি মেমরি ফাঁস না করে?
ডাবলকে

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

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

2

এখানে সরলীকৃত এবং আরও অভিব্যক্তিযুক্ত সমাধান। এটি মান এবং রেফারেন্স উভয় প্রকারের জন্য কাজ করে। উত্তোলনের পদ্ধতিটি @ হেপককেস উত্তর থেকে নেওয়া হয়েছে।

সমিতির কোড:

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 associated<T>(to base: AnyObject,
                key: UnsafePointer<UInt8>,
                policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN,
                initialiser: () -> T) -> T {
    if let v = objc_getAssociatedObject(base, key) as? T {
        return v
    }

    if let v = objc_getAssociatedObject(base, key) as? Lifted<T> {
        return v.value
    }

    let lifted = Lifted(initialiser())
    objc_setAssociatedObject(base, key, lifted, policy)
    return lifted.value
}

func associate<T>(to base: AnyObject, key: UnsafePointer<UInt8>, value: T, policy: objc_AssociationPolicy = .OBJC_ASSOCIATION_RETAIN) {
    if let v: AnyObject = value as AnyObject? {
        objc_setAssociatedObject(base, key, v, policy)
    }
    else {
        objc_setAssociatedObject(base, key, lift(value), policy)
    }
}

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

1) এটি এক্সটেনশন এবং সহযোগী সম্পত্তি তৈরি করুন। আসুন মান এবং রেফারেন্স ধরণের বৈশিষ্ট্য উভয়ই ব্যবহার করি।

extension UIButton {

    struct Keys {
        static fileprivate var color: UInt8 = 0
        static fileprivate var index: UInt8 = 0
    }

    var color: UIColor {
        get {
            return associated(to: self, key: &Keys.color) { .green }
        }
        set {
            associate(to: self, key: &Keys.color, value: newValue)
        }
    }

    var index: Int {
        get {
            return associated(to: self, key: &Keys.index) { -1 }
        }
        set {
            associate(to: self, key: &Keys.index, value: newValue)
        }
    }

}

2) এখন আপনি ঠিক নিয়মিত বৈশিষ্ট্য হিসাবে ব্যবহার করতে পারেন:

    let button = UIButton()
    print(button.color) // UIExtendedSRGBColorSpace 0 1 0 1 == green
    button.color = .black
    print(button.color) // UIExtendedGrayColorSpace 0 1 == black

    print(button.index) // -1
    button.index = 3
    print(button.index) // 3

আরো বিস্তারিত:

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

1

ওবজেক্টিভ-সি সম্পর্কিত বস্তু এবং সুইফট 3 এবং সুইফট 4 এর জন্য গণিত বৈশিষ্ট্যগুলি ব্যবহার করে অন্য একটি উদাহরণ

import CoreLocation

extension CLLocation {

    private struct AssociatedKeys {
        static var originAddress = "originAddress"
        static var destinationAddress = "destinationAddress"
    }

    var originAddress: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.originAddress) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.originAddress,
                    newValue as NSString?,
                    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                )
            }
        }
    }

    var destinationAddress: String? {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.destinationAddress) as? String
        }
        set {
            if let newValue = newValue {
                objc_setAssociatedObject(
                    self,
                    &AssociatedKeys.destinationAddress,
                    newValue as NSString?,
                    .OBJC_ASSOCIATION_RETAIN_NONATOMIC
                )
            }
        }
    }

}

1

আপনি যদি কোনও ইউআইভিউতে একটি কাস্টম স্ট্রিং বৈশিষ্ট্য নির্ধারণ করতে চান তবে আমি সুইফট 4 এ এটিই করেছি

একটি ইউআইভিউ এক্সটেনশন তৈরি করুন

extension UIView {

    func setStringValue(value: String, key: String) {
        layer.setValue(value, forKey: key)
    }

    func stringValueFor(key: String) -> String? {
        return layer.value(forKey: key) as? String
    }
}

এই এক্সটেনশনটি ব্যবহার করতে

let key = "COLOR"

let redView = UIView() 

// To set
redView.setStringAttribute(value: "Red", key: key)

// To read
print(redView.stringValueFor(key: key)) // Optional("Red")

1

স্থিতিশীল মানচিত্রটিকে ক্লাসে কীভাবে সংরক্ষণ করা যায় যা এর মতো প্রসারিত হয়:

extension UIView {

    struct Holder {
        static var _padding:[UIView:UIEdgeInsets] = [:]
    }

    var padding : UIEdgeInsets {
        get{ return UIView.Holder._padding[self] ?? .zero}
        set { UIView.Holder._padding[self] = newValue }
    }

}

1
কেন এই উত্তরের কোনও অগ্রগতি নেই? সর্বোপরি স্মার্ট সমাধান।
জীবন

এটি কাজ করে তবে আমি মনে করি যে এই পদ্ধতির ত্রুটি রয়েছে এখানে যেমন বলা হয়েছে মাঝারি.com
@

0

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

private var _min: Int?
private var _max: Int?

extension UITextField {    
    @IBInspectable var minLength: Int {
        get {
            return _min ?? 0
        }
        set {
            _min = newValue
        }
    }

    @IBInspectable var maxLength: Int {
        get {
            return _max ?? 1000
        }
        set {
            _max = newValue
        }
    }

    func validation() -> (valid: Bool, error: String) {
        var valid: Bool = true
        var error: String = ""
        guard let text = self.text else { return (true, "") }

        if text.characters.count < minLength {
            valid = false
            error = "Textfield should contain at least \(minLength) characters"
        }

        if text.characters.count > maxLength {
            valid = false
            error = "Textfield should not contain more then \(maxLength) characters"
        }

        if (text.characters.count < minLength) && (text.characters.count > maxLength) {
            valid = false
            error = "Textfield should contain at least \(minLength) characters\n"
            error = "Textfield should not contain more then \(maxLength) characters"
        }

        return (valid, error)
    }
}

গ্লোবাল ব্যক্তিগত ভেরিয়েবল? আপনি কী তা উপলব্ধি করেছেন _minএবং _maxবৈশ্বিক এবং ইউআইটিেক্সটফিল্ডের সমস্ত ক্ষেত্রে একই হবে? এমনকি যদি এটি আপনার পক্ষে কাজ করে তবে এই উত্তরটি সম্পর্কিত নয় কারণ মার্কোস উদাহরণ ভেরিয়েবল সম্পর্কে জিজ্ঞাসা করছে ।
কেলিন

হ্যাঁ আপনি ঠিক বলেছেন, এটি সমস্ত দৃষ্টান্তের জন্য কাজ করে না। স্ট্রাক্টে ন্যূনতম এবং সর্বাধিক মান সংরক্ষণ করে আমি স্থির করেছি। বন্ধ বিষয় জন্য দুঃখিত।
ভাদিমস ক্রুতভস

0

এখানে একটি বিকল্প যা কাজ করে

public final class Storage : AnyObject {

    var object:Any?

    public init(_ object:Any) {
        self.object = object
    }
}

extension Date {

    private static let associationMap = NSMapTable<NSString, AnyObject>()
    private struct Keys {
        static var Locale:NSString = "locale"
    }

    public var locale:Locale? {
        get {

            if let storage = Date.associationMap.object(forKey: Keys.Locale) {
                return (storage as! Storage).object as? Locale
            }
            return nil
        }
        set {
            if newValue != nil {
                Date.associationMap.setObject(Storage(newValue), forKey: Keys.Locale)
            }
        }
    }
}



var date = Date()
date.locale = Locale(identifier: "pt_BR")
print( date.locale )

-1

আমি এই সমাধানটিকে আরও ব্যবহারিক বলে মনে করেছি

সুইফট 3-এর জন্য আপডেট করা

extension UIColor {

    static let graySpace = UIColor.init(red: 50/255, green: 50/255, blue: 50/255, alpha: 1.0)
    static let redBlood = UIColor.init(red: 102/255, green: 0/255, blue: 0/255, alpha: 1.0)
    static let redOrange = UIColor.init(red: 204/255, green: 17/255, blue: 0/255, alpha: 1.0)

    func alpha(value : CGFloat) -> UIColor {
        var r = CGFloat(0), g = CGFloat(0), b = CGFloat(0), a = CGFloat(0)
        self.getRed(&r, green: &g, blue: &b, alpha: &a)
        return UIColor(red: r, green: g, blue: b, alpha: value)
    }

}

... তাহলে আপনার কোডে

class gameController: UIViewController {

    @IBOutlet var game: gameClass!

    override func viewDidLoad() {
        self.view.backgroundColor = UIColor.graySpace

    }
}

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