আইডির পরিবর্তে উদাহরণস্বরূপ ব্যবহার করা কি উপকারী হবে?


226

ক্ল্যাং এমন একটি কীওয়ার্ড যুক্ত করেছে instancetypeযা আমি যতদূর দেখতে পাচ্ছি, এবং এর idমধ্যে একটি রিটার্ন টাইপ হিসাবে প্রতিস্থাপন করে ।-allocinit

instancetypeপরিবর্তে ব্যবহার করে কি কোনও সুবিধা আছে id?


10
না .. বরাদ্দ এবং ডিআইএসের জন্য নয়, তারা ইতিমধ্যে এটির মতো কাজ করে। উদাহরণস্বরূপ বিন্দুটি যাতে আপনি আচরণের মতো কাস্টম পদ্ধতিগুলি বরাদ্দ / আর ডি দিতে পারেন।
hooleyhoop

@hooleyhoop তারা এইভাবে কাজ করে না। তারা আইডি ফেরত। আইডি 'একটি ওবজ-সি অবজেক্ট'। এটাই সব। সংকলক রিটার্ন মান ব্যতীত অন্য কিছুই জানে না।
griotspeak

5
তারা এ জাতীয় কাজ করে, চুক্তি এবং ধরণের চেকিং ইতিমধ্যে init এর জন্য ঘটছে, কেবলমাত্র প্রশিক্ষকদের জন্য আপনার এটির দরকার আছে। nshipster.com/instancetype
কোকোডে

বিষয়গুলি বেশ খানিকটা এগিয়েছে, হ্যাঁ। সম্পর্কিত ফলাফলের ধরনগুলি তুলনামূলকভাবে নতুন এবং অন্যান্য পরিবর্তনগুলির অর্থ এটি শীঘ্রই একটি আরও পরিষ্কার সমস্যা হবে।
griotspeak

1
আমি কেবল মন্তব্য করতে চাই যে এখন আইওএস 8 এ ফিরে আসার জন্য প্রচুর পদ্ধতি ব্যবহার করা idহয়েছিল instancetype, এমনকি এটি initথেকেও প্রতিস্থাপন করা হয়েছে NSObject। আপনি যদি আপনার কোডটি সুইফটের সাথে সামঞ্জস্য করতে চান তবে আপনাকে ব্যবহার করতে হবেinstancetype
Hola Soy Edu Feliz নাভিদাদ

উত্তর:


192

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

কেবল সেখানে এটি ব্যবহার করুন যেখানে এটি অবশ্যই উপলব্ধি করে (অর্থাত এমন একটি পদ্ধতি যা সেই শ্রেণীর উদাহরণ ফিরিয়ে দেয়); আইডি এখনও দরকারী।


8
alloc, initইত্যাদি স্বয়ংক্রিয়ভাবে instancetypeসংকলক দ্বারা প্রচারিত হয় । এর অর্থ নেই যে কোনও লাভ নেই; আছে, কিন্তু এটা না।
স্টিভেন ফিশার

10
এটি বেশিরভাগ সুবিধার্থী
নির্মাতাদের

5
এটি ২০১১ সালে সিংহকে ছেড়ে দেওয়ার সাথে সাথে (এবং সহায়তা করতে) এআরসি দিয়ে প্রবর্তন করা হয়েছিল। কোকোয় ব্যাপকভাবে গ্রহণের বিষয়টি জটিল করে তোলে যে সমস্ত প্রার্থী পদ্ধতিগুলি [নাম বরফ] এর পরিবর্তে [স্ব বরাদ্দ] করেন কিনা তা দেখার জন্য নিরীক্ষণ করতে হবে বরাদ্দ], কারণ এটি করা + বিভ্রান্তিকর হবে [সামসসব্লাস সুবিধার্থে কনস্ট্রাক্টর] সহ + সুবিধামত কনস্ট্রাক্টর উদাহরণস্বরূপ প্রত্যাবর্তন করার ঘোষণা দিয়েছিল এবং এটি সামসসব্লক্লাসের কোনও উদাহরণ ফেরত না দেয়।
ক্যাটফিশ_মন

2
'আইডি' কেবলমাত্র উদাহরণস্বরূপে রূপান্তরিত হয় যখন সংকলকটি পদ্ধতি পরিবারকে অনুমান করতে পারে। এটি অবশ্যই সুবিধার্থী নির্মাণকারী বা অন্যান্য আইডি-রিটার্নিং পদ্ধতির জন্য এটি করে না।
ক্যাটফিশ_মান

