আমি কি একটি NSMutableArray
উদাহরণ তৈরি করতে পারি যেখানে সমস্ত উপাদানগুলি টাইপযুক্ত SomeClass
?
উত্তর:
-addSomeClass:
সংকলন-স্ট্যাটিক ধরণের চেকিংয়ের অনুমতি দেওয়ার জন্য আপনি কোনও পদ্ধতির সাথে একটি বিভাগ তৈরি করতে পারেন (যাতে সংকলকটি আপনাকে জানতে পারে যে কোনও অবজেক্ট যোগ করার চেষ্টা করতে পারে তবে সেই পদ্ধতির মাধ্যমে এটি একটি পৃথক শ্রেণি), তবে এটি বাস্তবায়নের কোনও সত্যিকারের উপায় নেই একটি অ্যারেতে কেবল প্রদত্ত শ্রেণীর অবজেক্ট থাকে।
সাধারণভাবে, অবজেক্টিভ-সি তে এই জাতীয় বাধা থাকার প্রয়োজন বলে মনে হচ্ছে না। আমি মনে করি না যে আমি কোনও অভিজ্ঞ কোকো প্রোগ্রামার সেই বৈশিষ্ট্যের জন্য শুভেচ্ছা শুনেছি heard কেবলমাত্র লোকেরা মনে হয় যে অন্য ভাষা থেকে প্রোগ্রামার যারা এখনও সেই ভাষাগুলিতে চিন্তাভাবনা করে। আপনি যদি কেবলমাত্র একটি অ্যারেতে প্রদত্ত শ্রেণীর অবজেক্টগুলি চান তবে কেবল সেখানে শ্রেণীর অবজেক্টগুলি স্টিক করুন। যদি আপনি পরীক্ষা করতে চান যে আপনার কোডটি সঠিকভাবে আচরণ করছে, এটি পরীক্ষা করুন।
এখনও কেউ এটিকে এখানে রাখেনি, তাই আমি এটি করব!
এটি এখন সরকারীভাবে অবজেক্টিভ-সি তে সমর্থিত। এক্সকোড 7 হিসাবে, আপনি নিম্নলিখিত সিনট্যাক্সটি ব্যবহার করতে পারেন:
NSArray<MyClass *> *myArray = @[[MyClass new], [MyClass new]];
বিঃদ্রঃ
এটি লক্ষ্য করা গুরুত্বপূর্ণ যে এগুলি কেবল সংকলক সতর্কতা এবং আপনি প্রযুক্তিগতভাবে কোনও অ্যারেটিকে আপনার অ্যারেতে সন্নিবেশ করতে পারেন। এমন স্ক্রিপ্টগুলি উপলব্ধ রয়েছে যা সমস্ত সতর্কতাগুলিকে ত্রুটিতে পরিণত করে যা বিল্ডিং প্রতিরোধ করবে।
nonnull
এক্সকোড 6 এ ব্যবহার করতে পারি এবং যতদূর আমার মনে আছে, সেগুলি একই সময়ে প্রবর্তিত হয়েছিল। এছাড়াও, এই জাতীয় ধারণাগুলির ব্যবহার কি এক্সকোড সংস্করণ বা আইওএস সংস্করণে নির্ভর করে?
@property (nonatomic, strong) NSArray<id<SomeProtocol>>* protocolObjects;
দেখতে কিছুটা ক্লিঙ্কি আছে তবে কৌতুকটি কি!
এটি দৃ strongly়ভাবে টাইপ করা ভাষাগুলি (সি ++ বা জাভা এর মতো) থেকে দুর্বল বা গতিশীলভাবে টাইপ করা ভাষায় পাইথন, রুবি বা অবজেক্টিভ-সি-তে রূপান্তরকারীদের কাছে তুলনামূলকভাবে সাধারণ প্রশ্ন। অবজেক্টিভ-সি-তে বেশিরভাগ অবজেক্ট NSObject
(টাইপ id
) থেকে উত্তরাধিকারী হয় ( বাকী অংশগুলি অন্য মূল শ্রেণীর যেমন উত্তরাধিকার সূত্রে যেমন NSProxy
টাইপও করা যায় id
), এবং যে কোনও বস্তুতে কোনও বার্তা প্রেরণ করা যায়। অবশ্যই, কোনও বার্তা পাঠানো যে এটি সনাক্ত করে না এটি রানটাইম ত্রুটির কারণ হতে পারে (এবং সংকলক সতর্কবার্তাও সৃষ্টি করবে)যথাযথ -W পতাকা সহ)। আপনি যে বার্তা পাঠিয়েছেন তাতে কোনও উদাহরণ সাড়া না দেওয়া ততক্ষণ আপনি এটি কোন শ্রেণীর অন্তর্ভুক্ত তা যত্নশীল না করতে পারেন। এটিকে প্রায়শই "হাঁসের টাইপিং" হিসাবে উল্লেখ করা হয় কারণ "যদি এটি হাঁসের মতো ঝাঁকুনি দেয় [অর্থাত্ কোনও নির্বাচককে প্রতিক্রিয়া জানায়], এটি একটি হাঁস [অর্থাৎ এটি বার্তাটি পরিচালনা করতে পারে; কে এটি কোন শ্রেণীর যত্ন করে]"।
কোনও -(BOOL)respondsToSelector:(SEL)selector
পদ্ধতি কোনও পদ্ধতিতে রানের সময় কোনও নির্বাচককে সাড়া দেয় কিনা তা আপনি পরীক্ষা করতে পারেন can ধরে নেওয়া যাক আপনি একটি অ্যারের মধ্যে প্রতিটি উদাহরণের উপর একটি পদ্ধতি কল করতে চান কিন্তু নিশ্চিত না যে সমস্ত উদাহরণ বার্তা সব ব্যবস্থা করতে সক্ষম (তাই আপনি শুধু ব্যবহার করতে পারবেন না হয় NSArray
এর -[NSArray makeObjectsPerformSelector:]
, ভালো কিছু কাজ করবে:
for(id o in myArray) {
if([o respondsToSelector:@selector(myMethod)]) {
[o myMethod];
}
}
আপনি কল করতে চান এমন পদ্ধতি (গুলি) প্রয়োগ করে এমন উদাহরণগুলির জন্য উত্স কোডটি যদি আপনি নিয়ন্ত্রণ করেন তবে আরও সাধারণ পদ্ধতির @protocol
মধ্যে সেই পদ্ধতিগুলির সংজ্ঞা দেওয়া এবং ঘোষণা করা হবে যে প্রশ্নে ক্লাসগুলি তাদের ঘোষণায় সেই প্রোটোকলটি প্রয়োগ করে। এই ব্যবহারে, একটি @protocol
জাভা ইন্টারফেস বা একটি সি ++ বিমূর্ত বেস শ্রেণীর সাথে সাদৃশ্যযুক্ত। তারপরে আপনি প্রতিটি পদ্ধতির প্রতিক্রিয়া না দিয়ে পুরো প্রোটোকলের সাথে সংযোগের জন্য পরীক্ষা করতে পারেন। পূর্ববর্তী উদাহরণে, এটি খুব বেশি পার্থক্য করতে পারে না, তবে আপনি যদি একাধিক পদ্ধতি কল করে থাকেন তবে এটি জিনিসগুলিকে সহজতর করতে পারে। উদাহরণটি তখন হবে:
for(id o in myArray) {
if([o conformsToProtocol:@protocol(MyProtocol)]) {
[o myMethod];
}
}
অনুমান MyProtocol
করে ঘোষণা myMethod
। এই দ্বিতীয় পদ্ধতির পক্ষে নেওয়া হয়েছে কারণ এটি কোডের উদ্দেশ্যটিকে প্রথমটির চেয়ে বেশি স্পষ্ট করে।
প্রায়শই, এই পদ্ধতির মধ্যে একটি আপনাকে অ্যারেতে থাকা সমস্ত অবজেক্ট নির্দিষ্ট ধরণের কিনা তা দেখাশোনা থেকে মুক্তি দেয়। আপনি যদি এখনও যত্ন নেন তবে মানক গতিশীল ভাষার পদ্ধতির সাথে ইউনিট পরীক্ষা, ইউনিট পরীক্ষা, ইউনিট পরীক্ষা। যেহেতু এই প্রয়োজনীয়তার একটি রিগ্রেশন একটি (সম্ভবত অপরিবর্তনযোগ্য) রানটাইম (সময় সংকলন নয়) ত্রুটি তৈরি করবে, তাই আচরণটি যাচাই করার জন্য আপনার পরীক্ষার কভারেজ থাকা দরকার যাতে আপনি বুনো কোনও ক্র্যাশারকে মুক্তি না পান। এই ক্ষেত্রে, অ্যারেটি সংশোধন করে এমন একটি ক্রিয়াকলাপ তৈরি করুন, তারপরে যাচাই করুন যে অ্যারেতে সমস্ত দৃষ্টান্ত একটি নির্দিষ্ট শ্রেণীর অন্তর্ভুক্ত। যথাযথ পরীক্ষার কভারেজ সহ, আপনার এমনকি পরিচয় সনাক্তকরণের অতিরিক্ত রানটাইম ওভারহেডের প্রয়োজন নেই। আপনি ভাল ইউনিট পরীক্ষা কভারেজ আছে, তাই না?
id
যেখানে প্রয়োজন সেখানে বাদে আপনি কাঁচা গুলি ব্যবহার করবেন না , জাভা কোডার্সের চেয়ে আরও বেশি কোনও Object
এস পাস করতে পারবেন না । কেন না? আপনি ইউনিট পরীক্ষা পেয়েছি এটি প্রয়োজন হবে না? কারণ এটি সেখানে রয়েছে এবং আপনার কোডটি আরও রক্ষণাবেক্ষণযোগ্য করে তোলে যেমন অ্যারে টাইপ করা হয়। লোকেরা প্ল্যাটফর্মে বিনিয়োগকারীদের মতো একটি বিন্দু স্বীকার করতে ইচ্ছুক নয়, এবং এই কারণটি বাদ দেওয়ার কারণগুলি কেন আবিষ্কার হচ্ছে তা আসলে একটি সুবিধা।
আপনি NSMutableArray
ধরণের সুরক্ষা প্রয়োগ করতে সাবক্লাস করতে পারেন ।
NSMutableArray
একটি ক্লাস ক্লাস্টার , সুতরাং সাবক্লাসিং তুচ্ছ নয়। আমি উত্তরাধিকার সূত্রে শেষ হয়েছি NSArray
এবং সেই শ্রেণীর ভিতরে থাকা একটি অ্যারেতে আমন্ত্রণগুলি ফরোয়ার্ড করেছি। ফলাফলের একটি বর্গ বলা হয় ConcreteMutableArray
যা হয় উপশ্রেণী করা সহজ। আমি এখানে যা এলাম তা এখানে:
আপডেট: ক্লাস ক্লাস্টার সাবক্লাসিংয়ের বিষয়ে মাইকের অ্যাশ থেকে এই ব্লগ পোস্টটি চেকআউট করুন।
আপনার প্রকল্পে এই ফাইলগুলি অন্তর্ভুক্ত করুন, তারপরে ম্যাক্রো ব্যবহার করে আপনার যে কোনও ধরণের পছন্দ করুন:
MyArrayTypees.h
CUSTOM_ARRAY_INTERFACE(NSString)
CUSTOM_ARRAY_INTERFACE(User)
MyArrayTypees.m
CUSTOM_ARRAY_IMPLEMENTATION(NSString)
CUSTOM_ARRAY_IMPLEMENTATION(User)
ব্যবহার:
NSStringArray* strings = [NSStringArray array];
[strings add:@"Hello"];
NSString* str = [strings get:0];
[strings add:[User new]]; //compiler error
User* user = [strings get:0]; //compiler error
অন্যান্য চিন্তা
NSArray
সিরিয়ালাইজেশন / ডেসারিয়ালাইজেশন সমর্থন থেকে এটি উত্তরাধিকার সূত্রে প্রাপ্তআপনার স্বাদের উপর নির্ভর করে আপনি জেনেরিক পদ্ধতিগুলি ওভাররাইড / লুকিয়ে রাখতে চান
- (void) addObject:(id)anObject
কটাক্ষপাত আছে https://github.com/tomersh/Objective-C-Generics , একটি কম্পাইল-টাইম উদ্দেশ্য সি জন্য (প্রাক প্রসেসর প্রয়োগ) জেনেরিক্স বাস্তবায়ন। এই ব্লগ পোস্ট একটি সুন্দর ওভারভিউ আছে। মূলত আপনি কম্পাইল-টাইম চেকিং (সতর্কতা বা ত্রুটি) পান তবে জেনেরিকদের জন্য রানটাইম পেনাল্টি নেই।
এই গিথুব প্রকল্পটি ঠিক সেই কার্যকারিতা কার্যকর করে।
এরপরে আপনি <>
বন্ধনীগুলিও ব্যবহার করতে পারেন ঠিক যেমন আপনি সি # তে।
তাদের উদাহরণ থেকে:
NSArray<MyClass>* classArray = [NSArray array];
NSString *name = [classArray lastObject].name; // No cast needed
একটি সম্ভাব্য উপায় এনএসআরিকে সাবক্লাসিং করা যেতে পারে তবে অ্যাপল এটি না করার পরামর্শ দেয়। টাইপড এনএসআরির প্রকৃত প্রয়োজনের দ্বিগুণ ভাবা সহজ।
আমি একটি এনএসআরাই সাবক্লাস তৈরি করেছি যা এনএসআরাইয়ের ক্লাস-ক্লাস্টার প্রকৃতির সমস্যাগুলি এড়াতে কোনও এনএসআরাই অবজেক্টকে ব্যাকিং আইভার হিসাবে ব্যবহার করছে। এটি কোনও অবজেক্ট যোগ করা বা প্রত্যাখ্যান করতে ব্লক লাগে takes
কেবল এনএসএসস্ট্রিং অবজেক্টগুলিকে অনুমতি দেওয়ার জন্য আপনি একটি AddBlock
হিসাবে সংজ্ঞায়িত করতে পারেন
^BOOL(id element) {
return [element isKindOfClass:[NSString class]];
}
আপনি কোনও কী FailBlock
করতে হবে তা নির্ধারণ করতে সংজ্ঞায়িত করতে পারেন, যদি কোনও উপাদান পরীক্ষায় ব্যর্থ হয় - ফিল্টারিংয়ের জন্য চূড়ান্তভাবে ব্যর্থ হয়, এটি অন্য অ্যারেতে যুক্ত করে, বা - এটি ডিফল্ট - একটি ব্যতিক্রম বাড়াতে পারে।
ভিএসব্লকটেষ্টডজেক্টআররে
#import <Foundation/Foundation.h>
typedef BOOL(^AddBlock)(id element);
typedef void(^FailBlock)(id element);
@interface VSBlockTestedObjectArray : NSMutableArray
@property (nonatomic, copy, readonly) AddBlock testBlock;
@property (nonatomic, copy, readonly) FailBlock failBlock;
-(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock Capacity:(NSUInteger)capacity;
-(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock;
-(id)initWithTestBlock:(AddBlock)testBlock;
@end
ভিএসব্লকটিস্টডোবজেক্টআর্রে.মি
#import "VSBlockTestedObjectArray.h"
@interface VSBlockTestedObjectArray ()
@property (nonatomic, retain) NSMutableArray *realArray;
-(void)errorWhileInitializing:(SEL)selector;
@end
@implementation VSBlockTestedObjectArray
@synthesize testBlock = _testBlock;
@synthesize failBlock = _failBlock;
@synthesize realArray = _realArray;
-(id)initWithCapacity:(NSUInteger)capacity
{
if (self = [super init]) {
_realArray = [[NSMutableArray alloc] initWithCapacity:capacity];
}
return self;
}
-(id)initWithTestBlock:(AddBlock)testBlock
FailBlock:(FailBlock)failBlock
Capacity:(NSUInteger)capacity
{
self = [self initWithCapacity:capacity];
if (self) {
_testBlock = [testBlock copy];
_failBlock = [failBlock copy];
}
return self;
}
-(id)initWithTestBlock:(AddBlock)testBlock FailBlock:(FailBlock)failBlock
{
return [self initWithTestBlock:testBlock FailBlock:failBlock Capacity:0];
}
-(id)initWithTestBlock:(AddBlock)testBlock
{
return [self initWithTestBlock:testBlock FailBlock:^(id element) {
[NSException raise:@"NotSupportedElement" format:@"%@ faild the test and can't be add to this VSBlockTestedObjectArray", element];
} Capacity:0];
}
- (void)dealloc {
[_failBlock release];
[_testBlock release];
self.realArray = nil;
[super dealloc];
}
- (void) insertObject:(id)anObject atIndex:(NSUInteger)index
{
if(self.testBlock(anObject))
[self.realArray insertObject:anObject atIndex:index];
else
self.failBlock(anObject);
}
- (void) removeObjectAtIndex:(NSUInteger)index
{
[self.realArray removeObjectAtIndex:index];
}
-(NSUInteger)count
{
return [self.realArray count];
}
- (id) objectAtIndex:(NSUInteger)index
{
return [self.realArray objectAtIndex:index];
}
-(void)errorWhileInitializing:(SEL)selector
{
[NSException raise:@"NotSupportedInstantiation" format:@"not supported %@", NSStringFromSelector(selector)];
}
- (id)initWithArray:(NSArray *)anArray { [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithContentsOfFile:(NSString *)aPath{ [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithContentsOfURL:(NSURL *)aURL{ [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithObjects:(id)firstObj, ... { [self errorWhileInitializing:_cmd]; return nil;}
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { [self errorWhileInitializing:_cmd]; return nil;}
@end
এটি ব্যবহার করুন:
VSBlockTestedObjectArray *stringArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) {
return [element isKindOfClass:[NSString class]];
} FailBlock:^(id element) {
NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSString", element);
}];
VSBlockTestedObjectArray *numberArray = [[VSBlockTestedObjectArray alloc] initWithTestBlock:^BOOL(id element) {
return [element isKindOfClass:[NSNumber class]];
} FailBlock:^(id element) {
NSLog(@"%@ can't be added, didn't pass the test. It is not an object of class NSNumber", element);
}];
[stringArray addObject:@"test"];
[stringArray addObject:@"test1"];
[stringArray addObject:[NSNumber numberWithInt:9]];
[stringArray addObject:@"test2"];
[stringArray addObject:@"test3"];
[numberArray addObject:@"test"];
[numberArray addObject:@"test1"];
[numberArray addObject:[NSNumber numberWithInt:9]];
[numberArray addObject:@"test2"];
[numberArray addObject:@"test3"];
NSLog(@"%@", stringArray);
NSLog(@"%@", numberArray);
এটি কেবল একটি উদাহরণ কোড এবং বাস্তব বিশ্বের অ্যাপ্লিকেশনটিতে কখনই ব্যবহৃত হয়নি। এটি করার জন্য সম্ভবত মুর এনএসআরাই পদ্ধতি প্রয়োগ করা দরকার।
যদি আপনি সি ++ এবং অবজেক্টিভি-সি মিশ্রণ করেন (অর্থাত মিমি ফাইল টাইপ ব্যবহার করে), আপনি জোড় বা টিপল ব্যবহার করে টাইপিং প্রয়োগ করতে পারেন। উদাহরণস্বরূপ, নিম্নলিখিত পদ্ধতিতে, আপনি std :: জোড়া টাইপের একটি C ++ অবজেক্ট তৈরি করতে পারেন, ওসি র্যাপার প্রকারের (একটি স্ট্যান্ড :: জোড়ের মোড়ক যা আপনাকে সংজ্ঞায়িত করতে হবে) একটি বস্তুতে রূপান্তর করতে পারেন, এবং তারপরে এটি কিছুতে পাঠাতে পারেন অন্যান্য ওসি পদ্ধতি, যার মধ্যে আপনাকে ওসি অবজেক্টটি C ++ অবজেক্টে ব্যবহারের জন্য রূপান্তর করতে হবে। ওসি পদ্ধতিটি কেবল ওসি মোড়কের ধরণটি গ্রহণ করে, সুতরাং প্রকারের সুরক্ষা নিশ্চিত করে। এমনকি প্রকারের সুরক্ষার সুবিধার্থে আরও উন্নত সি ++ বৈশিষ্ট্য লাভের জন্য আপনি টুপল, বৈকল্পিক টেম্পলেট, টাইপলিস্ট ব্যবহার করতে পারেন।
- (void) tableView:(UITableView*) tableView didSelectRowAtIndexPath:(NSIndexPath*) indexPath
{
std::pair<UITableView*, NSIndexPath*> tableRow(tableView, indexPath);
ObjCTableRowWrapper* oCTableRow = [[[ObjCTableRowWrapper alloc] initWithTableRow:tableRow] autorelease];
[self performSelector:@selector(selectRow:) withObject:oCTableRow];
}
2020, সরল উত্তর। এটি ঠিক তাই ঘটেছে যে আমার প্রকারের সাথে একটি পরিবর্তনীয় অ্যারের প্রয়োজন NSString
।
বাক্য গঠন:
Type<ArrayElementType *> *objectName;
উদাহরণ:
@property(nonatomic, strong) NSMutableArray<NSString *> *buttonInputCellValues;