Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

arkmannj

macrumors 68000
Original poster
Oct 1, 2003
1,765
562
UT
Hello.

I am trying to teach myself Objective-C, I've been reading the following:
1) Objective-C Programming - The Big Nerd Ranch Guid (1st Edition)
2) The C Programming Language (ANSI C) (2nd Ed.) By Brian Kernighan

I went through about the first 6 or 8 chapters of the BNRG (which is covering basics of C) then switched to the C programming and went through chapter 6.

Anyhow I am now back to the BNRG and on Chapter 15 (NSArray / NSMutableArray) working on the challenge. The challenge is to make a Command Line Foundation project that includes an NSMutable Array, then add some "grocery items" to the array and finally to enumerate through and print all of the items in the array into the Log output.

I did this, and decided to stretch myself a bit further so I could get practice with other skills we have gone through in the book but also found myself needing to learn new skills to accomplish my new goals of creating a pool of available grocery items, randomly build a grocery list from that and print them out.

okay with that lengthy background, I am going to post my code in hopes that someone would be willing to help critique it for me, sure I met the books goals for the chapter and I stretched to meet my own, but I would also like to see what I could/should have done better, best practices, pitfalls to avoid, etc... This was the first time I have done many things (such as making a class, using class methods etc... they are actually in chapters to come) so I am not sure if I did things properly.




main.m
Code:
//
//  main.m
//  groceries
//
//  Created by Ark on 4/7/14.
//  Copyright (c) 2014 Ark. All rights reserved.
//
#include <stdlib.h>
#import <Foundation/Foundation.h>
#import "grocm.h"
#import "inven.h"
#import "randm.h"

//NSMutableArray *grocerylist = [NSMutableArray array];

int noItems = -1;
NSMutableArray *grocerylist;
NSUInteger grocerycount;
NSMutableArray *StoreInv;


int main(int argc, const char * argv[])
{
    @autoreleasepool {
        
        [grocClass grocs];
        
        return 0;
    }
}

grocm.h
Code:
//
//  groc.h
//  groceries
//
//  Created by Arkman  on 4/7/14.
//  Copyright (c) 2014 Arkman . All rights reserved.
//

#import <Foundation/Foundation.h>

@interface grocClass : NSObject

+ (void) GrocItems;
+ (int) grocs;

@end


grocm.m
Code:
//
//  groc.m
//  groceries
//
//  Created by Arkman  on 4/7/14.
//  Copyright (c) 2014 Arkman . All rights reserved.
//

#import "grocm.h"
#import "inven.h"


@implementation grocClass


+ (void) GrocItems {
    //How many groceries
    grocerycount = [grocerylist count];
    NSLog(@"There are now %lu grocery items",grocerycount);
    NSLog(@"Now 1st item is: %@",[grocerylist objectAtIndex:0]);
}


+ (int) grocs {
    
    //init array
    grocerylist = [NSMutableArray array];
    
    //add dates to the array
 /*   
    [grocerylist addObject:@"Celery"];
    [grocerylist addObject:@"Carrots"];
    [grocerylist addObject:@"Apple Juice"];
    [grocerylist addObject:@"Milk"];
    [grocerylist addObject:@"eggs"];
    [grocerylist addObject:@"hamburger"];    
*/
        [InvenClass AddInven];
    
        //How many groceries
        //NSLog(@"There are %lu grocery items",grocerycount);
        //[self GrocItems];
        [grocClass GrocItems];
    
        // print them
        
        //standard [for loop]
        for (int i = 0; i< grocerycount; i++) {
            NSString *d = [grocerylist objectAtIndex:i];
            NSLog(@"Here is the grocery item at array index %d date: %@",i,d);
        }
        
        //fast enumeration [for loop]
        for (NSString *d2 in grocerylist) {
            NSLog(@"Fast Enum: Here is the item: %@",d2);
            
        }
        
        
        // Remove yesterday from NSMutablearray
        [grocerylist removeObjectAtIndex:0];
        //GrocItems();
        // [self GrocItems];
            [grocClass GrocItems];
        
        
        /*
         UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:@"cancel", nil];
         [alert show];
         */
        
        return 0;
    }
