উদ্দেশ্য-সি: বিভাগে সম্পত্তি / উদাহরণ পরিবর্তনশীল


122

যেহেতু আমি উদ্দেশ্য-সিতে কোনও বিভাগে সংশ্লেষিত সম্পত্তি তৈরি করতে পারি না, নীচের কোডটি কীভাবে অনুকূল করা যায় তা আমি জানি না:

@interface MyClass (Variant)
@property (nonatomic, strong) NSString *test;
@end

@implementation MyClass (Variant)

@dynamic test;

- (NSString *)test {
    NSString *res;
    //do a lot of stuff
    return res;
}

@end

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


2
আপনি সাধারণত যা করেন না কেন কেবল কোনও বিভাগের পরিবর্তে সম্পত্তিটি মাইক্লাস বেস শ্রেণিতে যুক্ত করবেন? এবং এটিকে আরও নিতে, আপনার ভারী জিনিসটিকে ব্যাকগ্রাউন্ডে সঞ্চালন করুন এবং প্রক্রিয়াটি কোনও বিজ্ঞপ্তি বন্ধ করে দিন বা প্রক্রিয়াটি সম্পূর্ণ হয়ে গেলে মাই ক্লাসের জন্য কোনও হ্যান্ডলারকে কল করুন।
জেরেমি

4
মাইক্লাস মূল ডেটা থেকে উত্পন্ন শ্রেণি। উত্পন্ন শ্রেণীর ভিতরে যদি আমি তবে আমার কাস্টম অবজেক্ট কোডটি না থেকে যায় তবে আমি আমার কোর ডেটা থেকে ক্লাসটি পুনরায় জেনারেট করলে তা অদৃশ্য হয়ে যাবে। এই কারণে, আমি একটি বিভাগ ব্যবহার করছি।
dhrm

1
শিরোনামের সবচেয়ে ভাল প্রযোজ্য প্রশ্নটি গ্রহণ করুন? ("বিভাগে সম্পত্তি")
hfossli

কেন শুধু একটি সাবক্লাস তৈরি করবেন না?
স্কট ঝু

উত্তর:


124

@ লরিয়ানের পদ্ধতিটি কাজ করবে (দ্রষ্টব্য: উত্তরটি এখন মুছে ফেলা হয়েছে) তবে আপনি কেবলমাত্র একটি স্টোরেজ স্লট পেতে চাইবেন। সুতরাং আপনি যদি এটি একাধিক উদাহরণে ব্যবহার করতে চান এবং প্রতিটি উদাহরণের জন্য একটি পৃথক মান গণনা করা হয়, এটি কাজ করবে না।

ভাগ্যক্রমে, অবজেক্টিভ-সি রানটাইমের এই জিনিসটি অ্যাসোসিয়েটেড অবজেক্টস নামে পরিচিত যা আপনি যা চান ঠিক তা করতে পারে:

#import <objc/runtime.h>

static void *MyClassResultKey;
@implementation MyClass

- (NSString *)test {
  NSString *result = objc_getAssociatedObject(self, &MyClassResultKey);
  if (result == nil) {
    // do a lot of stuff
    result = ...;
    objc_setAssociatedObject(self, &MyClassResultKey, result, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  }
  return result;
}

@end

অ্যাসোসিয়েটেড অবজেক্টের জন্য স্থির লিঙ্ক: বিকাশকারী.অ্যাপল.
com

5
@ ডেভিডলং এই সমাধানের জন্য আপনাকে ধন্যবাদ! খুব সুন্দর নয় তবে এটি কাজ করে :)
dhrm

42
"খুব সুন্দর না"? এটি অবজেক্টিভ-সি এর সৌন্দর্য! ;)
ডেভ দেলং

6
দুর্দান্ত উত্তর! আপনি @selector(test)এখানে কীভাবে ব্যাখ্যা করেছেন তেমন কী হিসাবে স্ট্যাটিক ভেরিয়েবলটি মুক্তি দিতে পারেন : stackoverflow.com/questions/16020918/…
গ্যাব্রিয়েল পেট্রোনেলা

1
@HotFudgeSunday - মনে হয় এটা দ্রুতগতি কাজ করে: stackoverflow.com/questions/24133058/...
স্কট Corscadden

174

জ ফাইল

@interface NSObject (LaserUnicorn)

@property (nonatomic, strong) LaserUnicorn *laserUnicorn;

@end

.m ফাইল

#import <objc/runtime.h>

static void * LaserUnicornPropertyKey = &LaserUnicornPropertyKey;

@implementation NSObject (LaserUnicorn)

- (LaserUnicorn *)laserUnicorn {
    return objc_getAssociatedObject(self, LaserUnicornPropertyKey);
}

