0

I have created a class which has a static NSMutableArray, I want this array to be filled with each instance of the class, during my override of init so I don't have to do anything more coding than I need to.

I should point out the array works perfectly, I am just having trouble storing the correct data.

Does this make sense? If so how can I do this?

Although I have tried doing this

_instance = self;

[[MyClass getStack] addObject:_instance];

It seems I cannot access the instances of the property, and when logged all I get is:

2012-07-14 22:37:58.223 Application[4497:1bb03] <MyClass: 0x92cfc70>

Edit with more code:

My .h file:

@interface MyClass : NSObject

+ (NSMutableArray *)getStack;

My .m file:

@interface MyClass ()

@end

static NSMutableArray *stack;

@implementation MyClass

Edit with image of crash

When logging the array property NSLog(@"%@", [[[MyClass stack] objectAtIndex:0] adam]); It crashes on that line and gives me the following error.

Crash error

5
  • can you show us your init method? Commented Jul 14, 2012 at 21:42
  • 1
    have you initialized the static NSMutableArray? Commented Jul 14, 2012 at 21:45
  • I should point out the array works perfectly, I am just having trouble storing the correct data. i.e. the instance during init. Commented Jul 14, 2012 at 21:51
  • 1
    "having trouble storing the correct data" define "trouble" and "correct data". What the hell does "I cannot access the instances of the property," mean? What "property"? What "instances"? Commented Jul 15, 2012 at 1:01
  • I want to add the instance, during init, to the static mutable array. Then I can (in another class file) reference that array and get each instance from it, accompanied by the instances properties. The problem is not with the array, which can store objects and let me view them. The problem is with the data that I want to store, i.e. the instance (during init). The question is, "how do I add an instance to the static mutable array, from within the instance's class init method?" Commented Jul 15, 2012 at 1:08

4 Answers 4

1

Kevin Grant's answer is good, but there's a problem with it. NSArray retains the objects it contains. So, when you add an instance to the array the object won't actually ever be deallocated, because the array will maintain a strong reference to it. Of course, usually it makes sense for NSArray to retain its children, so that it doesn't end up holding a no longer valid pointer to objects that get released out from under it. In this case, where you're manually going to remove the object from the array right before it's deallocated, you actually want to prevent the array from retaining the objects it contains.

One way to do that is to wrap each instance in an NSValue. NSValue has a method called -valueWithNonretainedObject:, which does what it sounds like. It creates an NSValue instance which contains an object but doesn't retain that object. Now, when you add the NSValue instance to the array, the array retains the NSValue instance, instead of the contained object, and won't prevent the instance from being deallocated. Here's an example in code:

static NSMutableArray *instanceArray = nil;

@implementation MyClass

+ (void)addInstance:(MyClass *)instance
{
    if (!instanceArray) instanceArray = [[NSMutableArray alloc] init];
    NSValue *value = [NSValue valueWithNonretainedObject:instance];
    [instanceArray addObject:value];
}

+ (void)removeInstance:(MyClass *)instance
{
    NSValue *valueToRemove = nil;
    for (NSValue *value in instanceArray) 
    {
        if ([value nonretainedObjectValue] == instance) 
        {
            valueToRemove = value;
            break;
        }
    }
    if (valueToRemove != nil) [instanceArray removeObject:valueToRemove];
}

- (id)init
{
    self = [super init];
    if (self != nil)
    {
        [[self class] addInstance:self];
    }
 }

 - (void)dealloc
 {
      [[self class] removeInstance:self];
      [super dealloc];
 }

 @end
Sign up to request clarification or add additional context in comments.

4 Comments

How do I access those properties? I have tried: NSLog(@"%@", [[[MyClass getStack] objectAtIndex:0] layer]); to get a property I created called 'layer', but it just crashes.
The most obvious reason for that to crash is because the array returned by getStack is empty.
According to NSLog(@"%@", [MyClass getStack]); it contains two objects: 2012-07-15 00:32:36.657 Application[5093:1bb03] ( "<1028950a>", "<b068950a>" )
@AndrewMadsen: "crash" is an ambiguous term. If the array were empty, it would raise an exception.
0

It's easy to add each instance in its init to a global array:

static NSMutableArray *stack = nil;

@implementation MyClass
+ (void)initialize {
    if (stack == nil)
        stack = [[NSMutableArray alloc] init];
}

+ (id)init {
    self = [super init];
    if (self) {
        [stack addObject:self];
    }
    return self;
}
@end

Your problem must be from something else. Either you are not retaining the global array. Or you are not storing your "property" properly (e.g. you are not retaining it). Or something.

Comments

0

Edit: As has been correctly pointed out, an Objective-C container has an over-retain issue. Also, there isn't guaranteed to be an autorelease pool available so it would have to be allocated explicitly.

A way around those problems is to use a container that doesn't retain at all, e.g. a dynamically-reallocated array or (if Objective-C++) a std::set< YourClass* > that contains the pointers to current instances.

Given such a "safe" container, the basic idea remains the same: the normal initializer adds to the container, e.g. myGlobal.insert(self);, and the dealloc method removes it, e.g. myGlobal.erase(self);.

1 Comment

"The variable can either be initialized in its expression" No you can't
0

It turns out the problem was with the names of the instance properties I created, for example I created an int for 'size' and a CALayer for 'layer' but these were being overridden by standard properties. To overcome it I simply added the class name as a prefix to each property. Also, the log was crashing above due to the format being %@ instead of %i. Thanks everyone for your help!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.