ইনিজ পদ্ধতিটি কী উদ্দেশ্যমূলক-সি তে ব্যক্তিগত করা সম্ভব?


147

-initআমার ক্লাসের পদ্ধতিটি অবজেক্টিভ-সি- তে লুকিয়ে রাখা (প্রাইভেট করা) দরকার ।

আমি এটা কিভাবে করবো?


3
এটি অর্জনের জন্য এখন একটি নির্দিষ্ট, পরিষ্কার এবং বর্ণনামূলক সুবিধা রয়েছে, যেমন নীচে এই উত্তরে দেখানো হয়েছে । বিশেষ করে: NS_UNAVAILABLE। আমি আপনাকে সাধারণত এই পদ্ধতির ব্যবহার করার জন্য অনুরোধ করব। ওপি তাদের গৃহীত উত্তরগুলির সংশোধন বিবেচনা করবে? এখানে অন্যান্য উত্তরগুলি প্রচুর দরকারী বিশদ সরবরাহ করে তবে এটি অর্জনের পছন্দসই পদ্ধতি নয়।
বেনজোহন

অন্যরা যেমন নীচে উল্লিখিত হয়েছে, NS_UNAVAILABLEতবুও একজন কলারকে initঅপ্রত্যক্ষভাবে মাধ্যমে ডাকতে অনুমতি দেয় new। কেবল initফেরত যেতে ওভাররাইড করা nilউভয় ক্ষেত্রে পরিচালনা করবে।
গ্রেগ ব্রাউন

উত্তর:


88

অবজেক্টিভ-সি, স্মলটালকের মতো, "ব্যক্তিগত" বনাম "পাবলিক" পদ্ধতির কোনও ধারণা নেই। যে কোনও সময় যে কোনও বস্তুতে কোনও বার্তা প্রেরণ করা যায়।

NSInternalInconsistencyExceptionআপনার -initপদ্ধতিটি চালু থাকলে আপনি যা করতে পারেন তা হ'ল :

- (id)init {
    [self release];
    @throw [NSException exceptionWithName:NSInternalInconsistencyException
                                   reason:@"-init is not a valid initializer for the class Foo"
                                 userInfo:nil];
    return nil;
}

অন্য বিকল্প - যা অনুশীলনে সম্ভবত অনেক বেশি ভাল - হ'ল -initযদি সম্ভব হয় তবে আপনার শ্রেণীর জন্য বুদ্ধিমান কিছু করা।

যদি আপনি এটি করার চেষ্টা করছেন কারণ আপনি যদি একটি সিঙ্গলটন অবজেক্টটি "নিশ্চিত" করার চেষ্টা করছেন, বিরক্ত করবেন না। বিশেষ করে, বিরক্ত না "ওভাররাইড +allocWithZone:, -init, -retain, -release" singletons তৈরি করার পদ্ধতি। এটি কার্যত সর্বদা অপ্রয়োজনীয় এবং সত্যিকারের উল্লেখযোগ্য সুবিধার জন্য কেবল জটিলতা যুক্ত করছে।

পরিবর্তে, কেবল আপনার কোডটি লিখুন যাতে আপনার +sharedWhateverপদ্ধতিটি কীভাবে আপনি একটি সিঙ্গলটন অ্যাক্সেস করতে পারেন এবং এটি আপনার নথিতে সিঙ্গলটন উদাহরণ পাওয়ার উপায় হিসাবে নথি করে দেয়। বিস্তৃত ক্ষেত্রে আপনার এটি প্রয়োজন।


2
এখানে কি রিটার্ন আসলে প্রয়োজনীয়?
ফিল্ডসওয়ার্ড

5
হ্যাঁ, সংকলককে খুশি রাখতে। অন্যথায় সংকলক অভিযোগ করতে পারে যে অকার্যকর রিটার্ন সহ কোনও পদ্ধতি থেকে কোনও রিটার্ন নেই।
ক্রিস হ্যানসন

