How do I make and use a Queue in Objective-C? - objective-c

I want to use a queue data structure in my Objective-C program. In C++ I'd use the STL queue. What is the equivalent data structure in Objective-C? How do I push/pop items?

Ben's version is a stack instead of a queue, so i tweaked it a bit:
NSMutableArray+QueueAdditions.h
#interface NSMutableArray (QueueAdditions)
- (id) dequeue;
- (void) enqueue:(id)obj;
#end
NSMutableArray+QueueAdditions.m
#implementation NSMutableArray (QueueAdditions)
// Queues are first-in-first-out, so we remove objects from the head
- (id) dequeue {
// if ([self count] == 0) return nil; // to avoid raising exception (Quinn)
id headObject = [self objectAtIndex:0];
if (headObject != nil) {
[[headObject retain] autorelease]; // so it isn't dealloc'ed on remove
[self removeObjectAtIndex:0];
}
return headObject;
}
// Add to the tail of the queue (no one likes it when people cut in line!)
- (void) enqueue:(id)anObject {
[self addObject:anObject];
//this method automatically adds to the end of the array
}
#end
Just import the .h file wherever you want to use your new methods, and call them like you would any other NSMutableArray methods.

I wouldn't say that using NSMutableArray is necessarily the best solution, particularly if you're adding methods with categories, due to the fragility they can cause if method names collide. For a quick-n-dirty queue, I'd use the methods to add and remove at the end of a mutable array. However, if you plan to reuse the queue, or if you want your code to be more readable and self-evident, a dedicated queue class is probably what you want.
Cocoa doesn't have one built in, but there are other options, and you don't have to write one from scratch either. For a true queue that only adds and removes from the ends, a circular buffer array is an extremely fast implementation. Check out CHDataStructures.framework, a library/framework in Objective-C that I've been working on. It has a variety of implementations of queues, as well as stacks, deques, sorted sets, etc. For your purposes, CHCircularBufferQueue is significantly faster (i.e. provable with benchmarks) and more readable (admittedly subjective) than using an NSMutableArray.
One big advantage of using a native Objective-C class instead of a C++ STL class is that it integrates seamlessly with Cocoa code, and works much better with encode/decode (serialization). It also works perfectly with garbage collection and fast enumeration (both present in 10.5+, but only the latter on iPhone) and you don't have to worry about what is an Objective-C object and what is a C++ object.
Lastly, although NSMutableArray is better than a standard C array when adding and removing from either end, it's also not the fastest solution for a queue. For most applications it is satisfactory, but if you need speed, a circular buffer (or in some cases a linked list optimized to keep cache lines hot) can easily trounce an NSMutableArray.

As far as I know, Objective-C does not provide a Queue data structure. Your best bet is to create an NSMutableArray, and then use [array lastObject], [array removeLastObject] to fetch the item, and [array insertObject:o atIndex:0]...
If you're doing this a lot, you might want to create an Objective-C category to extend the functionality of the NSMutableArray class. Categories allow you to dynamically add functions to existing classes (even the ones you don't have the source for) - you could make a queue one like this:
(NOTE: This code is actually for a stack, not a queue. See comments below)
#interface NSMutableArray (QueueAdditions)
- (id)pop;
- (void)push:(id)obj;
#end
#implementation NSMutableArray (QueueAdditions)
- (id)pop
{
// nil if [self count] == 0
id lastObject = [[[self lastObject] retain] autorelease];
if (lastObject)
[self removeLastObject];
return lastObject;
}
- (void)push:(id)obj
{
[self addObject: obj];
}
#end

There's no real queue collections class, but NSMutableArray can be used for effectively the same thing. You can define a category to add pop/push methods as a convenience if you want.

Yes, use NSMutableArray. NSMutableArray is actually implemented as 2-3 tree; you typically need not concern yourself with the performance characteristics of adding or removing objects from NSMutableArray at arbitrary indices.

re:Wolfcow -- Here is a corrected implementation of Wolfcow's dequeue method
- (id)dequeue {
if ([self count] == 0) {
return nil;
}
id queueObject = [[[self objectAtIndex:0] retain] autorelease];
[self removeObjectAtIndex:0];
return queueObject;
}