4
নোট করুন যে আইওএস 7-এ, ফাউন্ডেশনের অনেকগুলি পদ্ধতি উদাহরণস্বরূপে রূপান্তরিত হয়েছে। আমি ব্যক্তিগতভাবে এই ক্যাচটি ভুল পূর্ববর্তী বিদ্যমান কোডের কমপক্ষে 3 টি ক্ষেত্রে দেখেছি।
ক্যাটফিশ_মান

336

হ্যাঁ, instancetypeএটি প্রযোজ্য সমস্ত ক্ষেত্রেই ব্যবহার করার সুবিধা রয়েছে । আমি আরও বিশদে ব্যাখ্যা করব, তবে আমাকে এই সাহসী বক্তব্য দিয়ে শুরু করতে দাও: instancetypeএটি যখনই উপযুক্ত হয় ব্যবহার করুন , যখনই কোনও শ্রেণি একই শ্রেণীর উদাহরণ দেয় returns

আসলে, অ্যাপল এখন এই বিষয়ে যা বলেছে তা এখানে:

আপনার কোডে, যেখানে উপযুক্ত সেখানে idরিটার্ন মান হিসাবে উপস্থিতিগুলি প্রতিস্থাপন করুন instancetype। এটি সাধারণত initপদ্ধতি এবং ক্লাস কারখানার পদ্ধতিগুলির ক্ষেত্রে। যদিও সংকলক স্বয়ংক্রিয়ভাবে "বরাদ্দ," "আরম্ভ," বা "নতুন" দিয়ে শুরু হওয়া পদ্ধতিগুলির রূপান্তর করে এবং ফিরে আসার মতো ধরণের idরিটার্ন থাকে instancetype, এটি অন্যান্য পদ্ধতিগুলিতে রূপান্তর করে না। উদ্দেশ্য-সি কনভেনশনটি instancetypeসমস্ত পদ্ধতির জন্য স্পষ্টভাবে লিখতে হয় write

উপায়টি অতিক্রম করার সাথে, আসুন এবং এটি কেন ভাল ধারণা তা ব্যাখ্যা করি।

প্রথমত, কিছু সংজ্ঞা:

 @interface Foo:NSObject
 - (id)initWithBar:(NSInteger)bar; // initializer
 + (id)fooWithBar:(NSInteger)bar;  // class factory
 @end

ক্লাস কারখানার জন্য, আপনার সর্বদা ব্যবহার করা উচিত instancetype। কম্পাইলার স্বয়ংক্রিয়ভাবে রূপান্তর না idকরার instancetype। যে idএকটি জেনেরিক অবজেক্ট। তবে আপনি যদি এটি একটি instancetypeসংকলক তৈরি করেন তবে পদ্ধতিটি কী ধরণের জিনিসটি ফিরে আসে তা জানে।

এই না একটি একাডেমিক সমস্যা। উদাহরণস্বরূপ, [[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]ম্যাক ওএস এক্স-এ একটি ত্রুটি উত্পন্ন করবে ( কেবলমাত্র ) 'রাইটড্যাটা:' নামের একাধিক পদ্ধতিতে অমিল ফলাফল, প্যারামিটারের ধরন বা বৈশিষ্ট্য পাওয়া গেছে । কারণটি হ'ল এনএসফাইহ্যান্ডল এবং এনএসআরএল হ্যান্ডেল উভয়ই একটি সরবরাহ করে writeData:। যেহেতু [NSFileHandle fileHandleWithStandardOutput]রিটার্ন দেয় একটি id, সংকলকটি নির্দিষ্ট নয় যে কোন শ্রেণিতে কল writeData:করা হচ্ছে।

আপনার এই চারপাশে কাজ করা দরকার, এটি ব্যবহার করে:

[(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData];

বা:

NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardOutput];
[fileHandle writeData:formattedData];

অবশ্যই, আরও ভাল সমাধানটি রিটার্ন fileHandleWithStandardOutputহিসাবে ঘোষণা করা instancetype। তারপরে কাস্ট বা অ্যাসাইনমেন্টের প্রয়োজন নেই।

(নোট করুন যে আইওএস-এ, উদাহরণটি কেবল সেখানে NSFileHandleসরবরাহ করে ত্রুটি তৈরি করবে না writeData:Other অন্যান্য উদাহরণ রয়েছে যেমন length, যা একটি CGFloatথেকে আসে UILayoutSupportতবে একটি NSUIntegerথেকে আসে NSString))

দ্রষ্টব্য : যেহেতু আমি এটি লিখেছি, ম্যাকস শিরোনামগুলির NSFileHandleপরিবর্তে একটি এর পরিবর্তে পরিবর্তন করা হয়েছে id