- (void)setLaserUnicorn:(LaserUnicorn *)unicorn {
    objc_setAssociatedObject(self, LaserUnicornPropertyKey, unicorn, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

@end

ঠিক একটি সাধারণ সম্পত্তির মতো - বিন্দু-চিহ্ন সহ অ্যাক্সেসযোগ্য

NSObject *myObject = [NSObject new];
myObject.laserUnicorn = [LaserUnicorn new];
NSLog(@"Laser unicorn: %@", myObject.laserUnicorn);

আরও সহজ বাক্য গঠন

বিকল্পভাবে আপনি এর @selector(nameOfGetter)মতো স্থির পয়েন্টার কী তৈরির পরিবর্তে ব্যবহার করতে পারেন :

- (LaserUnicorn *)laserUnicorn {
    return objc_getAssociatedObject(self, @selector(laserUnicorn));
}

- (void)setLaserUnicorn:(LaserUnicorn *)unicorn {
    objc_setAssociatedObject(self, @selector(laserUnicorn), unicorn, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
}

আরও তথ্যের জন্য https://stackoverflow.com/a/16020927/202451 দেখুন


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

4
আপনার সত্যই দরকার নেই @dynamic objectTag;@dynamicমানে সেটার এবং গেটর অন্য কোথাও তৈরি করা হবে তবে এই ক্ষেত্রে সেগুলি এখানেই প্রয়োগ করা হয়েছে।
ইলুটোভ

@ এনএসডিকেট সত্য! সংশোধন করা হয়েছে!
hfossli

1
ম্যানুয়াল মেমরি পরিচালনার জন্য লেজার ইউনিকর্নগুলির ডেলোক সম্পর্কে কীভাবে? এটি কি স্মৃতি ফুটো?
মানি

স্বয়ংক্রিয়ভাবে মুক্তি হয় stackoverflow.com/questions/6039309/...
hfossli

32

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

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

ম্যাক্রো ছাড়াই ditionতিহ্যগত পদ্ধতির approach

Ditionতিহ্যগতভাবে আপনি যেমন একটি বিভাগের সম্পত্তি নির্ধারণ করেন

@interface MyClass (Category)
@property (strong, nonatomic) NSString *text;
@end

তারপরে আপনার কোনও সম্পর্কিত বস্তু এবং কী হিসাবে নির্বাচককে কী ( মূল উত্তর দেখুন ) ব্যবহার করে একটি গিটার এবং সেটার পদ্ধতি প্রয়োগ করতে হবে :

#import <objc/runtime.h>

@implementation MyClass (Category)
- (NSString *)text{
    return objc_getAssociatedObject(self, @selector(text));
}

- (void)setText:(NSString *)text{
    objc_setAssociatedObject(self, @selector(text), text, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

আমার প্রস্তাবিত পদ্ধতির

এখন, ম্যাক্রো ব্যবহার করে আপনি পরিবর্তে লিখবেন:

@implementation MyClass (Category)

CATEGORY_PROPERTY_GET_SET(NSString*, text, setText:)

@end

ম্যাক্রো নিম্নলিখিত হিসাবে সংজ্ঞায়িত করা হয়:

#import <objc/runtime.h>

#define CATEGORY_PROPERTY_GET(type, property) - (type) property { return objc_getAssociatedObject(self, @selector(property)); }
#define CATEGORY_PROPERTY_SET(type, property, setter) - (void) setter (type) property { objc_setAssociatedObject(self, @selector(property), property, OBJC_ASSOCIATION_RETAIN_NONATOMIC); }
#define CATEGORY_PROPERTY_GET_SET(type, property, setter) CATEGORY_PROPERTY_GET(type, property) CATEGORY_PROPERTY_SET(type, property, setter)

#define CATEGORY_PROPERTY_GET_NSNUMBER_PRIMITIVE(type, property, valueSelector) - (type) property { return [objc_getAssociatedObject(self, @selector(property)) valueSelector]; }
#define CATEGORY_PROPERTY_SET_NSNUMBER_PRIMITIVE(type, property, setter, numberSelector) - (void) setter (type) property { objc_setAssociatedObject(self, @selector(property), [NSNumber numberSelector: property], OBJC_ASSOCIATION_RETAIN_NONATOMIC); }

#define CATEGORY_PROPERTY_GET_UINT(property) CATEGORY_PROPERTY_GET_NSNUMBER_PRIMITIVE(unsigned int, property, unsignedIntValue)
#define CATEGORY_PROPERTY_SET_UINT(property, setter) CATEGORY_PROPERTY_SET_NSNUMBER_PRIMITIVE(unsigned int, property, setter, numberWithUnsignedInt)
#define CATEGORY_PROPERTY_GET_SET_UINT(property, setter) CATEGORY_PROPERTY_GET_UINT(property) CATEGORY_PROPERTY_SET_UINT(property, setter)

ম্যাক্রো CATEGORY_PROPERTY_GET_SETপ্রদত্ত সম্পত্তির জন্য একজন গিটার এবং সেটার যুক্ত করে। কেবলমাত্র পঠনযোগ্য বা কেবল লেখার বৈশিষ্ট্য যথাক্রমে CATEGORY_PROPERTY_GETএবং CATEGORY_PROPERTY_SETম্যাক্রো ব্যবহার করবে ।

আদিম ধরণেরগুলিকে আরও বেশি মনোযোগ দেওয়া দরকার

আদিম ধরণের কোনও বস্তু না হওয়ায় উপরের ম্যাক্রোগুলিতে unsigned intসম্পত্তিটির ধরণ হিসাবে ব্যবহারের জন্য উদাহরণ রয়েছে । এটি কোনও NSNumberবস্তুর মধ্যে পূর্ণসংখ্যার মানটি মোড়ক করে does সুতরাং এর ব্যবহার পূর্ববর্তী উদাহরণের সাথে অ্যানালগ:

@interface ...
@property unsigned int value;
@end

@implementation ...
CATEGORY_PROPERTY_GET_SET_UINT(value, setValue:)
@end

এই প্যাটার্ন অনুসরণ করে আপনি কেবল এছাড়াও সমর্থন করার জন্য আরো ম্যাক্রো যোগ করতে পারেন signed int, BOOL, ইত্যাদি ...

সীমাবদ্ধতা

  1. সমস্ত ম্যাক্রো OBJC_ASSOCIATION_RETAIN_NONATOMICডিফল্টরূপে ব্যবহার করছে ।

  2. অ্যাপের কোডের মতো আইডিআই বর্তমানে সম্পত্তির নাম পুনরায় সংশোধন করার সময় সেটারের নামটি স্বীকৃতি দেয় না। আপনার নিজের এটির নতুন নামকরণ করতে হবে।


1
#import <objc/runtime.h>অন্যথায় .m ফাইল বিভাগে ভুলে যাবেন না। সংকলনের সময় ত্রুটি: '99c_getAssociatedObject 'ফাংশনের অন্তর্নিহিত ঘোষণাটি C99 এ অবৈধ up stackoverflow.com/questions/9408934/...
Sathe_Nagaraja

7

কেবল লিভেক্সটোবিজেসি ব্যবহার করুন লাইব্রেরি

এইচ-ফাইল:

@interface MyClass (Variant)
@property (nonatomic, strong) NSString *test;
@end

M-ফাইল:

#import <extobjc.h>
@implementation MyClass (Variant)

@synthesizeAssociation (MyClass, test);

@end

টুইটারে


এটির সাহায্যে অ্যাক্সেসরকে ওভাররাইড করার সঠিক উপায়টি কী (উদাহরণস্বরূপ অলস লোড একটি সম্পত্তি)
ডেভিড জেমস

3

শুধুমাত্র আইওএস 9 দিয়ে পরীক্ষা করা হয়েছে উদাহরণ: ইউআইএনভিগেশনবারে (বিভাগ) একটি ইউআইভিউ সম্পত্তি যুক্ত করা

UINavigationBar + + Helper.h

#import <UIKit/UIKit.h>

@interface UINavigationBar (Helper)
@property (nonatomic, strong) UIView *tkLogoView;
@end

UINavigationBar + + Helper.m

#import "UINavigationBar+Helper.h"
#import <objc/runtime.h>

#define kTKLogoViewKey @"tkLogoView"

@implementation UINavigationBar (Helper)

- (void)setTkLogoView:(UIView *)tkLogoView {
    objc_setAssociatedObject(self, kTKLogoViewKey, tkLogoView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (UIView *)tkLogoView {
    return objc_getAssociatedObject(self, kTKLogoViewKey);
}

@end

-2

আর একটি সম্ভাব্য সমাধান, সম্ভবত সহজ, যা ব্যবহার করে না তা Associated Objectsহল বিভাগের বাস্তবায়ন ফাইলে একটি পরিবর্তনশীল নিম্নরূপ হিসাবে ঘোষণা করা:

@interface UIAlertView (UIAlertViewAdditions)

- (void)setObject:(id)anObject;
- (id)object;

@end


@implementation UIAlertView (UIAlertViewAdditions)

id _object = nil;

- (id)object
{
    return _object;
}

- (void)setObject:(id)anObject
{
    _object = anObject;
}
@end

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


প্রশ্ন উদাহরণ ভেরিয়েবল সম্পর্কে জিজ্ঞাসা করে। আপনার সমাধান ঠিক
লরেনের

1
সত্যিই ?? আপনি কি জানেন আপনি কি করছেন? আপনি একটি অভ্যন্তরীণ ভেরিয়েবল অ্যাক্সেসের জন্য গেটর / সেটার পদ্ধতির একটি জুড়ি তৈরি করেছেন যা কোনও শ্রেণি অবজেক্টের জন্য কোনও ফাইলের জন্য স্বতন্ত্র that
Itachi
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.