The solutions that use a category on NSMutableArray are not true queues, because NSMutableArray exposes operations that are a superset of queues. For example, you should not be allowed to remove an item from the middle of a queue (as those category solutions still let you do). It is best to encapsulate functionality, a major principle of object oriented design.
StdQueue.h
#import <Foundation/Foundation.h>
#interface StdQueue : NSObject
#property(nonatomic, readonly) BOOL empty;
#property(nonatomic, readonly) NSUInteger size;
#property(nonatomic, readonly) id front;
#property(nonatomic, readonly) id back;
- (void)enqueue:(id)object;
- (id)dequeue;
#end
StdQueue.m
#import "StdQueue.h"
#interface StdQueue ()
#property(nonatomic, strong) NSMutableArray* storage;
#end
#implementation StdQueue
#pragma mark NSObject
- (id)init
{
if (self = [super init]) {
_storage = [NSMutableArray array];
}
return self;
}
#pragma mark StdQueue
- (BOOL)empty
{
return self.storage.count == 0;
}
- (NSUInteger)size
{
return self.storage.count;
}
- (id)front
{
return self.storage.firstObject;
}
- (id)back
{
return self.storage.lastObject;
}
- (void)enqueue:(id)object
{
[self.storage addObject:object];
}
- (id)dequeue
{
id firstObject = nil;
if (!self.empty) {
firstObject = self.storage.firstObject;
[self.storage removeObjectAtIndex:0];
}
return firstObject;
}
#end

this is my implementation, hope it helps.
Is kind of minimalistic, so you must keep the track of the head by saving the new head at pop and discarding the old head
#interface Queue : NSObject {
id _data;
Queue *tail;
}
-(id) initWithData:(id) data;
-(id) getData;
-(Queue*) pop;
-(void) push:(id) data;
#end
#import "Queue.h"
#implementation Queue
-(id) initWithData:(id) data {
if (self=[super init]) {
_data = data;
[_data retain];
}
return self;
}
-(id) getData {
return _data;
}
-(Queue*) pop {
return tail;
}
-(void) push:(id) data{
if (tail) {
[tail push:data];
} else {
tail = [[Queue alloc]initWithData:data];
}
}
-(void) dealloc {
if (_data) {
[_data release];
}
[super release];
}
#end

Is there some particular reason you cannot just use the STL queue? Objective C++ is a superset of C++ (just use .mm as the extension instead of .m to use Objective C++ instead of Objective C). Then you can use the STL or any other C++ code.
One issue of using the STL queue/vector/list etc with Objective C objects is that they do not typically support retain/release/autorelease memory management. This is easily worked around with a C++ Smart Pointer container class which retains its Objective C object when constructed and releases it when destroyed. Depending on what you are putting in the STL queue this is often not necessary.

Use NSMutableArray.

Related

Why is Objective-C designed to have a three-layer based messaging mechanism?