মজার, এটা আমার পক্ষে হয় না। সম্ভবত একটি পৃথক সংকলক সংস্করণ বা সুইচ? (আমি কেবল
এক্সকোড

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

4
"কোন সত্যিকারের উল্লেখযোগ্য সুবিধার জন্য" । সম্পূর্ণ অসত্য। উল্লেখযোগ্য সুবিধা হ'ল আপনি সিঙ্গলটন প্যাটার্নটি প্রয়োগ করতে চান । আপনি যদি নতুন দৃষ্টান্ত তৈরি করার অনুমতি দেন তবে এমন একটি বিকাশকারী যিনি এপিআইয়ের সাথে পরিচিত নন তারা সঠিকভাবে ক্লাসের কারণে ভুল কোড ব্যবহার করতে পারেন allocএবং initতাদের কোডটি ভুলভাবে রাখতে পারেন কারণ তাদের সঠিক বর্গ রয়েছে তবে ভুল উদাহরণ। এটি ওওতে এনক্যাপসুলেশন নীতিটির সারাংশ । আপনি আপনার এপিআইগুলিতে এমন জিনিস লুকিয়ে রেখেছেন যা অন্য শ্রেণীর কাছে প্রবেশ করা উচিত নয় বা পাওয়া উচিত। আপনি কেবল সমস্ত কিছু সর্বজনীন রাখেন না এবং মানবেরা এগুলি সম্পর্কে সর্বদা নজর রাখবেন বলে আশা করেন।
নাট

345

NS_UNAVAILABLE

- (instancetype)init NS_UNAVAILABLE;

এটি অনুপলব্ধ বৈশিষ্ট্যের একটি সংক্ষিপ্ত সংস্করণ। এটি প্রথম ম্যাকোস 10.7 এবং আইওএস 5 এ উপস্থিত হয়েছিল । এটি NSObjCRuntime.h হিসাবে সংজ্ঞায়িত করা হয়েছে #define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE

একটি সংস্করণ রয়েছে যা কেবল সুইফ্ট ক্লায়েন্টদের জন্য পদ্ধতিটি অক্ষম করে , ওবজিসি কোডের জন্য নয়:

- (instancetype)init NS_SWIFT_UNAVAILABLE;

unavailable

কোনও কলটিতে কোনও সংকলনে ত্রুটিunavailable উত্পন্ন করতে শিরোলেখটিতে বৈশিষ্ট্য যুক্ত করুন ।

-(instancetype) init __attribute__((unavailable("init not available")));  

সংকলন সময় ত্রুটি

আপনার যদি কোনও কারণ না থাকে তবে কেবল টাইপ করুন __attribute__((unavailable))বা এমনকি __unavailable:

-(instancetype) __unavailable init;  

doesNotRecognizeSelector:

doesNotRecognizeSelector:একটি এনএসআইএনওডিয়ালআরগমেন্টএক্সসেপশন বাড়াতে ব্যবহার করুন । "রানটাইম সিস্টেমটি এই পদ্ধতিটি আহ্বান করে যখনই কোনও বস্তু কোনও নির্বাচিত বার্তা গ্রহণ করে তবে তা প্রতিক্রিয়া জানাতে বা প্রেরণ করতে পারে না।"

- (instancetype) init {
    [self release];
    [super doesNotRecognizeSelector:_cmd];
    return nil;
}

NSAssert

NSAssertNSInternInconsistencyException নিক্ষেপ করতে এবং একটি বার্তা দেখানোর জন্য ব্যবহার করুন :

- (instancetype) init {
    [self release];
    NSAssert(false,@"unavailable, use initWithBlah: instead");
    return nil;
}

raise:format:

raise:format:আপনার নিজস্ব ব্যতিক্রম নিক্ষেপ করতে ব্যবহার করুন :

- (instancetype) init {
    [self release];
    [NSException raise:NSGenericException 
                format:@"Disabled. Use +[[%@ alloc] %@] instead",
                       NSStringFromClass([self class]),
                       NSStringFromSelector(@selector(initWithStateDictionary:))];
    return nil;
}

[self release]প্রয়োজনীয় কারণ বস্তুটি ইতিমধ্যে নষ্ট হয়ে গেছে alloc। আরসি ব্যবহার করার সময় সংকলকটি এটি আপনার জন্য কল করবে। যাই হোক না কেন, আপনি যখন ইচ্ছাকৃতভাবে মৃত্যুদন্ড কার্যকর করতে চলেছেন তখন উদ্বিগ্ন হওয়ার কিছু নেই।

objc_designated_initializer

যদি আপনি initকোনও মনোনীত প্রাথমিকের ব্যবহারটি জোর করে অক্ষম করতে চান , তবে এর জন্য একটি বৈশিষ্ট্য রয়েছে:

-(instancetype)myOwnInit NS_DESIGNATED_INITIALIZER;

অন্য কোনও আরম্ভকারী পদ্ধতি myOwnInitঅভ্যন্তরীণভাবে কল না করা হলে এটি একটি সতর্কতা উত্পন্ন করে । পরবর্তী এক্সকোড প্রকাশের পরে ( আধুনিক ধারণা) মডার্ন অবজেক্টিভ-সি অ্যাডাপ্টিংয়ে বিশদ প্রকাশিত হবে I


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

কোন ধারণা আলেকস, এটি সেখানে হওয়া উচিত নয়) আমি উত্তরটি সম্পাদনা করেছি।
জানো