@end


inven.h
Code:
//
//  inven.h
//  groceries
//
//  Created by Arkman  on 4/8/14.
//  Copyright (c) 2014 Arkman . All rights reserved.
//

#import <Foundation/Foundation.h>

@interface InvenClass : NSObject

+ (void) AddInven;
extern int noItems;
extern NSMutableArray *grocerylist;
extern NSUInteger grocerycount;
extern NSMutableArray *StoreInv;

@end

inven.m
Code:
//
//  inven.m
//  groceries
//
//  Created by Arkman  on 4/8/14.
//  Copyright (c) 2014 Arkman . All rights reserved.
//

#import "inven.h"
#import "randm.h"
#include <stdio.h>
#include <stdlib.h>

@implementation InvenClass

+ (void) AddInven {
StoreInv = [NSMutableArray array];

[StoreInv addObject:@"Apples"];
[StoreInv addObject:@"Banannas"];
[StoreInv addObject:@"Peas"];
[StoreInv addObject:@"Carrots"];
[StoreInv addObject:@"Brussel Sprouts"];
[StoreInv addObject:@"Broccoli"];
[StoreInv addObject:@"Oranges"];
[StoreInv addObject:@"Bread"];
[StoreInv addObject:@"Milk"];
[StoreInv addObject:@"Butter"];
[StoreInv addObject:@"Cereal"];
[StoreInv addObject:@"Pears"];
[StoreInv addObject:@"Oatmeal"];
[StoreInv addObject:@"Sugar"];
[StoreInv addObject:@"flour"];
[StoreInv addObject:@"chocolate"];
[StoreInv addObject:@"Peanut butter"];
[StoreInv addObject:@"Biscoff Spread"];
[StoreInv addObject:@"Dish Soap"];
[StoreInv addObject:@"Laundry Soap"];
[StoreInv addObject:@"Spinich"];
[StoreInv addObject:@"Peppers"];
[StoreInv addObject:@"Onions"];
[StoreInv addObject:@"Steak"];
[StoreInv addObject:@"Chicken"];
[StoreInv addObject:@"Pork Chops"];
[StoreInv addObject:@"Spaghetti"];
[StoreInv addObject:@"Brown Sugar"];
[StoreInv addObject:@"Pepeproni"];
[StoreInv addObject:@"Tomatoes"];
[StoreInv addObject:@"Cheese"];
[StoreInv addObject:@"Toilet Paper"];
[StoreInv addObject:@"Paper Towels"];
[StoreInv addObject:@"Bleach"];
[StoreInv addObject:@"Honey"];
[StoreInv addObject:@"Shavers"];
[StoreInv addObject:@"Shampoo"];
[StoreInv addObject:@"Hair cream"];
[StoreInv addObject:@"Light Bulbs"];
[StoreInv addObject:@"Garlic"];
[StoreInv addObject:@"Glass Cleaner"];
[StoreInv addObject:@"Ghram Crackers"];
[StoreInv addObject:@"Chocolate bars"];
[StoreInv addObject:@"MashMellows"];
[StoreInv addObject:@"Pistachios"];
[StoreInv addObject:@"Cheesecake"];
[StoreInv addObject:@"Batteries"];
[StoreInv addObject:@"Peanut Butter Cups"];
[StoreInv addObject:@"Hair Spray"];
[StoreInv addObject:@"Lotion"];

    
    
    if (noItems <= 0) { noItems = 1+ abs((arc4random() % 25));} // Random number 0-25
    
    
    
for (int i = 0; i< noItems; i++) {
   [grocerylist addObject:[StoreInv randomObject]];
}


}


@end


randm.h
Code:
//
//  randm.h
//  groceries
//
//  Created by Arkman  on 4/8/14.
//  Copyright (c) 2014 Arkman . All rights reserved.
//

#import <Foundation/Foundation.h>

@interface NSArray (randmClass)

- (id)randomObject;

@end

randm.m
Code:
//
//  randm.m
//  groceries
//
//  Created by Arkman  on 4/8/14.
//  Copyright (c) 2014 Arkman . All rights reserved.
//

#import "randm.h"
#import "inven.h"

@implementation NSArray (randmClass)

-(id)randomObject {
    NSUInteger myCount = [self count];
    if (myCount)
        return [self objectAtIndex:arc4random_uniform(myCount)];
    else
        return nil;
}

@end


I'm not asking for anyone to "fix" the code, it works and the only person I have to answer to is myself on the quality of it. But any guidance, thoughts, feedback would be greatly appreciated. I am trying to prevent myself from going down a path of bad habits, etc... if at all possible.

Thanks
Ark
 
My first thought is naming.

http://developer.apple.com/library/...eptual/CodingGuidelines/CodingGuidelines.html

The main naming things:
  1. Class-names begin with upper case.
  2. Method names begin with lower-case.
  3. If you have to use "Class" in the class-name, you've failed.
    Instances of a class should be nouns. Examples: NSArray, NSDictionary, NSNumber. If a class name isn't a noun, make sure you have a good reason.
  4. Tu mch abrvtn is cnfsng.
    Clarity is not improved. Get a thesaurus, and learn how to look up synonyms. It's one of the most useful books I own.

The main implementation things:
1.Too much repetition.
Code:
StoreInv = [NSMutableArray array];

[StoreInv addObject:@"Apples"];
[StoreInv addObject:@"Banannas"];
[StoreInv addObject:@"Peas"];
[StoreInv addObject:@"Carrots"];
[StoreInv addObject:@"Brussel Sprouts"];
[StoreInv addObject:@"Broccoli"];
Use the array literal syntax instead of a series of method calls:
https://developer.apple.com/library...ollections/FoundationTypesandCollections.html

Literal Syntax
It’s also possible to create an array using an Objective-C literal, like this:
Code:
    NSArray *someArray = @[firstObject, secondObject, thirdObject];

2. Too much confusing extraneous stuff.

There's no reason for a separate rndmClass, especially not as a category.

What purpose is served by separate grocClass and InvenClass?
There's no sense of what an object is (nouns), what the actions are (verbs), nor the relationship between the nouns and verbs. I see no obvious structure at all. It's not object-oriented, it's not class-oriented, it's not even procedural.
 
Last edited:
Also, I wouldn't use extern variables (StoreInv) in a help method only (+ (void) AddInven) in a separate class. Either move AddInven (after changing its name to conform to the usual camel-case convention) to the main class or change it so that it is passed a reference of the already-created NSMutableArray instance and just add new items to this. As mutable array references are passed as references, the changes will be visible in the caller.
 
First I wanted to thank you both (chown33, Menneisyys2) for taking the time to respond. I very much appreciate the time you took in doing so, and the feedback.

I did want to make a couple comments.
  • I realize I didn't need to make so many classes, but this was my first time, and basically once I got one working, I just wanted to try and make some more to get them working.
  • Thank you for the help with naming, and sharing the links I had not really thought about using nouns, verbs, etc.. I feel a little silly as that makes (almost) perfect sense now that you brought it to my attention.

Again thank you, I appreciate the candor, hopefully if I have another post as I continue to try and learn then you will see improvement in these areas. :)
I obviously still have a long way to go in my learning.
 
[*]Thank you for the help with naming, and sharing the links I had not really thought about using nouns, verbs, etc.. I feel a little silly as that makes (almost) perfect sense now that you brought it to my attention.

You're welcome. If you want comments on revised versions, feel free to post them in this thread.

Personally, I don't understand why the noun/verb thing is never mentioned in any books or tutorials. At least none I've ever seen.

Back in the old days, when we programmers were first learning the new-fangled object-oriented thing (yes, well before the invention of C++) and how to make our modular procedural code into objects, I read an article in some long-forgotten magazine that specifically made the analogy of objects as nouns. To me, that was a revelation, and I began looking at my procedural code using the same metaphor. It was clear then that the data structures were the nouns, and the procedures were the verbs, but also sometimes adjectives or adverbs (modifiers). That noun/verb thing stuck with me, and I use it to this day when selecting names for classes and methods, as well as variables.
 
Second (Version)

Hello!
I tried to implement many of the suggestions, hopefully I'm improving somewhat :)



main.m
Code:
//  main.m
//  groceries
//
//  Created by ArkStudios on 4/7/14.
//  Copyright (c) 2014 ArkStudios. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "StoreInventory.h"
#import "MyGroceries.h"


int main(int argc, const char * argv[])
{
    @autoreleasepool {
        
        //Create array containing Store Inventory (All items that could potentially be added to a grocery list)
        //Create array for my grocery list (random items pulled from Available Store Inventory)
        //Show My Entire Grocery list
        //Check off (remove) a grocery item from the list
        //Show the next item on the grocery list
        
        
        [StoreInventory createInventory];   //Create store inventory to pick from
        [StoreInventory listInventory];     // List all the items we've added to the store inventory
        
        [MyGroceries makeGroceryList];      // Build Grocery List
        [MyGroceries countGroceries];       //How many groceries remaining on my grocery list, and show next item on the list
        
        [MyGroceries removeNextListItem];
        [MyGroceries countGroceries];
        
        return 0;
    }
}

MyGroceries.h
Code:
//  MyGroceries.h
//  groceries
//
//  Created by ArkStudios on 4/7/14.
//  Copyright (c) 2014 ArkStudios. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface MyGroceries : NSObject

+ (void) countGroceries;
+ (int)  makeGroceryList;
+ (void) printGroceryList;
+ (int)  removeNextListItem;

extern NSMutableArray  *grocerylist;
extern NSUInteger       grocerycount;

@end

MyGroceries.m
Code:
//  MyGroceries.m
//  groceries
//
//  Created by ArkStudios on 4/7/14.
//  Copyright (c) 2014 ArkStudios. All rights reserved.
//
#import "MyGroceries.h"
#import "StoreInventory.h"

@implementation MyGroceries

/* Variables */
int itemsToGet = -1;
NSMutableArray *grocerylist;
NSUInteger grocerycount;
NSMutableArray *StoreInv;

+ (int) makeGroceryList {
    
    grocerylist = [NSMutableArray array];
    
    //add Grocery Itmes to the grocery List array
    NSLog(@"Making Grocery List!");
    
    if (itemsToGet <= 0) { itemsToGet = 1+ abs((arc4random() % 25));} // Random number 0-25
    NSLog(@"Items to get: %d!",itemsToGet);
    
    for (int i = 0; i< itemsToGet; i++) {
        [grocerylist addObject:[StoreInventory RandomItemFromStoreInventory]];
    }
    
        //standard [for loop] (for practice)
        for (int i = 0; i< [grocerylist count]; i++) {
            NSString *d = [grocerylist objectAtIndex:i];
            NSLog(@"Added '%@' to Grocery List array index %d",d,i);
        }
     return 0;
}


+ (void) countGroceries {
    long Gcount = [grocerylist count];
    NSLog(@"There are now %lu items on your list",Gcount);
    if (Gcount > 0) {
        //How many groceries
        NSLog(@"Your next grocery item is: %@",[grocerylist objectAtIndex:0]);
        
    }
    else {NSLog(@"No More items in your list %lu",Gcount);}
}


+ (void) printGroceryList {
    
    //fast enumeration [for loop] (for Practice)
    for (NSString *d2 in grocerylist) {
        NSLog(@"Fast Enum: Here is the item: %@",d2);
        
    }
    
}

    
 + (int) removeNextListItem {
        // Remove Grocery Item from NSMutablearray
        NSLog(@"Removing from Grocery List: %@",[grocerylist objectAtIndex:0]);
        [grocerylist removeObjectAtIndex:0];
        NSLog(@"New Top Item on Grocery List: %@",[grocerylist objectAtIndex:0]);
        return 0;
    }
@end

StoreInventory.h
Code:
//  StoreInventory.h
//  groceries
//
//  Created by ArkStudios on 4/8/14.
//  Copyright (c) 2014 ArkStudios. All rights reserved.
//
#import <Foundation/Foundation.h>

