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

childoftheko4n

macrumors 6502
Original poster
Oct 18, 2011
276
88
Evening,

So I am trying to teach myself Objective-C and have a question. One particular area of toughness so far to me appears to be this:

Lets say NSObject has 2 classes: Employee & Asset
I want to create 10 instances of each, have each instance number (Employee ID and Asset Number), and then link the two together in an array.

This is what my scrap work looks like so far:

Code:
main.m:
int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        //create employee list array
        NSMutableArray *employeeList = [[NSMutableArray alloc] init];
        
//create 10 employees, assign their employee ID, and add to employee list array
        for (int i = 1; i <11; i++)
        {
            Employee *employeeInstance = [[Employee alloc] init];
            [employeeInstance setEmployeeID:i];
            [employeeList addObject:employeeInstance];
            
            
        }
        
        
      //create 10 assets (laptops)
        for (int i =1; i<11; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            
            //find employee ID number that matches asset number (i?)
            Employee *employeeNumbered = [employeeList objectAtIndex:i];
            
            //assign the asset to the employee
            ????????????????


So im pretty sure everything looks good right up to the end of the asset section. I am not sure how i would go about assigning the asset (i) to the employee from the array employeeList (at index i)



My .h/.m files for the 2 classes are pretty bare at the moment, trying to keep this as basic as possible up until i got the the "assigning" portion to help myself better understand this concept:

@interface Employee : NSObject
@property int employeeID;

@implementation Employee
@synthesize employeeID;


@interface Asset : NSObject
@property NSString *assetLable;

@implementation Asset
@synthesize assetLable;

Thank you!!!

(BTW using Big Nerd Ranch Guide, for what its worth)
 
Last edited by a moderator:
This code looks like it comes from the Big Nerd ranch Objective-C book ?

Have you looked on their forums as well for answers and help?
 
This code looks like it comes from the Big Nerd ranch Objective-C book ?

Have you looked on their forums as well for answers and help?

It actually does haha. I was doing the practice in the chapter and struggling with understanding it, so i tried to rewrite it in a simpler fashion with ONLY what was the part that i was struggling with.

----------

Give your employee class an asset property.

How exactly would you go about setting that property and creating that relationship, if you were to write it in the most basic form?
 
im still stuck on this =(

so i have added this to the "create assets" section of main

Code:
  //create 10 assets (laptops)
        for (int i =1; i<11; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            
            //find employee ID number that matches asset number (i?)
            Employee *employeeNumbered = [employeeList objectAtIndex:i];

Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
[employeeToGetAsset addAssetToEmployee:assetInstance];

Is that portion right? Would it assign asset #3 to employee ID #3? (using int i)

If so, when it comes time to printing results it i am having an issue now as well.
 
im still stuck on this =(

so i have added this to the "create assets" section of main

Code:
  //create 10 assets (laptops)
        for (int i =1; i<11; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            
            //find employee ID number that matches asset number (i?)
            Employee *employeeNumbered = [employeeList objectAtIndex:i];

Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
[employeeToGetAsset addAssetToEmployee:assetInstance];

Is that portion right? Would it assign asset #3 to employee ID #3? (using int i)

If so, when it comes time to printing results it i am having an issue now as well.

Yes, it is assigning #3 to #3.

What issue are you having when printing results?
 
i think its more or less how to print results. My initial try was
Code:
for (int i = 0; i< [employeeList count]; i++)
{
    Employee *employeeToPrint = [employeeList objectAtIndex:i];
    NSLog(@"Employee ID:%i", [employeeToPrint employeeID]);
    
}

but i am also getting an error with the assigning portion of the asset code (that i just posted today)

Code:
      //create 10 assets (laptops)
        for (int i =1; i<11; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            

           [B] Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
 [/B]
            [employeeToGetAsset addAssetToEmployee:assetInstance];
           
        }

returns this error:
Thread 1: signal SIGABRT
 
i think its more or less how to print results. My initial try was
Code:
for (int i = 0; i< [employeeList count]; i++)
{
    Employee *employeeToPrint = [employeeList objectAtIndex:i];
    NSLog(@"Employee ID:%i", [employeeToPrint employeeID]);
    
}

but i am also getting an error with the assigning portion of the asset code (that i just posted today)

Code:
      //create 10 assets (laptops)
        for (int i =1; i<11; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            

           [B] Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
 [/B]
            [employeeToGetAsset addAssetToEmployee:assetInstance];
           
        }

returns this error:
Thread 1: signal SIGABRT

Paste the error from the console

But anyway, I am gonna go ahead and guess you are trying to fetch employeeToGetAsset from a non existant index.

How do you set up an employeeList?
 
error from the console:

2013-07-23 18:56:49.986 BMI By Myself Test[35469:303] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 10 beyond bounds [0 .. 9]'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff8af82b06 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff8b1e03f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8af1f8ec -[__NSArrayM objectAtIndex:] + 252
3 BMI By Myself Test 0x0000000100001763 main + 451
4 libdyld.dylib 0x00007fff855817e1 start + 0
)
libc++abi.dylib: terminate called throwing an exception
(lldb)

and here is the main code
Code:
#import <Foundation/Foundation.h>
#import "Asset.h"
#import "Employee.h"


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

    @autoreleasepool {
        
        //create employee list array
        NSMutableArray *employeeList = [[NSMutableArray alloc] init];
        
     //create 10 employees, assign their employee ID, and add to employee list array
        for (int i = 1; i <11; i++)
        {
            
            Employee *employeeInstance = [[Employee alloc] init];
            [employeeInstance setEmployeeID:i];
            [employeeList addObject:employeeInstance];
            
            
        }
        
        
      //create 10 assets (laptops)
        for (int i =1; i<11; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            

            Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
            [employeeToGetAsset addAssetToEmployee:assetInstance];
            
        }

see, i know if i take out the last part of the asset code, where i try to assign it to an employee, and i try
Code:
for (int i = 0; i< [employeeList count]; i++)
{
    Employee *employeeToPrint = [employeeList objectAtIndex:i];
    NSLog(@"Employee ID:%i", [employeeToPrint employeeID]);
    
}

then it works, the log prints out each employee ID, but when i try the code to assign it and print it, thats where it throws it (during the assigning)
 
Try, see what happens

Code:
#import <Foundation/Foundation.h>
#import "Asset.h"
#import "Employee.h"


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

    @autoreleasepool {
        
        //create employee list array
        NSMutableArray *employeeList = [[NSMutableArray alloc] init];
        
     //create 10 employees, assign their employee ID, and add to employee list array
        for (int i = 0; i < 10; i++)
        {
            
            Employee *employeeInstance = [[Employee alloc] init];
            [employeeInstance setEmployeeID:i];
            [employeeList addObject:employeeInstance];
            
            
        }
        
        
      //create 10 assets (laptops)
        for (int i = 0; i < 10; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            

            Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
            [employeeToGetAsset addAssetToEmployee:assetInstance];
            
        }
 
Array indexes are zero based. Read the error message. Index 10 is out of range if the array has 10 elements. The last element's index would be 9. Your loop should start at 0 and end at 9.

Or better yet use fast enumeration.
 
wow, so i definitely had 1 and not 0 in there, that corrects that error.

How would you add to the NSLog/print portion to retrieve and print it in the fashion of
Employee ID: x has "Laptop x"
?

Thanks again , i really do appreciate your alls help :)
 
wow, so i definitely had 1 and not 0 in there, that corrects that error.

How would you add to the NSLog/print portion to retrieve and print it in the fashion of
Employee ID: x has "Laptop x"
?

Thanks again , i really do appreciate your alls help :)

Try:

Code:
//create 10 assets (laptops)
        for (int i = 0; i < 10; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetNumber =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLable:assetNumber];
            

            Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
            [employeeToGetAsset addAssetToEmployee:assetInstance];
            
            [B]NSLog(@"Employee #%i has Laptop #%i", i + 1);[/B]
        }
 
To expand on that, NSLog can take any number of arguments. So you could use multiple format specifiers in your first argument, then have the rest of the arguments to match. For example:

Code:
for (Employee *employee in employeeList) {
  NSLog(@"Employee ID:%d has \"%@\"", employee.employeeID, employee.asset.assetLable);
}

I'm assuming you would add a property "asset" on the Employee class to retrieve the associated Asset for an Employee.

As a side note, you should be more careful with your naming of variables & members. For example you have typos in the names (e.g. "Lable"). And you're creating a NSString and calling it "assetNumber" when it includes much more than just a number. Really it's a label or description or something. The variable name should reflect that. Believe me, down the road it pays off big time to correctly name things.
 
To expand on that, NSLog can take any number of arguments. So you could use multiple format specifiers in your first argument, then have the rest of the arguments to match. For example:

Code:
for (Employee *employee in employeeList) {
  NSLog(@"Employee ID:%d has \"%@\"", employee.employeeID, employee.asset.assetLable);
}

I'm assuming you would add a property "asset" on the Employee class to retrieve the associated Asset for an Employee.

As a side note, you should be more careful with your naming of variables & members. For example you have typos in the names (e.g. "Lable"). And you're creating a NSString and calling it "assetNumber" when it includes much more than just a number. Really it's a label or description or something. The variable name should reflect that. Believe me, down the road it pays off big time to correctly name things.

Couldn't have said any better
 
To expand on that, NSLog can take any number of arguments. So you could use multiple format specifiers in your first argument, then have the rest of the arguments to match. For example:

Code:
for (Employee *employee in employeeList) {
  NSLog(@"Employee ID:%d has \"%@\"", employee.employeeID, employee.asset.assetLable);
}

I'm assuming you would add a property "asset" on the Employee class to retrieve the associated Asset for an Employee.

As a side note, you should be more careful with your naming of variables & members. For example you have typos in the names (e.g. "Lable"). And you're creating a NSString and calling it "assetNumber" when it includes much more than just a number. Really it's a label or description or something. The variable name should reflect that. Believe me, down the road it pays off big time to correctly name things.

Definetely noted on the naming and typos. No excuse for that.

However on the code sample above, i get "Proper asset" not found on object of type "employee" when i try to link employee.asset.assetlable

----------

This method did work however:

Code:
      //create 10 assets (laptops)
        for (int i =0; i<11; i++)
        {
            Asset *assetInstance = [[Asset alloc] init];
            NSString *assetIdentifier =[NSString stringWithFormat:@"Laptop:%i", i];
            [assetInstance setAssetLabel:assetIdentifier];
            

            
             Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
            [employeeToGetAsset addAssetToEmployee:assetInstance];
            
            NSLog(@"Employee ID:%i has Laptop #%i", i, i);

I just want to make sure whatever i do, i am fully understanding and creating the relationships amongst them before moving forward
 
I also feel like while the one code above that did work, it's only because asset "i" is the same as employee "i" and wouldn't otherwise. Therefore I definitely need to ironout what I am missing between establishing the relationship between the two
 
I also feel like while the one code above that did work, it's only because asset "i" is the same as employee "i" and wouldn't otherwise. Therefore I definitely need to ironout what I am missing between establishing the relationship between the two

Hollersoft's code is way more robust than simply writing

Code:
NSLog(@"Employee ID:%i has Laptop #%i", i, i);

The above works because of the structure of your code. If you had something more complex it would definitely not work and you would have to use Hollersoft's code.
 
I also feel like while the one code above that did work, it's only because asset "i" is the same as employee "i" and wouldn't otherwise. Therefore I definitely need to ironout what I am missing between establishing the relationship between the two

This is why having a -description method for your data class objects is useful.
It can simply output a string you can structure to show important information about the object.

Also from memory NSArray when asked for description will list the objects in the array as a list by the objects description. Below is completely untested from memory, but I hope you get the idea.

so if Asset.m had

Code:
-description
{
return self.assetInstance;
}

then if Employee.m had
Code:
-description
{
return [NSString stringWithFormat:@"Employee ID: %i has %@", self.employeeID, [self.asset description]];
}

then after making your array of employee's
Code:
NSLog([employeeList description]);
 
However on the code sample above, i get "Proper asset" not found on object of type "employee" when i try to link employee.asset.assetlable
The answer to that is in my second paragraph (also suggested by ArtOfWarfare earlier in the thread).

This is why having a -description method for your data class objects is useful.
It can simply output a string you can structure to show important information about the object.

Also from memory NSArray when asked for description will list the objects in the array as a list by the objects description. Below is completely untested from memory, but I hope you get the idea.

so if Asset.m had

Code:
-description
{
return self.assetInstance;
}
Very good point. (I think you mean assetLable, not assetInstance but the idea is sound.) This is an example of encapsulation, one of the very important principles of object-oriented programming. The "user" of a class should know as little as possible about that class's internal structure. In this case, the Employee class should not know about the member names ("assetLable") if you can avoid it. It's better to hide that behind a well designed interface (methods and properties).

Actually this is an absolutely perfect example of why. If you have references to that "assetLable" member all over your code, then when you go to fix the spelling error or make other changes to that property (maybe you want to use a whole list of things, or compute it from some other contained objects or something) you have a lot of work to do. If it's properly encapsulated (hidden behind the "description" method, or other methods) then you only have to change one place.
 
**edit, i think i got everything working now, just need to format the asset portion to print properly

Main.m
Code:
    #import <Foundation/Foundation.h>
    #import "Asset.h"
    #import "Employee.h"


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

        @autoreleasepool {
           
            //create employee list array
            NSMutableArray *employeeList = [[NSMutableArray alloc] init];
           
         //create 10 employees, assign their employee ID, and add to employee list array
            for (int i = 0; i <11; i++)
            {
               
                Employee *employeeInstance = [[Employee alloc] init];
                [employeeInstance setEmployeeID:i];
                [employeeList addObject:employeeInstance];
               
               
            }
           
           
          //create 10 assets (laptops)
            for (int i =0; i<11; i++)
            {
                Asset *assetInstance = [[Asset alloc] init];
                NSString *assetIdentifier =[NSString stringWithFormat:@"Laptop:%i", i];
                [assetInstance setAssetLabel:assetIdentifier];
               

               
                 Employee *employeeToGetAsset = [employeeList objectAtIndex:i];
                [employeeToGetAsset addAssetToEmployee:assetInstance];
                [employeeToGetAsset.assetLabel = assetInstance;
               
               
               
            }

           
            for (Employee *employee in employeeList)
            {
                NSLog(@"Employee ID: %i has %@", employee.employeeID, employee.assetLabel);
            }
           

           
        }
        return 0;
    }

Employee.h
Code:
    #import <Foundation/Foundation.h>
    #import "Asset.h"


    @interface Employee : NSObject
    @property int employeeID;


    @property (strong) Asset *assetLabel;

    @property NSMutableArray *arrayOfOneEmployeeAssets;
    -(void) addAssetToEmployee: (Asset *)a;


    @end

Employee.m
Code:
    #import "Employee.h"
    #import "Asset.h"

    @implementation Employee
    @synthesize employeeID;
    @synthesize arrayOfOneEmployeeAssets;

    -(void) addAssetToEmployee: (Asset *)a
    {
        if (!arrayOfOneEmployeeAssets)
        {
            arrayOfOneEmployeeAssets = [[NSMutableArray alloc] init];
        }
        [arrayOfOneEmployeeAssets addObject:a];
    }


    @synthesize assetLabel;


    @end

Asset.h
Code:
    #import <Foundation/Foundation.h>

    @interface Asset : NSObject
    @property NSString *assetLabel;

    @end

Asset.m
Code:
    #import "Asset.h"

    @implementation Asset
    @synthesize assetLabel;

    @end

This assigns everythign correctly it appears, just not printing in the correct format:
Employee ID 1 has <Asset: ox10010b510>
 
Last edited:
Been reading and testing today. Think I have a grasp now , finally. I'm going to recode this tonight and see if I can do it.

I appreciate all the assistance :)
 
This assigns everythign correctly it appears, just not printing in the correct format:
Employee ID 1 has <Asset: ox10010b510>

You've probably got this figured out already but I'll just add some more explanation in case anyone else finds this thread useful.

Back to my point about naming. Your code as posted is using "employee.assetLabel" in the NSLog call. From the name of that property, you would expect to see an NSString (or maybe a UILabel). But you've declared

Code:
@property (strong) Asset *assetLabel;

So assetLabel is not a label at all, but an Asset object. Better naming can prevent this sort of problem.

The "<Asset: ox10010b510>" output you're seeing is from the implementation of the -(NSString *)description method from the NSObject class. When you use the format specifier "%@" in an NSLog or stringWithFormat: call, it calls the -(NSString *)description method and uses the string that's returned. So in your Asset class you would want to override -(NSString *)description to return something more meaningful, like the asset's label string.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.