এটি অদ্ভুত কারণ এটি আপনার সিস্টেমে ক্র্যাশ হয়ে গেছে। আমি অনুমান করি যে কিছু ঘটতে না দেওয়া ভাল তবে আমি আরও ভাবছি যে এর থেকে আরও ভাল উপায় আছে কিনা। আমি যা চাই তা অন্য বিকাশকারীদের পক্ষে এটি কল করতে না পারা এবং 'দৌড়' বা 'বিল্ডিং' করার সময় এটি
সংকলকটির

1
আমি এটি চেষ্টা করেছি এবং এটি কাজ করে না: - (id) init __attribute __ ((অনুপলব্ধ ("init উপলব্ধ নয়"))) {NSAssert (মিথ্যা, @ "initWithType ব্যবহার করুন"); রিটার্ন শূন্য; }
Okysabeni

1
@ মীরাজ মনে হচ্ছে এটি আপনার সংকলকটিতে সমর্থিত নয়। এটি এক্সকোড in-তে সমর্থিত if
জানো

101

অ্যাপল তাদের কন্ট্রাক্টর অক্ষম করতে তাদের হেডার ফাইলগুলিতে নিম্নলিখিতগুলি ব্যবহার শুরু করেছে:

- (instancetype)init NS_UNAVAILABLE;

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


3
নোট করুন যদিও আপনি এখনও [মাইবজেক্ট নতুন] দিয়ে অবজেক্টটি ইনস্ট্যান্ট করতে পারেন;
জোসে

11
আপনি নতুন (এনএসএনটাইপ) নতুন এনএস_উনাএইভিএআইএলবিএল করতেও পারেন;
sonicfly

@ সোনিকফ্লাই এটি করার চেষ্টা করেছিল কিন্তু প্রকল্পটি এখনও সংকলন করে
সাইবারমিউ

3

আপনি যদি ডিফল্ট-ইনিট পদ্ধতি সম্পর্কে কথা বলছেন তবে আপনি পারবেন না। এটি এনএসবজেক্ট থেকে উত্তরাধিকার সূত্রে প্রাপ্ত এবং প্রতিটি বর্গ কোনও সতর্কীকরণ ছাড়াই এর প্রতিক্রিয়া জানাবে।

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

লোকেরা ডিআইডি গোপন করতে চায় বলে মনে করার অন্যতম প্রধান কারণ হ'ল সিঙ্গলটন অবজেক্টের জন্য । যদি এটি হয় তবে আপনার লুকানোর দরকার নেই, কেবল পরিবর্তে সিঙ্গলটন অবজেক্টটি ফিরিয়ে দিন (বা এটি উপস্থিত না থাকলে এটি তৈরি করুন)।


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