@interface StoreInventory : NSObject

+ (void)    createInventory;
+ (void)    listInventory;
+ (id)      RandomItemFromStoreInventory;

extern NSMutableArray   *availableStoreInventory;
extern NSUInteger        grocerycount;

@end

StoreInventory.m
Code:
//  StoreInventory.m
//  groceries
//
//  Created by ArkStudios on 4/8/14.
//  Copyright (c) 2014 ArkStudios. All rights reserved.
//
#import "StoreInventory.h"
#import "MyGroceries.h"

@implementation StoreInventory

/* Variables */
NSUInteger inventoryCount = -1;
NSMutableArray *availableStoreInventory ;


+ (void) createInventory {
   availableStoreInventory = [NSMutableArray array];
    
  NSLog(@"Creating Inventory!");
    [availableStoreInventory addObject:@"Apples"];
    [availableStoreInventory addObject:@"Banannas"];
    [availableStoreInventory addObject:@"Peas"];
    [availableStoreInventory addObject:@"Carrots"];
    [availableStoreInventory addObject:@"Brussel Sprouts"];
    [availableStoreInventory addObject:@"Broccoli"];
    [availableStoreInventory addObject:@"Oranges"];
    [availableStoreInventory addObject:@"Bread"];
    [availableStoreInventory addObject:@"Milk"];
    [availableStoreInventory addObject:@"Butter"];
    [availableStoreInventory addObject:@"Cereal"];
    [availableStoreInventory addObject:@"Pears"];
    [availableStoreInventory addObject:@"Oatmeal"];
    [availableStoreInventory addObject:@"Sugar"];
    [availableStoreInventory addObject:@"flour"];
    [availableStoreInventory addObject:@"chocolate"];
    [availableStoreInventory addObject:@"Peanut butter"];
    [availableStoreInventory addObject:@"Biscoff Spread"];
    [availableStoreInventory addObject:@"Dish Soap"];
    [availableStoreInventory addObject:@"Laundry Soap"];
    [availableStoreInventory addObject:@"Spinich"];
    [availableStoreInventory addObject:@"Peppers"];
    [availableStoreInventory addObject:@"Onions"];
    [availableStoreInventory addObject:@"Steak"];
    [availableStoreInventory addObject:@"Chicken"];
    [availableStoreInventory addObject:@"Pork Chops"];
    [availableStoreInventory addObject:@"Spaghetti"];
    [availableStoreInventory addObject:@"Brown Sugar"];
    [availableStoreInventory addObject:@"Pepeproni"];
    [availableStoreInventory addObject:@"Tomatoes"];
    [availableStoreInventory addObject:@"Cheese"];
    [availableStoreInventory addObject:@"Toilet Paper"];
    [availableStoreInventory addObject:@"Paper Towels"];
    [availableStoreInventory addObject:@"Bleach"];
    [availableStoreInventory addObject:@"Honey"];
    [availableStoreInventory addObject:@"Shavers"];
    [availableStoreInventory addObject:@"Shampoo"];
    [availableStoreInventory addObject:@"Hair cream"];
    [availableStoreInventory addObject:@"Light Bulbs"];
    [availableStoreInventory addObject:@"Garlic"];
    [availableStoreInventory addObject:@"Glass Cleaner"];
    [availableStoreInventory addObject:@"Ghram Crackers"];
    [availableStoreInventory addObject:@"Chocolate bars"];
    [availableStoreInventory addObject:@"MashMellows"];
    [availableStoreInventory addObject:@"Pistachios"];
    [availableStoreInventory addObject:@"Cheesecake"];
    [availableStoreInventory addObject:@"Batteries"];
    [availableStoreInventory addObject:@"Peanut Butter Cups"];
    [availableStoreInventory addObject:@"Hair Spray"];
    [availableStoreInventory addObject:@"Lotion"];
    
 
    for (NSString *d in availableStoreInventory)
    {
        NSLog(@" Added to Store Inventory: %@", d);
        
    }
   // NSLog(@"-Items in store Inventory: %lu",[availableStoreInventory count]);
    
}


+ (void) listInventory {
    NSLog(@"Listing Inventory");
    inventoryCount = [availableStoreInventory count];
    for (NSString *d in availableStoreInventory)
    {
        NSLog(@" In Store Inventory: %@", d);
        
    }
    
    NSLog(@"Items in store Inventory: %lu",inventoryCount);
    NSLog(@"A) inven 0: %@",[availableStoreInventory objectAtIndex:0]);

}


+ (id) RandomItemFromStoreInventory {
    NSUInteger myCount = [availableStoreInventory count];
    if (!myCount) {myCount = 1; }
    //NSLog(@"****RandomitemFromStoreInventory**mycount: %lu", myCount);
    
    if (myCount) {
        NSLog(@"B) inven 0: %@",[availableStoreInventory objectAtIndex:0]);
        return [availableStoreInventory objectAtIndex:arc4random_uniform(myCount)];
    } else {
     return nil;
    }
}
@end
 
All your methods are class methods. You have no instance methods. Is there a particular reason for that?

If I am to be compleatly honest it's because
  1. The program worked this way.
  2. I'm still trying to wrap my head around the differences in the types of methods.
  3. I don't (yet) know better.

Sad reasons I know...but I got to start somewhere I suppose.


I must admit, I'm very capable when it comes to SQL, HTML,CSS, JavaScript
but Objective-C so far I'm feeling pretty dumb. To write a web page, the SQL code (stored procedures) etc. to do the same thing as I'm trying above would be trivial. But that's part of why I'm trying to learn Obj-C, for the growth. I could have picked another language but being an Apple fan, technology pointing that direction held the most interest for me :)
 
Last edited:
You don't get classes at all if you don't get the difference between classes and instances, I don't think. You may as well be writing your code in straight C if you're only going to use class methods.
 
You don't get classes at all if you don't get the difference between classes and instances, I don't think. You may as well be writing your code in straight C if you're only going to use class methods.


Thank you for taking time to share your thought and I don't disagree with what you said. However, I haven't actually gotten to "Classes" in the book I'm going through and so far the author has likened Classes in Obj-C to functions and left it at that. So by that understanding you are likely spot on as that's the example I have so far that's kind of how I have treated them.

the actual chapter/challenge I'm on is covering NSArray and NSMutableArray really all it asked for was to make an array, add items to the array and then remove a item from the array and finally use a loop to print the results to the console. That seemed to easy so I tried to challenge myself. I find I learn better when I try to make a challenge (and back when I was in school, assignments) "my own" by incorporating some of my own goals. in this case I wanted to give myself some purpose and made it into an array for a store inventory and a possible grocery list based on that inventory.

Specifically to your point though, as I said my self, this is a deficiency I recognize I have at this point in my learning path. I have gathered a few bits of information specifically on Classes/Instances and will review those tonight to try and improve my understanding on those topics specifically. If you have any insight, suggestions, thoughts, ways for me to better implant what I have going or materials you could share that would be both helpful and appreciated.
 
Last edited:
I feel like you are getting ahead of yourself a bit. Yes, it's good to want to challenge yourself but you have to be careful to not bite off way more than you can chew at this point. Concentrate on learning the fundamentals as presented in the manner laid out in the book. You're very close to Chapter 17, where you get to create your own class. I would keep reading and doing the challenges based on what you've been taught, until you finish the book. If you think up some variation on a challenge, make a note of it, and then revisit that once you've finished the book.

However, I will say, I'm not sure the BNR book does a good job explaining the distinction between class methods and instance methods. Stephen Kochan's "Programming in Objective-C" talks about it explicitly in Chapter 3, 'Classes, Objects, and Methods'.
 
Last edited:
I think I know what happened here: Your read to much on Ansi-C. Good modern objective-c has not much in common with Ansi-C thats why books on objective-c *don't* explain every c feature. They explain the objective-c language and the common idioms of it. Why did you switch to the 2nd book?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.