আরম্ভকারীদের জন্য, এটি আরও জটিল। আপনি যখন এটি টাইপ করবেন:

- (id)initWithBar:(NSInteger)bar

… সংকলক পরিবর্তে আপনি এটি টাইপ করে ভান করবেন:

- (instancetype)initWithBar:(NSInteger)bar

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

এর তিনটি সুবিধা রয়েছে:

  1. স্পষ্ট। আপনার কোডটি অন্য কিছু না করে যা বলছে তাই করছে।
  2. প্যাটার্ন। আপনি এটি গুরুত্বপূর্ণ যে সময়ের জন্য ভাল অভ্যাস তৈরি করছেন, যা বিদ্যমান।
  3. সমন্নয়। আপনি আপনার কোডে কিছু ধারাবাহিকতা স্থাপন করেছেন যা এটি আরও পাঠযোগ্য।

স্পষ্ট

এটা যে কোন সত্য প্রযুক্তিগত ফিরে সুবিধার instancetypeএকটি থেকে init। কিন্তু এই কারণ কম্পাইলার স্বয়ংক্রিয়ভাবে পরিবর্তিত হয় idথেকে instancetype। আপনি এই বিচক্ষণতার উপর নির্ভর করছেন; আপনি যখন লিখছেন যে একটি initফেরত দেয় id, সংকলক এটি ব্যাখ্যা করছে যেন এটি কোনও ফেরত দেয় instancetype

এগুলি সংকলকের সমতুল্য :

- (id)initWithBar:(NSInteger)bar;
- (instancetype)initWithBar:(NSInteger)bar;

এগুলি আপনার চোখের সমতুল্য নয়। সর্বোপরি, আপনি পার্থক্যটি উপেক্ষা করতে এবং এটির উপরে স্কিম শিখতে পারবেন। এটি এমন কিছু নয় যা আপনার উপেক্ষা করা শিখতে হবে।

প্যাটার্ন

যদিও সেখানে কোন পার্থক্য initএবং অন্যান্য পদ্ধতি, সেখানে হয় তাড়াতাড়ি আপনি একটি বর্গ কারখানা সংজ্ঞায়িত হিসাবে একটি পার্থক্য।

এই দুটি সমতুল্য নয়:

+ (id)fooWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;

আপনি দ্বিতীয় ফর্ম চান। আপনি যদি instancetypeকোনও কনস্ট্রাক্টরের রিটার্ন টাইপ হিসাবে টাইপ করতে অভ্যস্ত হন তবে আপনি প্রতিবারই এটি পেয়ে যাবেন।

দৃঢ়তা

পরিশেষে, কল্পনা করুন আপনি যদি এটি একসাথে রাখেন: আপনি একটি initফাংশন এবং একটি শ্রেণিকেন্দ্রও চান want

আপনি যদি এর idজন্য ব্যবহার করেন তবে আপনি initএই জাতীয় কোডটি সহ শেষ করবেন:

- (id)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;

তবে আপনি যদি ব্যবহার করেন তবে আপনি এটি instancetypeপাবেন:

- (instancetype)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;

এটি আরও সামঞ্জস্যপূর্ণ এবং আরও পঠনযোগ্য। তারা একই জিনিস ফেরত দেয়, এবং এখন এটি সুস্পষ্ট।

উপসংহার

আপনি যদি ইচ্ছাকৃতভাবে পুরানো সংকলকগুলির জন্য কোডটি না লিখে থাকেন তবে instancetypeউপযুক্ত হলে আপনার ব্যবহার করা উচিত ।

ফিরে আসা কোনও বার্তা লেখার আগে আপনার দ্বিধা করা উচিত id। নিজেকে জিজ্ঞাসা করুন: এটি কি এই শ্রেণীর কোনও উদাহরণ ফিরিয়ে দিচ্ছে? যদি তাই হয়, এটি একটি instancetype

কিছু ক্ষেত্রে অবশ্যই আপনাকে ফিরে যেতে idহবে তবে আপনি সম্ভবত instancetypeআরও ঘন ঘন ব্যবহার করবেন ।


4
আমি যখন এটি জিজ্ঞাসা করেছি তখন এটির বেশিরভাগ সময় হয়ে গেছে এবং আপনি এখানে যেভাবে বক্তব্য রেখেছিলেন তার মতো পদক্ষেপ গ্রহণ করেছি long আমি এটি এখানে যেতে দিলাম কারণ আমি মনে করি যে দুর্ভাগ্যক্রমে, এটি আরম্ভের জন্য শৈলীর একটি সমস্যা হিসাবে বিবেচিত হবে এবং পূর্ববর্তী প্রতিক্রিয়াগুলিতে উপস্থাপিত তথ্যগুলি প্রশ্নের উত্তরটি বেশ পরিষ্কার করে দিয়েছে।
griotspeak

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

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