3

এটি হেডার ফাইলে রাখুন

- (id)init UNAVAILABLE_ATTRIBUTE;

এটি সুপারিশ করা হয় না। অ্যাপলের আধুনিক উদ্দেশ্য-সি নথিগুলিতে উল্লেখ করা হয়েছে যে আরআইডি নয়, আইডি নয়, উদাহরণস্বরূপ ফিরতে হবে। বিকাশকারী.এপলল.লাইবারি
আইওস

5
এবং এটি: - (উদাহরণস্বরূপ) init NS_UNAVAILABLE;
বান্দেজপাটাইস

3

আপনি যে কোনও পদ্ধতি ব্যবহারের জন্য উপলব্ধ নয় তা ঘোষণা করতে পারেন NS_UNAVAILABLE

সুতরাং আপনি এই লাইনগুলি আপনার @ আন্তঃ পৃষ্ঠের নীচে রাখতে পারেন

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

এমনকি আপনার উপসর্গ শিরোনামে একটি ম্যাক্রো আরও ভাল সংজ্ঞায়িত করুন

#define NO_INIT \
- (instancetype)init NS_UNAVAILABLE; \
+ (instancetype)new NS_UNAVAILABLE;

এবং

@interface YourClass : NSObject
NO_INIT

// Your properties and messages

@end

2

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

এটি বলেছিল, অবজেক্টিভ-সিতে একটি ব্যক্তিগত পদ্ধতি তৈরির সর্বাধিক সাধারণ উপায় হ'ল বাস্তবায়ন ফাইলে একটি বিভাগ তৈরি করা এবং সেখানে " গোপনীয় " সমস্ত পদ্ধতি ঘোষণা করা। মনে রাখবেন যে এটি কলকে initদৌড়াতে সত্যই আটকাবে না , তবে কেউ যদি এটির চেষ্টা করে তবে সংকলক সতর্কবাণী ছুঁড়ে দেবে।

MyClass.m

@interface MyClass (PrivateMethods)
- (NSString*) init;
@end

@implementation MyClass

- (NSString*) init
{
    // code...
}

@end

একটি শালীন আছে এই বিষয়টি সম্পর্কে ম্যাকরামার্স.কম-এ থ্রেড রয়েছে।


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

2

ভাল সমস্যাটি কেন আপনি এটিকে "ব্যক্তিগত / অদৃশ্য" করতে পারেন না তার কারণ দিশ পদ্ধতিটি আইডিতে প্রেরণ হয়ে যায় (বরাদ্দ হিসাবে কোনও আইডি ফেরত আসে) আপনার ক্লাসে না

নোট করুন যে সংকলক (পরীক্ষক) এর বিন্দু থেকে কোনও আইডি কখনও টাইপ করা যেকোন কিছুতে প্রতিক্রিয়া জানাতে পারে (এটি রানডটাইমের সময় আইডিতে আসলে কী যায় তা পরীক্ষা করতে পারে না), তাই আপনি কেবল তখনই লুকিয়ে রাখতে পারবেন যখন কিছুই নেই (প্রকাশ্যে = ইন শিরোনাম) একটি পদ্ধতি init ব্যবহার করুন, সংকলনের চেয়ে জানা যাবে যে আইডির জন্য আরআইপি সাড়া দেওয়ার কোনও উপায় নেই, যেহেতু কোথাও কোনও দীক্ষা নেই (আপনার উত্সে, সমস্ত লিবস ইত্যাদি ...)

সুতরাং আপনি ব্যবহারকারীকে আর ডিগ্রি পাস করতে এবং সংকলক দ্বারা টুকরো টুকরো করতে নিষেধ করতে পারবেন না ... তবে আপনি যা করতে পারেন তা হ'ল ইআর কল করে ব্যবহারকারীকে প্রকৃত উদাহরণ পেতে বাধা দেওয়া is

