I have a class that inherits from NSObject. It uses an NSMutableArray to hold children objects, e.g. People using NSMutableArray *items to hold Person objects. How do I implement the NSFastEnumerator on items?
I have tried the following but it is invalid:
#interface People : NSObject <NSFastEnumeration>
{
NSMutableArray *items;
}
#implementation ...
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
{
if(state->state == 0)
{
state->mutationsPtr = (unsigned long *)self;
state->itemsPtr = items;
state->state = [items count];
return count;
}
else
return 0;
}
You are not using the NSFastEnumerationState structure properly. See NSFastEnumeration Protocol Reference and look at the constants section to see a description of each of the fields. In your case, you should leave state->mutationsPtr as nil. state->itemsPtr should be set to a C-array of the objects, not an NSArray or NSMutableArray. You also need to put the same objects into the array passed as stackbuf.
However, since you are using an NSMutableArray to contain the objects you are enumerating, you could just forward the call to that object:
- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len {
return [items countByEnumeratingWithState:state objects:stackbuf count:len];
}
There's an NSFastEnumeration protocol, but you are using the (non-existent) NSFastEnumerator protocol. Could that be the problem?
Related
Is there a way to add multiple objects into a NSMutableArray through a custom method? Here my code.
#property NSMutableArray *MusicCollectionArray;
-(void) addPlaylist: (Playlist *) thePlaylist;
.
-(void) addPlaylist: (Playlist *) thePlaylist {
[MusicCollectionArray addObject:thePlaylist];
}
Now lets say I call the method but instead of one object to add, is there a way to add multiple into one instead of calling each method separately. (the number of objects is unknown)
eg. [mycollection addPlaylist: first, second, third];
you can add another array like this:
NSMutableArray *sourceArray = [NSMutableArray arrayWithObject:#"FirstObject"];
NSString *secondObject = #"SecondObject";
NSString *thirdObject = #"ThirdObject";
NSArray *objectsToAdd = #[secondObject, thirdObject];
[sourceArray addObjectsFromArray:objectsToAdd];
It is possible, please take a look at Apple docs and this thread:
https://developer.apple.com/library/mac/qa/qa1405/_index.html
#import <Cocoa/Cocoa.h>
#interface NSMutableArray (variadicMethodExample)
- (void) appendObjects:(id) firstObject, ...; // This method takes a nil-terminated list of objects.
#end
#implementation NSMutableArray (variadicMethodExample)
- (void) appendObjects:(id) firstObject, ...
{
id eachObject;
va_list argumentList;
if (firstObject) // The first argument isn't part of the varargs list,
{ // so we'll handle it separately.
[self addObject: firstObject];
va_start(argumentList, firstObject); // Start scanning for arguments after firstObject.
while (eachObject = va_arg(argumentList, id)) // As many times as we can get an argument of type "id"
[self addObject: eachObject]; // that isn't nil, add it to self's contents.
va_end(argumentList);
}
}
#end
I guess you will catch an idea.
This would best be done using a for loop:
- (void) addPlaylistFromPlayLists:(NSArray <Playlist*>*)playlists {
for (Playlist *playlist in playlists) {
[musicCollectionArray addObject:playlist];
}
}
That way, you are ensuring that only the playlists that are inside the array are added. A for loop will only add what's given to it, you don't have to tell it how much if it's a for/in.
In objective C, its common practice to instantiate internal class arrays (and the like) in a lazy manner.
So if you call on the getter, it first checks if the array isn't nil, and allocates memory for it if needed.
But what about the setter?
If you are trying to insert some value into one of the array cells, since we did not allocate memory for it yet - where does it go?
I'm missing something here, clearly. Would be happy for a clarification.
I'm not sure I understand your question, but if you do this:
#property (nonatomic, strong) NSMutableArray* myArray;
...
- (NSMutableArray *) myArray {
if(!_myArray) {
NSLog(#"created");
_myArray = [[NSMutableArray alloc] init];
}
return _myArray;
}
...
[self.myArray addObject:#"test"];
The getter is actually getting called when you call addObject:, so you'll see "created" being logged.
So #property declarations are syntactic sugar for declaring, in the case of objects, pointers to instance variables. The "nonatomic" refers to the type of getter and setter automatically created (in this case "non thread safe.") And the "strong" is an indicator to ARC to increase the retain count of the variable.
So when you declare:
#property (nonatomic, strong) NSMutableArray* myArray;
This is what really gets created in your class - just a pointer to your hidden instance variable.
#implementation MyClass {
NSMutableArray *_myArray;
}
As you can see in the getter, you are initializing the _myArray pointer to point to a new NSMutableArray:
- (NSMutableArray *) myArray {
if(!_myArray) {
NSLog(#"created");
_myArray = [[NSMutableArray alloc] init];
}
return _myArray;
}
However in the setter, you are just updating the pointer to a variable you have already created.
self.myArray = [[NSMutableArray alloc] init];
This sends your class the following message:
- (void) myArray: (NSMutableArray *) myArray {
_myArray = myArray;
}
As you can, see the setter doesn't need any special initialization most of the time. The only time you want to create a custom setter is when you want to validate the incoming object has special properties. A contrived example is checking that the NSMutableArray is no larger than 10 objects:
- (void) myArray: (NSMutableArray *) myArray {
if (myArray.count < 10) {
_myArray = myArray;
}
}
Finally, I would like to point out that you can actually lazy instantiate objects using the short ternary operator and parenthetical return values. For example, the following statement:
- (NSMutableArray *) myArray {
return (_myArray = _myArray ?: #{}.mutableCopy);
}
Is equal to:
- (NSMutableArray *) myArray {
if(!_myArray) {
_myArray = [[NSMutableArray alloc] init];
}
return _myArray;
}
You can even macro this pattern into (WSM is my class prefix):
#define WSM_LAZY(object, assignment) (object = object ?: assignment)
So you can write statements like this:
- (NSMutableArray *) myArray {
return WSM_LAZY(_myArray, #{}.mutableCopy);
}
Or even use compound statement syntax to rewrite the original setter you presented as an example:
- (NSMutableArray *) myArray {
return WSM_LAZY(_myArray, ({
NSLog(#"created");
#{}.mutableCopy;
}));
}
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
I have the following class in my iOS application (it is like an abstract class from the Java world).
#implementation WSObject
static NSDictionary* _dictionary = nil;
+(NSDictionary*) dictionary {
if (_dictionary == nil) {
_dictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
}
return _dictionary;
}
...
#end
I then have multiple classes which implement this above WSObject with the class method dictionary. The problem is, that each of these classes should have their own _dictionary, but they are all sharing the same object from the super class. I could, of course, copy to all the subclasses, but that would break the reusability. Besides this getter, there are other class methods in WSObject which mutate the dictionary. Because of this, there would be a several class methods which should be in every subclass.
How can I solve this in a smart way? Please tell me if my description is insufficient.
Associative references seem like they'll do the trick. You can essentially tack some storage on to the class object itself. (I'm using NSStrings here, in place of the dictionaries you want to use, just for demonstration.)
Superclass:
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface Stuper : NSObject
// Accessor method for the "class variable"
+ (NSString *) str;
// Analog to your +localStorePath
+ (NSString *) quote;
#end
#import "Stuper.h"
// The doc suggests simply using the address of a static variable as the key.
// This works fine, even though every class is (as in your problem) using
// the same key, because we are associating to a different class each time.
static char key;
#implementation Stuper
+ (NSString *) str {
NSString * s = objc_getAssociatedObject(self, &key);
if( !s ){
s = [self quote];
// You'll probably want to use OBJC_ASSOCIATION_RETAIN for your dictionary.
// self inside a class method is the class object; use that as
// the associator. The string is now tied to the associator, i.e.,
// has the same lifetime.
objc_setAssociatedObject(self, &key, s, OBJC_ASSOCIATION_COPY);
}
return s;
}
+ (NSString *) quote {
return #"It was the best of times, it was the worst of times.";
}
#end
Subclass:
#import "Stuper.h"
#interface Stub : Stuper #end
#import "Stub.h"
#implementation Stub
+ (NSString *) quote {
return #"Call me Ishmael.";
}
#end
Trying this out:
#import <Foundation/Foundation.h>
#import "Stuper.h"
#import "Stub.h"
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSLog(#"%#", [Stuper str]);
NSLog(#"%#", [Stub str]);
[pool drain];
return 0;
}
Each class object now has its own string, associated with it.
2011-12-05 23:11:09.031 SubClassVariables[36254:903] It was the best of times, it was the worst of times.
2011-12-05 23:11:09.034 SubClassVariables[36254:903] Call me Ishmael.
The only downside here is that you'll have to call the accessor method every time you want the object; you don't have a pointer you can use directly. You can call objc_getAssociatedObject in the superclass as an accessor, too, of course, since it has access to key.
In order to give each subclass its own dictionary, store a second dictionary object in your primary dictionary using the class name as the key. For example:
static NSMutableDictionary *_dictionary = nil;
+ (NSDictionary*)dictionary
{
if (_dictionary == nil)
_dictionary = [[NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]] mutableCopy];
NSString *key = NSStringFromClass( [self class] );
if ( [_dictionary objectForKey:key] == nil )
[_dictionary setObject:[NSMutableDictionary dictionary] forKey:key];
return [_dictionary objectForKey:key];
}
Perhaps you can return a copy of the dictionary
#implementation WSObject
static NSDictionary* _dictionary = nil;
+(NSDictionary*) dictionary {
if (_dictionary == nil) {
_dictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
}
return [_dictionary copy];
}
...
#end
Keep in mind that if you modify _dictionary you will get a copy of that modified dictionary which may differ from what is on disk.
How often is this being called? is it really necessary to cache the file contents in this static _dictionary object?
Why not just fetch it every time form disk, assuming it isn't too often that performance comes into question.
#implementation WSObject
+(NSDictionary*) dictionary {
return [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
}
...
#end
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: