-1

I'm having trouble making a shopping cart sort-of concept in my app. I have my AppDelegate (named ST2AppDelegate) that contains an NSMutableArray called myCart. I want RecipeViewController.m to pass an NSString object to myCart, but every time I pass it the NSString and use NSLog to reveal the contents of the array, it is always empty.

Can anyone please tell me what I am doing wrong? I have worked on this code for days, and there is a line of code in which I don't understand at all what's going on (in the RecipeViewController.m, labeled as such).

Any help would be so appreciated... I'm just a beginner. Here are the relevant classes:

ST2AppDelegate.h:

#import <UIKit/UIKit.h>

@interface ST2AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) NSMutableArray* myCart;

- (void)addToCart:(NSString*)item;
- (void)readCartContents;

@end

ST2AppDelegate.m:

#import "ST2AppDelegate.h"

@implementation ST2AppDelegate

@synthesize myCart;

// all the 'applicationDid...' methods...

- (void)addToCart:(NSString *)item
{
    [self.myCart addObject:item];
}

- (void)readCartContents
{
    NSLog(@"Contents of cart: ");
    int count = [myCart count];
    for (int i = 0; i < count; i++)
    {
        NSLog(@"%@", myCart[count]);
    }
}

@end

RecipeDetailViewController.h:

#import <UIKit/UIKit.h>
#import "ST2AppDelegate.h"

@interface RecipeDetailViewController : UIViewController 

@property (nonatomic, strong) IBOutlet UILabel* recipeLabel;
@property (nonatomic, strong) NSString* recipeName;
@property (nonatomic, strong) IBOutlet UIButton* orderNowButton;

- (IBAction)orderNowButtonPress:(id)sender;

@end

RecipeDetailViewController.m:

#import "RecipeDetailViewController.h"

@implementation RecipeDetailViewController

@synthesize recipeName;
@synthesize orderNowButton;

// irrelevant methods...

- (IBAction)orderNowButtonPress:(id)sender
{
    // alter selected state
    [orderNowButton setSelected:YES];
    NSString* addedToCartString = [NSString stringWithFormat:@"%@ added to cart!",recipeName];
    [orderNowButton setTitle:addedToCartString forState:UIControlStateSelected];

    // show an alert
    NSString* addedToCartAlertMessage = [NSString stringWithFormat:@"%@ has been added to your cart.", recipeName];
    UIAlertView* addedToCartAlert = [[UIAlertView alloc] initWithTitle:@"Cart Updated" message:addedToCartAlertMessage  delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [addedToCartAlert show];

    // add to cart (I don't understand this, but it works)
    [((ST2AppDelegate*)[UIApplication sharedApplication].delegate) addToCart:recipeName];

    // read cart contents
    [((ST2AppDelegate*)[UIApplication sharedApplication].delegate) readCartContents];
}

@end
Ortwin Gentz
  • 52,648
  • 24
  • 135
  • 213
  • 1
    Are you allocating space for that NSMutableArray before you pass it and push items into it. If not, it will remain empty – MZimmerman6 Jul 09 '13 at 16:41
  • 1
    Did you initalize your NSMutableArray? Maybe it's nil? – h4labs Jul 09 '13 at 16:41
  • possible duplicate of [Having trouble adding objects to NSMutableArray](http://stackoverflow.com/q/851926) [Cannot add items to an NSMutableArray ivar](http://stackoverflow.com/q/7125326), [\[NSMutableArray addObject:\] not affecting count](http://stackoverflow.com/q/3683761), [\[NSMutableArray addObject:\] not working](http://stackoverflow.com/q/1827058) – jscs Jul 09 '13 at 19:23

2 Answers2

2

You need to initialize myCart when your application launches:

self.myCart = [[NSMutableArray alloc] init];

otherwise you are just attempting to add objects to a nil object which while it won't throw an exception because of the way objective-c handles nil objects it will not function as expected until you initialize it.

1

Do you ever initalize the shopping cart variable?

Try doing lazy instantiation.

-(NSMutableArray *) myCart{
     if (!_myCart){
          _myCart = [[NSMutableArray alloc] init];
     }
   return _myCart;

}

This way you will know it will always get allocated. Basically, this method makes it so that whenever someone calls your classes version of the object it checks to see if that object has been allocated and then allocates it if it has not. It's a common paradigm that you should employ with most of your objects.

This method should go in the app delegate (where the object was declared).

AdamG
  • 3,718
  • 2
  • 18
  • 28
  • I'm far lazier than that -- I'd just init the thing in the app delegate's `init` routine. – Hot Licks Jul 09 '13 at 17:20
  • I would recommend that you don't do that because it could possibly waste memory. – AdamG Jul 10 '13 at 23:38
  • In the grand scheme of things an empty mutable array is chicken feed. (And if the array will always be referenced then using lazy initialization is simply foolish added complexity.) Lazy initialization is only worthwhile where significant space and/or time is required for initialization and the object will not inevitably be referenced. And if you use lazy initialization, in the general case, you need to use a pattern that is more robust in the face of multithreading. – Hot Licks Jul 11 '13 at 02:42
  • The foresight of lazy instantiation would allow you to modify your app more easily without worrying. Also, shouldn't you only be writing to the array on the main thread? To my knowledge it would be bad practice to write to a shared resource unless you are using semaphores or something a lot more complex than the typical asynchronous thread. That way you could avoid writing to a resource in the asynchronous thread before the main thread executes a read and grabs the same information. I am not claiming to be an expert on this particular issue, and would love to hear what you have to say. – AdamG Jul 12 '13 at 03:46