কেবল init প্রয়োগ করে, যা শূন্য করে এবং এমন একটি (ব্যক্তিগত / অদৃশ্য) প্রারম্ভিক রয়েছে যা অন্য কারও নাম পাবে না (যেমন দীক্ষা, উদ্যোগসহ বিশেষ ...)

static SomeClass * SInstance = nil;

- (id)init
{
    // possibly throw smth. here
    return nil;
}

- (id)initOnce
{
    self = [super init];
    if (self) {
        return self;
    }
    return nil;
}

+ (SomeClass *) shared 
{
    if (nil == SInstance) {
        SInstance = [[SomeClass alloc] initOnce];
    }
    return SInstance;
}

দ্রষ্টব্য: যে কেউ এটি করতে পারে

SomeClass * c = [[SomeClass alloc] initOnce];

এবং এটি প্রকৃতপক্ষে একটি নতুন উদাহরণ ফেরত দেবে, তবে আমাদের প্রকল্পের সূচনাটি কোথাও প্রকাশ্যে (শিরোনামে) ঘোষিত না হলে এটি একটি সতর্কতা তৈরি করবে (আইডি হয়ত প্রতিক্রিয়া জানাতে পারে না ...) এবং যাইহোক এটি ব্যবহারকারী ব্যক্তির প্রয়োজন হবে আসল আরম্ভকারীটি হ'ল দীক্ষা exactly

আমরা এটিকে আরও আরও আটকাতে পারি, তবে প্রয়োজন নেই


0

আমার উল্লেখ করতে হবে যে সাবক্লাসে পদ্ধতিগুলি আড়াল করার জন্য দৃser়তা উত্থাপন এবং ব্যতিক্রম উত্থাপনের সার্থক উদ্দেশ্যে একটি বাজে ফাঁদ রয়েছে।

আমি জানো__unavailable যেমন তার প্রথম উদাহরণের জন্য ব্যাখ্যা হিসাবে ব্যবহার করার পরামর্শ দেব

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

- (SuperClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
    ...bla bla...
    return self;
}

- (SuperClass *)initWithLessParameters:(Type1 *)arg1
{
    self = [self initWithParameters:arg1 optional:DEFAULT_ARG2];
    return self;
}

সাবট্লাসে আমি যদি এটি করি তবে -ইনটেলিসপ্যারামিটারগুলির কী হবে তা কল্পনা করুন:

- (SubClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
    [self release];
    [super doesNotRecognizeSelector:_cmd];
    return nil;
}

এটি সূচিত করে যে আপনার ব্যক্তিগত (লুকানো) পদ্ধতিগুলি বিশেষত আরম্ভকরণ পদ্ধতিতে ব্যবহার করা উচিত, যদি না আপনি পদ্ধতিগুলিকে ওভাররাইড করার পরিকল্পনা করেন। তবে, এটি আরেকটি বিষয়, যেহেতু সুপারক্লাস বাস্তবায়নে আপনার সর্বদা সম্পূর্ণ নিয়ন্ত্রণ থাকে না। (এটি আমাকে __attribute ((objc_designated_initializer)) খারাপ অভ্যাস হিসাবে ব্যবহার করার বিষয়ে প্রশ্ন তোলে, যদিও আমি এটিকে গভীরতার সাথে ব্যবহার করি নি used)

এটি সূচিত করে যে আপনি যে পদ্ধতিগুলিতে সাবক্লাসে ওভাররাইড করা আবশ্যক সেগুলিতে দৃ in়তা এবং ব্যতিক্রমগুলি ব্যবহার করতে পারেন। ( উদ্দেশ্য-সি তে একটি বিমূর্ত শ্রেণি তৈরির মতো "বিমূর্ত" পদ্ধতিগুলি )

এবং, নতুন ক্লাস পদ্ধতিটি ভুলে যাবেন না।

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