4
instancetypeবনাম idসত্যই কোনও স্টাইলের সিদ্ধান্ত নয়। চারপাশের সাম্প্রতিক পরিবর্তনগুলি instancetypeএটি স্পষ্ট করে instancetype-init
তুলেছে

2
আপনি বলেছিলেন আইডি ব্যবহারের কারণ রয়েছে, আপনি কি বিশদভাবে বলতে পারবেন? আমি কেবল দুটিই ভাবতে পারি তা হ'ল ব্রিভিটি এবং পিছনের দিকের সামঞ্জস্য; উভয়ই আপনার অভিপ্রায় প্রকাশের ব্যয় বিবেচনা করে, আমি মনে করি এগুলি সত্যই দুর্বল যুক্তি।
স্টিভেন ফিশার

10

উপরের উত্তরগুলি এই প্রশ্নের ব্যাখ্যা দেওয়ার জন্য যথেষ্ট বেশি। আমি কোডিংয়ের ক্ষেত্রে এটি বুঝতে পাঠকদের জন্য একটি উদাহরণ যুক্ত করতে চাই।

শ্রেণীকক্ষে

@interface ClassA : NSObject

- (id)methodA;
- (instancetype)methodB;

@end

ক্লাস বি

@interface ClassB : NSObject

- (id)methodX;

@end

TestViewController.m

#import "ClassA.h"
#import "ClassB.h"

- (void)viewDidLoad {

    [[[[ClassA alloc] init] methodA] methodX]; //This will NOT generate a compiler warning or error because the return type for methodA is id. Eventually this will generate exception at runtime

    [[[[ClassA alloc] init] methodB] methodX]; //This will generate a compiler error saying "No visible @interface ClassA declares selector methodX" because the methodB returns instanceType i.e. the type of the receiver
}

আপনি যদি # ইম্পোর্ট "ClassB.h" ব্যবহার না করেন তবে এটি কেবল একটি সংকলক ত্রুটি তৈরি করবে। অন্যথায়, সংকলক ধরে নিবে যে আপনি জানেন যে আপনি কী করছেন। উদাহরণস্বরূপ, নিম্নলিখিত সংকলনগুলি, তবে রানটাইমের সময় ক্র্যাশ হয়েছে: id myNumber = @ (1); আইডি iAsumeThatWasAnArray = আমার সংখ্যা [0]; id iAssumeThatWasAD शब्दकोয় = [আমার সংখ্যা নম্বরফোরকি: @ "কী"];
ওলডোর

1

আপনি ডিজাইনেটেড ইনিশিয়ালাইজারেও বিশদ পেতে পারেন

**

INSTANCETYPE

** এই কীওয়ার্ডটি কেবল রিটার্ন টাইপের জন্য ব্যবহার করা যেতে পারে, এটি রিসিভারের রিটারের সাথে মেলে। init পদ্ধতি সর্বদা উদাহরণস্বরূপ প্রত্যাবর্তনের ঘোষণা করে। দলীয় উদাহরণস্বরূপ, কেন রিটার্ন টাইপ পার্টি করবেন না? পার্টির ক্লাসটি যদি সর্বদা ক্লাস করা থাকে তবে এটি সমস্যার কারণ হতে পারে। সাবক্লাসটি ইনিশিয়ালাইজার এবং এর রিটার্নের ধরণ সহ পার্টি থেকে সমস্ত পদ্ধতি উত্তরাধিকার সূত্রে গ্রহণ করবে। সাবক্লাসের কোনও উদাহরণ যদি এই ইনিশিয়ালাইজার বার্তা প্রেরণ করা হত, তা কি ফিরে আসবে? পার্টির উদাহরণের জন্য কোনও পয়েন্টার নয়, সাবক্লাসের উদাহরণের জন্য একটি পয়েন্টার। আপনি মনে করতে পারেন যে এটি কোনও সমস্যা নয়, আমি রিটার্নের ধরণের পরিবর্তন করতে সাবক্লাসের প্রারম্ভিকটিকে ওভাররাইড করব। তবে অবজেক্টিভ-সি তে আপনার একই নির্বাচক এবং বিভিন্ন রিটার্নের ধরণের (বা যুক্তি) দুটি পদ্ধতি থাকতে পারে না। একটি সূচনা পদ্ধতি ফিরে আসে তা নির্দিষ্ট করে "

আইডি

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

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