Objective-C Stack implementation I just started coding in Objective-C and would like to know if my simple implementation of a Stack is acceptable &amp; what ways would you improve the Stack code, or the Main code? i'm curious of things such as (but not limited to):


formatting
edge cases
run time (like one part where try to manipulate strings in description)
general good practice
memory management practices (i'm using ARC in this code)


Stack.h:

#import &lt;Foundation/Foundation.h&gt;

@interface Stack : NSObject

-(void)push:(id)obj;
-(id)pop;
-(NSUInteger)size;
-(id)peek;
-(BOOL)isEmpty;

@end


Stack.m file:

#import "Stack.h"

@implementation Stack{
    NSMutableArray *stack;
}

-(id)init{
    self = [super init];
    if(self!=nil){
        stack = [[NSMutableArray alloc] init];
    }
    return self;
}

-(void)push:(id)obj{
    [stack addObject:obj];
}

-(id)pop{
    id lastObj = [stack lastObject];
    [stack removeLastObject];
    return lastObj;
}

-(NSUInteger)size{
    return stack.count;
}

-(id)peek{
    return [[stack lastObject] copy];
}

-(BOOL)isEmpty{
    return stack.count == 0;
}

-(NSString *)description{
    NSMutableString *result = [[NSMutableString alloc] initWithString:@"["];
    for (id s in stack) {
        [result appendFormat:@"%@, ",[s description]];
    }
    if (stack.count&gt;0) {
        result = [[result stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@", "]] mutableCopy];
    }
    [result appendString:@"]"];
    return result;
}

@end


Lastly, this is how i verify my code is "working":

#import &lt;Foundation/Foundation.h&gt;

#import "Stack.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        Stack *s1 = [[Stack alloc] init];
        assert([s1 size]==0);
        assert([s1 pop]==nil);
        assert([s1 peek]==nil);
        assert([s1 isEmpty]==YES);
        NSLog(@"first set of tests passed");
        [s1 push:[NSNumber numberWithInt:0]];
        [s1 push:[NSNumber numberWithInt:3]];
        [s1 push:[NSNumber numberWithInt:5]];
        NSLog(@"%@",[s1 description]);
        assert(![s1 isEmpty]);
        assert(s1.size == 3);
        assert([[s1 peek] isEqual:[NSNumber numberWithInt:5]]);
        assert([[s1 pop] isEqual:[NSNumber numberWithInt:5]]);
        assert(s1.size == 2);
        assert([[s1 pop] isEqual:[NSNumber numberWithInt:3]]);
        assert(![[s1 pop] isEqual:[NSNumber numberWithInt:3]]);
        assert([s1 pop] == nil);
        assert(s1.isEmpty);
        NSLog(@"second set of tests passed");
    }
    return 0;
}
-(id)pop{
    id lastObj = [stack lastObject];
    [stack removeLastObject];
    return lastObj;
}


Not sure if you are using ARC, but without ARC this is a potential use-after-free bug.  If you are not using ARC you should consider:

-(id)pop{
    id lastObj = [stack lastObject];

    if (lastObj)                         // &lt; -- now checking for nil
    {
       [[lastObj retain] autorelease];   // &lt; -- this line added

       [stack removeLastObject];
    }
    return lastObj;
}


(This also assumes that the objects in the stack are NSObjects, but I believe NSMutableArray makes the same assumption...)

This bumps the ref count up so that the next line (which will cause the NSMutableArray to release its reference to the object) does not end up deallocating the object.

Update on second reading:

Also, what do you do when lastObj is nil (i.e. too many pops)?  Doesn't seem like you've handled that case.