Need help with a conversion from SQLite data to Class Object

Discussion in 'Mac Programming' started by Anim, Jan 30, 2014.

  1. Anim macrumors 6502a

    Anim

    Joined:
    Dec 16, 2011
    Location:
    Macclesfield, UK
    #1
    Hey all

    I am pulling my hair out trying to work out how to convert a category list into a data model for a NSOutlineView.

    I am attempting to create a Source view / NSOutlineView to let a user select a product category. Just like a tree view. There are no Leaf nodes, just roots and branches.

    The user entered data is stored in an SQLite table as the following:

    Code:
    ID           PRODUCT         PARENTID
    1            FORD            0
    2            HONDA           0
    3            FIESTA          1
    4            XR2             3
    5            ESCORT          1
    6            CIVIC           2
    7            TURBO           6
    
    Three could be 20 or 1000 of these records, the user is allowed to add and delete them.

    So we can see there are 2 root nodes (Ford, Honda) and various branches and branches of branches (Turbo, XR2)

    So, for the data model I created a class to hold the data as in:
    Code:
    #import <Foundation/Foundation.h>
    
    @interface BP_category : NSObject
    
    @property (copy) NSString *categoryName;
    @property (readonly, copy) NSMutableArray *subCategory;
    
    -(id)initWithName:(NSString *)name;
    -(void)addChildCategory:(BP_category *)c;
    
    @end
    
    ------------------
    
    #import "BP_category.h"
    
    @implementation BP_category
    
    -(id)init {
        return [self initWithName:@"Untitled"];
    }
    
    -(id)initWithName:(NSString *)name {
        self = [super init];
        if (self) {
            _categoryName = [name copy];
            _subCategory  = [[NSMutableArray alloc]init];
        }
        
    return self;
    }
    
    -(void)addChildCategory:(BP_category *)c {
        [_subCategory addObject:c];
    }
    
    
    @end
    
    
    What I can't figure out is how to traverse the SQLite data and store it in the class object. I get muddled up when it comes to children of children.

    Any help would be much appreciated.

    I am also using FMDB as an SQLite wrapper.

    Many thanks
    Anim
     
  2. MasConejos macrumors regular

    MasConejos

    Joined:
    Jun 25, 2007
    Location:
    Houston, TX
    #2
    I can't help you with the cocoa syntax, but I can help from a general programming point of view.

    First you will need to add Id as a property of BP_Category

    Next you will need to do something like the following. Note that I dont know how sql access works in cocoa, I'm assuming (possible incorrectly) that it is vaguely similar to how .net works

    Code:
    -(NSMutableArray*) getCategoriesFromSql()
    {
    	//create MySQL connection
    	//Create Command object
    	//execute SQL query, get a MySqlReader
    	
    	//This list is a temporary list used for looking up parent categories
    	NSMutableArray* listCategories = [[NSMutableArray alloc] init];
    	
    	//This list is for holding the top level categories
    	NSMutableArray* listTopeLevelCategories = [[NSMutableArray alloc] init];
    	
    	while(reader.read())
    	{
    		int id = reader["ID"];
    		NSString* product = reader["Product"];
    		int parentId = reader["ParentID"];
    		
    		//create object for current record
    		BP_category* newCategory = [[BP_Category alloc]initWithName:product withId:id]
    		
    		//search to see if parent exists
    		BP_category* parentCategory = nil;
    		foreach(BP_category* category in listCategories)
    		{
    			if(cat.id == parentId)
    			{
    				parentCategory = cat;
    				break;
    			}
    		}
    		
    		//if a parent was found, add the new category as a child
    		//otherwise, add it to the top level list
    		if(parentCategory)
    		{
    			[parentCategory addChildCategory:newCategory];
    		}
    		else
    		{
    			[listTopeLevelCategories addObject:newCategory];
    		}
    		
    		//add the new category to our lookup list
    		[listCategories addObject:newCategory];
    	}
    	
    	return listTopeLevelCategories;
    }
    
     
  3. Anim thread starter macrumors 6502a

    Anim

    Joined:
    Dec 16, 2011
    Location:
    Macclesfield, UK
    #3
    Interesting, thanks. I will convert that and see how it functions. My issue was when adding a child of a child of a root to the array and where i get confused if there are say 10 child records of a particular root object. I knew I needed a loop within a loop to locate child categories but it was the storing of each parent and accessing a parent (so I can add a child to it) later in the record set.

    But, I will take a look at this and see how it works.

    Thanks again
    Anim
     
  4. Anim thread starter macrumors 6502a

    Anim

    Joined:
    Dec 16, 2011
    Location:
    Macclesfield, UK
    #4
    Another possible solution I found earlier was to use Cocoa bindings and an NSDictionary object which works well with NSOutlineView's and a NSTreeController for managing it.

    As shown here: http://daemonconstruction.blogspot.co.uk/2012/03/simplest-nstreecontroller-example.html

    I can then just work with a Dictionary object.

    I will try both methods and time them on 1000 records to see which is faster, an array of class objects vs a Dictionary for the data model.

    Cheers
    Anim
     
  5. MasConejos macrumors regular

    MasConejos

    Joined:
    Jun 25, 2007
    Location:
    Houston, TX
    #5
    Mine isn't super optimized. For the lookup list you'd be better off using a dictionary or some other container to look up the categories directly by Id, rather than looping through the entire list trying to find it.

    Good luck, either way.
     
  6. Mac_Max macrumors 6502

    Joined:
    Mar 8, 2004
    #6
    When I'm prototyping schemas I'll create wrapper classes around NSDictionaries and convert them into a proper implementation once my schema is set. Maybe it's my C#/Perl background coming out but it also lends itself to emulating C#'s named parameters/Perl object constructors.

    I.e.

    Code:
    MyClass *obj = [[MyClass alloc] initWithDictionary:@{
                              @"name"     : someVar1, 
                              @"tag"         : someVar1, 
                              @"location"  : someVar1, 
                              @"time"       : someVar1, 
                           }];
    
     
  7. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #7
    Erk. I think it was Ben Franklin who said:
    "He who would give up compile-time type safety and requiredness for convenience deserves neither."

    -Lee
     
  8. Mac_Max macrumors 6502

    Joined:
    Mar 8, 2004
    #8
    He also came up with Daylight Savings Time. Not all of his ideas were good in the long run ;).

    The key word there is "prototyping". Having a class to search for is a lot nicer than grepping for "theNameOfSomeRandomDictionaryImKillingMySelfOver".

    After I'm done prototyping the class can easily turn into

    Code:
    [[MyClass alloc] initWithName: someVar1
                              tag: someVar2, 
                              location: someVar3];
    
     

Share This Page