As far as I know, Objective-C has a three-layer based messaging mechanism:
+(BOOL)resolveInstanceMethod:(SEL)sel or +(BOOL)resolveClassMethod:(SEL)sel
-(id)forwardingTargetForSelector:(SEL)aSelector
-(void)forwardInvocation:(NSInvocation *)anInvocation
My question is why do we need all of the three layers? It seems that the second layer and the third layer have something in common.
The full system is described in great detail in the Objective-C Runtime Programming Guide, particularly in the Messaging, Dynamic Method Resolution, and Message Forwarding sections.
The short answer is: incredible flexibility, coupled with speed in the common cases. Messages handling is incredibly powerful in ObjC. You can create all kinds of elaborate behaviors at runtime to respond to messages. But that functionality, while critical to many important parts of the system, isn't used very often in day-to-day app development. In the overwhelming majority of cases, as an app developer, you expect your message passing to be dispatched to a method that has the same name. The system optimizes that case. If it didn't, calling a method would take hundreds of times longer than it does.
objc_msgSend has a fast path in assembly that handles the most common-of-common cases. If this is a regular method that you've called before, it just pulls it from its cache and jumps to it. If it doesn't find it, it also can look up the method on the class and handle inheritance. But what if it isn't there at all?
In that case, the system gives the object several more options. The first is Key Value Coding, which looks for an accessor. But if that doesn't work it goes to the dynamic dispatch options, which you've enumerated. It can (1) invent a new method dynamically, (2) hand the message to another object, or (3) handle it some other way.
The first case supports things like dynamic loading. You can't do this on iOS, but on Mac, you can use resolveInstanceMethod to load a library from disk. It also allows you to dynamically create properties that are still fast (as opposed to using Key Value Coding, valueForKey:, etc, which is slower). Here's one example:
#import "Person.h"
#import <objc/runtime.h>
#interface Person ()
#property (strong) NSMutableDictionary *properties;
#end
#implementation Person
#dynamic givenName, surname;
- (id)init {
if ((self = [super init])) {
_properties = [[NSMutableDictionary alloc] init];
}
return self;
}
static id propertyIMP(id self, SEL _cmd) {
return [[self properties] valueForKey:
NSStringFromSelector(_cmd)];
}
static void setPropertyIMP(id self, SEL _cmd, id aValue) {
id value = [aValue copy];
NSMutableString *key =
[NSStringFromSelector(_cmd) mutableCopy];
// Delete "set" and ":" and lowercase first letter
[key deleteCharactersInRange:NSMakeRange(0, 3)];
[key deleteCharactersInRange:
NSMakeRange([key length] - 1, 1)];
NSString *firstChar = [key substringToIndex:1];
[key replaceCharactersInRange:NSMakeRange(0, 1)
withString:[firstChar lowercaseString]];
[[self properties] setValue:value forKey:key];
}
+ (BOOL)resolveInstanceMethod:(SEL)aSEL {
if ([NSStringFromSelector(aSEL) hasPrefix:#"set"]) {
class_addMethod([self class], aSEL,
(IMP)setPropertyIMP, "v#:#");
}
else {
class_addMethod([self class], aSEL,
(IMP)propertyIMP, "##:");
}
return YES;
}
#end
This object can accept any property name you like, and it will automatically create a getter and setter for it the first time you try to access the property. (I can't completely remember, but I think this is is how Core Data is implemented.)
Next, the system will allow you to forward the message to another object. This is the core feature of NSProxy, and proxy objects in general. Proxy objects are central to things like distributed messaging (where the "real" object might be in another process, or even on another hots).
And finally, if nothing else meets your needs, you can implement messageSignatureForSelector and forwardInvocation and do literally anything you want with the message. For example, you might make a trampoline that wraps another object, but runs any requested methods on the main thread:
#interface RNMainThreadTrampoline : NSObject
#property (nonatomic, readwrite, strong) id target;
- (id)initWithTarget:(id)aTarget;
#end
#implementation RNMainThreadTrampoline
- (id)initWithTarget:(id)aTarget {
if ((self = [super init])) {
_target = aTarget;
}
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
return [self.target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:self.target];
[invocation retainArguments];
[invocation performSelectorOnMainThread:#selector(invoke)
withObject:nil
waitUntilDone:NO];
}
#end
The last time I profiled it, using forwardInvocation was about 500 times slower than a simple method call, so this is not a tool to use generally, but it's really powerful when you need it.
In the vast majority of cases, you won't need any of these things, but they exist for the parts of the system that do.

Relying on the (copy) attribute to copy NSMutableDictionary causes crash

The following program relies on the copy
attribute to copy a NSMutableDictionary.
The copy is apparently ok, but, if I try
to add a new element to the copy, the program crashes.
Is it some kind of bug?
PS. If it matters it's NON ARC
#import <Foundation/Foundation.h>
#interface Dog: NSObject
#property (copy) NSMutableDictionary *dict;
#end
#implementation Dog
#synthesize dict;
- (id) init
{
if ( (self = [super init]) ) {
dict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void) print {
for (id key in dict) {
printf("%s --> %s\n", [key UTF8String], [dict[key] UTF8String] );
}
}
#end
//------------------------------------------------------
int main() {
Dog *dog1 = [[Dog alloc] init];
Dog *dog2 = [[Dog alloc] init];
dog1.dict[#"color"] = #"black";
dog2.dict = dog1.dict;
[dog2 print];
// the print shows that dog2.dict is indeed a copy of dog1.dict
// lldb shows that it is a shallow copy, which I guess is ok
// since values are immutable.
// ... so far so good.
dog1.dict[#"tail"] = #"long"; // This goes smoothly
//
// But...
dog2.dict[#"tail"] = #"long";
// here program crashes with the following message
//
// -[__NSDictionaryI setObject:forKeyedSubscript:]: unrecognized selector sent to instance 0x100108ee0
//*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryI setObject:forKeyedSubscript:]: unrecognized selector sent to instance 0x100108ee0'
return(0);
}
EDIT:
If I replace the line
dog2.dict = dog1.dict;
with
[dog2.dict addEntriesFromDictionary: dog1.dict];
then it works. There is no crash.
So, OK, this is the correct way of doing it.
But my point is: don't I deserve at least a warning
from the compiler?
You've broken some rules here, which is why it's going badly for you. As a rule, you should not return or accept NSMutableDictionary as a property. There are exceptions (and you have to code around that), but generally you should not. To code this correctly, you need to separate your interface from your implementation.
The correct interface is:
#interface Dog: NSObject
#property (copy) NSDictionary *dict;
#end
This object promises to accept and return NSDictionary, and it promises that the accepted and returned NSDictionaries will be independent copies, so the caller doesn't need to worry about mutability issues. We then need to implement those promises:
#implementation Dog {
NSMutableDictionary *mutableDict;
}
- (id) init
{
if ( (self = [super init]) ) {
mutableDict = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void) print {
for (id key in mutableDict) {
printf("%s --> %s\n", [key UTF8String], [mutableDict[key] UTF8String] );
}
}
- (NSDictionary *)dict {
return [mutableDict copy]; // Add an -autorelease if this is MRC
}
- (void)setDict: (NSDictionary *)newValue {
// I'm going to pretend this is ARC; for MRC, code this in your style.
mutableDict = [newValue mutableCopy];
}
#end
On the other hand, if you really do want to share state with an NSMutableDictionary, you should not copy it, you should retain it to make clear the semantics.
#interface Dog: NSObject
#property (retain) NSMutableDictionary *dict;
#end
And this makes it (hopefully) clear to the caller that this is shared state and should be treated as such, and the caller should make copies if they so desire. But you generally should avoid this. And if you do go this way, I would call the property mutableDict or something like that to make it clear that this is unusual. For an example, see -[NSAttributedString mutableString].
There's not really a "mutable, but independent copy" semantic in ObjC property annotations, and I wouldn't create one unless you have a very strong need (generally performance related). I would generally just return an immutable copy and let the caller make their own mutable copy.
One more side note: Sometimes Cocoa implements "returns an immutable copy" as "just return the mutable one, cast to an immutable type." This improves performance by avoiding the copy, at the cost of sometimes the data changing behind your back. As an example, look at the docs for -[NSView subviews]. In my opinion you should avoid this pattern unless it is critical for performance (and even then, I'd make a special method like -subviewsBackingStore or something silly like that to make it clear "this is weird."
copy attribute creates an NSDictionary instance, not NSMutableDictionary, that's why it's crashing.
First, change the property to retain from copy:
#property (retain) NSMutableDictionary* duct;
Then you can do the following:
Dog *dog2 = [[Dog alloc] init];
dog2.dict = [dog1.dict mutableCopy];

Initializing child objects from parent

I'm having a bit of a structural dilemma with designing my app. I want to use a series of nested loops to create a large amount of custom objects. Once those objects are created, I want to store them all into an object which is collection of those objects.
Visualized:
#interface CollectionOfObjectA : NSObject
#property (nonatomic, strong) NSArray *reference;
#end
#implementation CollectionOfObjectA
-(CollectionOfObjectA *)init{
NSMutableArray *ref = [[NSMutableArray alloc] init];
for(int i=0; i < largeNumber; i++){ // There will be nested loops.
NSString *str = #"string made from each loop index";
ObjA *obj = [[ObjA alloc] initWithIndexes: str];
[ref addObject: obj];
}
self.reference = [ref copy];
}
#end
#interface ObjA : CollectionOfObjA
// several properties
#end
#implementation ObjA
-(ObjA *)initWithIndexes:(NSString *)indexes{
self = [super init];
// Use passed indexes to create several properties for this object.
return self;
}
#end
What would be the best way about creating this object which is a collection of child objects? Am I incorrect in making ObjA a child of CollectionOfObjectA -- should it be the other way around? Any help would be greatly appreciated.
Ok, my advise: I have nearly ~30 custom objects. Like events. After that I make class Factory which can create all of them. And also this class Factory have method: getAllObjects.
Like this:
#include "CustomEvent.h"
#interface EventFactory
+(NSArray*)allEvents;
#end
#implementation EventFactory
-(CustomEvent*)firstEvent{/*something here*/}
-(CustomEvent*)secondEvent{/*yes, you should init custom object here*/}
-(CustomEvent*)thirdEvent{/*and after that you can put them*/}
/*
...
*/
+(NSArray*)allEvents{
EventFactory* factory = [[EventFactory alloc]init];
return #[
[factory firstEvent],
[factory secondEvent],
/*...*/
[factory lastEvent]
];
}
#end
Here I return NSArray because I don't need, actually, know anything of them. They already have handlers and they subscribed on custom notifications. You can return NSDictionary for better access.
P.S: for better explanation you can read article in wiki about Factory pattern
But, if you want better manipulation of objects, you should use other pattern:Composite pattern.
What I mean?
#interface EventCollection{
NSMutableArray* YourArray;
}
-(void)addCustomEvent:(CustomEvent*)event atPosition:(NSInteger)position;
-(void)removeCustomEventAtPosition:(NSInteger)position;
-(void)seeAllEvents;
-(void)seeAllPositions; /*if you want*/
-(void)doesThisPositionAvailable:(NSInteger)position;
#end
#implementation EventCollection
-(void)addCustomEvent:(CustomEvent*)event atPosition:(NSInteger)position{
/*maybe you should check if this position available*/
if ([self doesThisPositionAvailable:position]){
/*add element and save position*/
}
}
-(void)removeCustomEventAtPosition:(NSInteger)position{
if (![self doesThisPositionAvailable:position]){
/*destroy element here*/
}
}
-(void)seeAllEvents{
/*yes, this method is the main method, you must store somewhere your objects.
you can use everything, what you want, but don't share your realization.
maybe, you want use array, so, put it as hidden variable. and init at the initialization of your collection
*/
for (CustomEvent* event in YourArray){
[event description];
}
}
#end

NSMutableArray - force the array to hold specific object type only

Is there a way to force NSMutableArray to hold one specific object type only?
I have classes definitions as follow:
#interface Wheel:NSObject
{
int size;
float diameter;
}
#end
#interface Car:NSObject
{
NSString *model;
NSString *make;
NSMutableArray *wheels;
}
#end
How can I force wheels array to hold Wheel objects only with code? (and absolutely not other objects)
Update in 2015
This answer was first written in early 2011 and began:
What we really want is parametric polymorphism so you could declare, say, NSMutableArray<NSString>; but alas such is not available.
In 2015 Apple apparently changed this with the introduction of "lightweight generics" into Objective-C and now you can declare:
NSMutableArray<NSString *> *onlyStrings = [NSMutableArray new];
But all is not quite what it seems, notice the "lightweight"... Then notice that the initialisation part of the above declaration does not contain any generic notation. While Apple have introduced parametric collections, and adding a non-string directly to the above array, onlyStrings, as in say:
[onlyStrings addObject:#666]; // <- Warning: Incompatible pointer types...
will illicit the warning as indicated, the type security is barely skin deep. Consider the method:
- (void) push:(id)obj onto:(NSMutableArray *)array
{
[array addObject:obj];
}
and the code fragment in another method of the same class:
NSMutableArray<NSString *> *oops = [NSMutableArray new];
[self push:#"asda" onto:oops]; // add a string, fine
[self push:#42 onto:oops]; // add a number, no warnings...
What Apple have implemented is essentially a hinting system to assist with automatic inter-operation with Swift, which does have a flavour of type-safe generics. However on the Objective-C side, while the compiler provides some extra hints the system is "lightweight" and type-integrity is still ultimately down to the programmer - as is the Objective-C way.
So which should you use? The new lightweight/pseudo generics, or devise your own patterns for your code? There really is no right answer, figure out what makes sense in your scenario and use it.
For example: If you are targeting interoperation with Swift you should use the lightweight generics! However if the type integrity of a collection is important in your scenario then you could combine the lightweight generics with your own code on the Objective-C side which enforces the type integrity that Swift will on its side.
The Remainder of the 2011 Answer
As another option here is a quick general subclass of NSMutableArray which you init with the kind of object you want in your monomorphic array. This option does not give you static type-checking (in as much as you ever get it in Obj-C), you get runtime exceptions on inserting the wrong type, just as you get runtime exceptions for index out of bounds etc.
This is not thoroughly tested and assumes the documentation on overriding NSMutableArray is correct...
#interface MonomorphicArray : NSMutableArray
{
Class elementClass;
NSMutableArray *realArray;
}
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems;
- (id) initWithClass:(Class)element;
#end
And the implementation:
#implementation MonomorphicArray
- (id) initWithClass:(Class)element andCapacity:(NSUInteger)numItems
{
elementClass = element;
realArray = [NSMutableArray arrayWithCapacity:numItems];
return self;
}
- (id) initWithClass:(Class)element
{
elementClass = element;
realArray = [NSMutableArray new];
return self;
}
// override primitive NSMutableArray methods and enforce monomorphism
- (void) insertObject:(id)anObject atIndex:(NSUInteger)index
{
if ([anObject isKindOfClass:elementClass]) // allows subclasses, use isMemeberOfClass for exact match
{
[realArray insertObject:anObject atIndex:index];
}
else
{
NSException* myException = [NSException
exceptionWithName:#"InvalidAddObject"
reason:#"Added object has wrong type"
userInfo:nil];
#throw myException;
}
}
- (void) removeObjectAtIndex:(NSUInteger)index
{
[realArray removeObjectAtIndex:index];
}
// override primitive NSArray methods
- (NSUInteger) count
{
return [realArray count];
}
- (id) objectAtIndex:(NSUInteger)index
{
return [realArray objectAtIndex:index];
}
// block all the other init's (some could be supported)
static id NotSupported()
{
NSException* myException = [NSException
exceptionWithName:#"InvalidInitializer"
reason:#"Only initWithClass: and initWithClass:andCapacity: supported"
userInfo:nil];
#throw myException;
}
- (id)initWithArray:(NSArray *)anArray { return NotSupported(); }
- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag { return NotSupported(); }
- (id)initWithContentsOfFile:(NSString *)aPath { return NotSupported(); }
- (id)initWithContentsOfURL:(NSURL *)aURL { return NotSupported(); }
- (id)initWithObjects:(id)firstObj, ... { return NotSupported(); }
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count { return NotSupported(); }
#end
Use as:
MonomorphicArray *monoString = [[MonomorphicArray alloc] initWithClass:[NSString class] andCapacity:3];
[monoString addObject:#"A string"];
[monoString addObject:[NSNumber numberWithInt:42]]; // will throw
[monoString addObject:#"Another string"];
Since Xcode 7, generics are available in Objective-C.
You can declare a NSMutableArray as:
NSMutableArray <Wheel*> *wheels = [[NSMutableArray alloc] initWithArray:#[[Wheel new],[Wheel new]];
The compiler will give you a warning if you try to put non-Wheel objects in the array.
I could be wrong (I'm a noob), but I think, if you create a custom protocol and make sure the objects you are adding to the array follow the same protocol, then when you declare the array you use
NSArray<Protocol Name>
That should prevent objects being added that do not follow the said protocol.
as per i know.. before you added any object in wheels mutableArray, u have to add some check mark. Is the object which i am adding is class "wheel". if it is then add, other wise not.
Example:
if([id isClassOf:"Wheel"] == YES)
{
[array addObject:id)
}
Something like this. i dont remember the exact syntax.
I hope this will help (and work... :P )
Wheel.h file:
#protocol Wheel
#end
#interface Wheel : NSObject
#property ...
#end
Car.h file:
#import "Wheel.h"
#interface Car:NSObject
{
NSString *model;
NSString *make;
NSMutableArray<Wheel, Optional> *wheels;
}
#end
Car.m file:
#import "Car.h"
#implementation Car
-(id)init{
if (self=[super init]){
self.wheels = (NSMutableArray<Wheel,Optional>*)[NSMutableArray alloc]init];
}
return self;
}
#end
Xcode 7 allows you to define Arrays, Dictionaries, and even your own Classes as having generics. The array syntax is as follows:
NSArray<NSString*>* array = #[#"hello world"];
I don't believe there's any way to do it with NSMutableArray out of the box. You could probably enforce this by subclassing and overriding all the constructors and insertion methods, but it's probably not worth it. What are you hoping to achieve with this?
That's not possible; an NSArray (whether mutable or not) will hold any object type. What you can do is to create your own custom subclasses as already suggested by Jim. Alternatively, if you wanted to filter an array to remove objects that weren't of the type you want, then you could do:
- (void)removeObjectsFromArray:(NSMutableArray *)array otherThanOfType:(Class)type
{
int c = 0;
while(c < [array length])
{
NSObject *object = [array objectAtIndex:c];
if([object isKindOfClass:type])
c++;
else
[array removeObjectAtIndex:c];
}
}
...
[self removeObjectsFromArray:array otherThanOfType:[Car class]];
Or make other judgments based on the result of isKindOfClass:, e.g. to divide an array containing a mixture of Cars and Wheels into two arrays, each containing only one kind of object.
You can use the nsexception if you dont have the specific object.
for (int i = 0; i<items.count;i++) {
if([[items objectAtIndex:i] isKindOfClass:[Wheel class]])
{
// do something..!
}else{
[NSException raise:#"Invalid value" format:#"Format of %# is invalid", items];
// do whatever to handle or raise your exception.
}
}
Here's something I've done to avoid subclassing NSMutableArray: use a category. This way you can have the argument and return types you want. Note the naming convention: replace the word "object" in each of the methods you will use with the name of the element class. "objectAtIndex" becomes "wheelAtIndex" and so on. This way there's no name conflict. Very tidy.
typedef NSMutableArray WheelList;
#interface NSMutableArray (WheelList)
- (wheel *) wheelAtIndex: (NSUInteger) index;
- (void) addWheel: (wheel *) w;
#end
#implementation NSMutableArray (WheelList)
- (wheel *) wheelAtIndex: (NSUInteger) index
{
return (wheel *) [self objectAtIndex: index];
}
- (void) addWheel: (wheel *) w
{
[self addObject: w];
}
#end
#interface Car : NSObject
#property WheelList *wheels;
#end;
#implementation Car
#synthesize wheels;
- (id) init
{
if (self = [super init]) {
wheels = [[WheelList alloc] initWithCapacity: 4];
}
return self;
}
#end
protocol maybe a good idea:
#protocol Person <NSObject>
#end
#interface Person : NSObject <Person>
#end
to use:
NSArray<Person>* personArray;
There is one-header file project which allows this:
Objective-C-Generics
Usage:
Copy ObjectiveCGenerics.h to your project.
When defining a new class use the GENERICSABLE macro.
#import "ObjectiveCGenerics.h"
GENERICSABLE(MyClass)
#interface MyClass : NSObject<MyClass>
#property (nonatomic, strong) NSString* name;
#end
Now you can use generics with arrays and sets just as you normally do in Java, C#, etc.
Code:

Is this a good (Cocoa-like, Apple-approved) model class?

I've been using Objective-C for a while, but I've not been following Apple's guidelines very well. Recently I read Cocoa Design Patterns and the Model Object Implementation Guide, and I'm trying to do some very simple things, but do them very well.
Have I missed any major concepts? Please don't mention self = [super init]; that's been covered many times on SO already. Feel free to critique my #pragma marks though!
#import "IRTileset.h"
#import "IRTileTemplate.h"
#interface IRTileset () //No longer lists protocols because of Felixyz
#property (retain) NSMutableArray* tileTemplates; //Added because of TechZen
#end
#pragma mark -
#implementation IRTileset
#pragma mark -
#pragma mark Initialization
- (IRTileset*)init
{
if (![super init])
{
return nil;
}
tileTemplates = [NSMutableArray new];
return self;
}
- (void)dealloc
{
[tileTemplates release];
[uniqueID release]; //Added because of Felixyz (and because OOPS. Gosh.)
[super dealloc]; //Moved from beginning to end because of Abizern
}
#pragma mark -
#pragma mark Copying/Archiving
- (IRTileset*)copyWithZone:(NSZone*)zone
{
IRTileset* copy = [IRTileset new];
[copy setTileTemplates:tileTemplates]; //No longer insertTileTemplates: because of Peter Hosey
[copy setUniqueID:uniqueID];
return copy; //No longer [copy autorelease] because of Jared P
}
- (void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:uniqueID forKey:#"uniqueID"];
[encoder encodeObject:tileTemplates forKey:#"tileTemplates"];
}
- (IRTileset*)initWithCoder:(NSCoder*)decoder
{
[self init];
[self setUniqueID:[decoder decodeObjectForKey:#"uniqueID"]];
[self setTileTemplates:[decoder decodeObjectForKey:#"tileTemplates"]]; //No longer insertTileTemplates: because of Peter Hosey
return self;
}
#pragma mark -
#pragma mark Public Accessors
#synthesize uniqueID;
#synthesize tileTemplates;
- (NSUInteger)countOfTileTemplates
{
return [tileTemplates count];
}
- (void)insertTileTemplates:(NSArray*)someTileTemplates atIndexes:(NSIndexSet*)indexes
{
[tileTemplates insertObjects:someTileTemplates atIndexes:indexes];
}
- (void)removeTileTemplatesAtIndexes:(NSIndexSet*)indexes
{
[tileTemplates removeObjectsAtIndexes:indexes];
}
//These are for later.
#pragma mark -
#pragma mark Private Accessors
#pragma mark -
#pragma mark Other
#end
(Edit: I've made the changes suggested so far and commented which answers discuss them, in case anyone needs to know why.)
Please don't mention self = [super init]…
So, why aren't you doing that?
The same goes for initWithCoder:: You should be using the object returned by [self init], not assuming that it initialized the initial object.
- (void)dealloc
{
[super dealloc];
[tileTemplates release];
}
As Abizern said in his comment, [super dealloc] should come last. Otherwise, you're accessing an instance variable of a deallocated object.
- (IRTileTemplate*)copyWithZone:(NSZone*)zone
The return type here should be id, matching the return type declared by the NSCopying protocol.
{
IRTileset* copy = [IRTileset new];
[copy insertTileTemplates:tileTemplates atIndexes:[NSIndexSet indexSetWithIndex:0]];
[copy setUniqueID:uniqueID];
You're inserting zero or more objects at one index. Create your index set with a range: location = 0, length = the count of the tileTemplates array. Better yet, just assign to the whole property value:
copy.tileTemplates = self.tileTemplates;
Or access the instance variables directly:
copy->tileTemplates = [tileTemplates copy];
(Note that you must do the copy yourself when bypassing property accessors, and that you are copying the array on behalf of the copy.)
return [copy autorelease];
}
copyWithZone: should not return an autoreleased object. According to the memory management rules, the caller of copy or copyWithZone: owns the copy, which means it is the caller's job to release it, not copyWithZone:'s.
#synthesize tileTemplates;
[et al]
You may want to implement the single-object array accessors as well:
- (void) insertObjectInTileTemplates:(IRTileTemplate *)template atIndex:(NSUInteger)idx;
- (void) removeObjectFromTileTemplatesAtIndex:(NSUInteger)idx;
This is optional, of course.
//However, should I list protocols
here, even though they're already
listed in IRTileset.h?
No, you shouldn't. The class extension declared in the implementation file is an extension, so you don't have to care about which protocols the class has been declared to follow.
I would recommend to mark your instance variables' names with an underscore: _tileTemplates. (Purists will tell you to affix rather than prefix the underscore; do that if you're afraid of them.)
Don't use new to instantiate classes. It's not recommended ever, as far as I understand.
[NSMutableArray new]; // :(
[NSMutableArray arrayWithCapacity:20]; // :)
Don't call [super dealloc] before doing your own deallocation! This can cause a crash in certain circumstances.
- (void)dealloc
{
[tileTemplates release];
[super dealloc]; // Do this last
}
I'm not sure what type uniqueID has, but shouldn't it also be released in dealloc?
I would never put my #synthesize directives in the middle of a file (place them immediately below ´#implementation´).
Also, having no clear idea about the role of this class, countOfTileTemplates doesn't sound good to me. Maybe just ´count´ will do, if it's unambiguous that what this class does it to hold tile templates?
It looks pretty good except you've left your properties open to arbitrary manipulation by external objects. Ideally, the data should be manipulated directly only by the model class itself and external objects should have access only via dedicated methods.
For example what if some external code calls this:
myIRTileset.tileTemplates=someArray;
Boom, you've lost all your data.
You should define both the data properties as readonly. Then write accessors internal to the class that will managed their retention within the class implementation. This way the only way for an external object to change the tileTemplates is by calling the - insertTileTemplates:atIndexes: and removeTileTemplatesAtIndexes: methods.
Edit01:
I think I mangled it the first go, so let me try again. You should setup you data model class in the following pattern:
Interface
#interface PrivateTest : NSObject {
#private
//iVar is invisible outside the class, even its subclasses
NSString *privateString;
#public
//iVar is visible and settable to every object.
NSString *publicString;
}
#property(nonatomic, retain) NSString *publicString; //property accessors are visible, settable and getable.
//These methods control logical operations on the private iVar.
- (void) setPrivateToPublic;
- (NSString *) returnPrivateString;
#end
So in use it would look like:
Implementation
#import "PrivateTest.h"
//private class extension category defines
// the propert setters and getters
// internal to the class
#interface PrivateTest ()
#property(nonatomic, retain) NSString *privateString;
#end
#implementation PrivateTest
//normal synthesize directives
#synthesize privateString;
#synthesize publicString;
// Methods that control access to private
- (void) setPrivateToPublic{
//Here we do a contrived validation test
if (self.privateString != nil) {
self.privateString=self.publicString;
}
}
- (NSString *) returnPrivateString{
return self.privateString;
}
#end
You would use it like so:
PrivateTest *pt=[[PrivateTest alloc] init];
// If you try to set private directly as in the next line
// the complier throws and error
//pt.privateString=#"Bob"; ==> "object cannot be set - either readonly property or no setter found"
pt.publicString=#"Steve";
[pt setPrivateToPublic];
NSLog(#"private=%#",[pt returnPrivateString]); //==> "Steve"
Now the class has bullet proof data integrity. Any object in your app can set and get the publicString string property but no external object can set or get the private.
This means you can safely allow access to the instance by any object in your app without worrying that a careless line of code in some minor object or method will trash everything.
two minor nitpicks:
One is the init method, (where stylistically I'm against having 2 different return points but thats just me), however there's nothing stopping super's init from returning a different object than itself or nil, eg a different object of its class or even just another object altogether. For this reason, self = [super init] is generally a good idea, even if it probably won't do much in practice.
Second is in the copyWithZone method, you don't copy the tileTemplates, which could be intentional but is generally a bad idea (unless they're immutable). Copying an object is supposed to have the same effect as allocing a fresh one, eg. retain count of 1, so don't autorelease it. Also, it doesn't look like you do anything with the zone, so you should probably replace it with something like
- (IRTileTemplate*)copyWithZone:(NSZone*)zone {
IRTileset* copy = [[IRTileset allocWithZone:zone] init];
[copy insertTileTemplates:[tileTemplates copyWithZone:zone]
atIndexes:[NSIndexSet indexSetWithIndex:0]];
[copy setUniqueID:uniqueID];
return copy;
}
thats everything I found; with the exception of the retain count of copy (which WILL lead to bugs later on) mostly just stuff that I prefer, you can do it your way if you like it better. Good work