Assigning instances from difference classes to Array

Discussion in 'iOS Programming' started by childoftheko4n, Jul 21, 2013.

  1. childoftheko4n, Jul 21, 2013
    Last edited by a moderator: Jul 21, 2013

    childoftheko4n macrumors regular

    Joined:
    Oct 18, 2011
    #1
    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)
     
  2. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
  3. Tander macrumors 6502a

    Tander

    Joined:
    Oct 21, 2011
    Location:
    Johannesburg, South Africa
    #3
    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?
     
  4. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #4
    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.

    ----------

    How exactly would you go about setting that property and creating that relationship, if you were to write it in the most basic form?
     
  5. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #5
    Code:
    @property Asset *asset;
     
  6. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #6
    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.
     
  7. Sonnestah macrumors regular

    Joined:
    Mar 2, 2013
    #7
    Yes, it is assigning #3 to #3.

    What issue are you having when printing results?
     
  8. MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #8
    Have you covered -description methods as yet?

    They might be helpful in this instance.
     
  9. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #9
    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
     
  10. Sonnestah macrumors regular

    Joined:
    Mar 2, 2013
    #10
    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?
     
  11. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #11
    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)
     
  12. Sonnestah macrumors regular

    Joined:
    Mar 2, 2013
    #12
    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];
                
            }
     
  13. hollersoft macrumors member

    Joined:
    Feb 10, 2013
    #13
    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.
     
  14. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #14
    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 :)
     
  15. Sonnestah macrumors regular

    Joined:
    Mar 2, 2013
    #15
    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]
            }
     
  16. hollersoft macrumors member

    Joined:
    Feb 10, 2013
    #16
    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.
     
  17. Sonnestah macrumors regular

    Joined:
    Mar 2, 2013
    #17
    Couldn't have said any better
     
  18. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #18
    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
     
  19. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #19
    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
     
  20. Sonnestah macrumors regular

    Joined:
    Mar 2, 2013
    #20
    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.
     
  21. MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #21
    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]);
    
     
  22. hollersoft macrumors member

    Joined:
    Feb 10, 2013
    #22
    The answer to that is in my second paragraph (also suggested by ArtOfWarfare earlier in the thread).

    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.
     
  23. childoftheko4n, Jul 24, 2013
    Last edited: Jul 24, 2013

    childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #23
    **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>
     
  24. childoftheko4n thread starter macrumors regular

    Joined:
    Oct 18, 2011
    #24
    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 :)
     
  25. hollersoft macrumors member

    Joined:
    Feb 10, 2013
    #25
    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.
     

Share This Page