Search code examples
iosobjective-csqlitefmdb

Line breaks using FMDB and Obj-C


I'm relatively new to iOS programming, so please bear with me.

I'm creating an app that calls recipes from a table view, then listing the measurements and ingredients as labels in the detail view. I catalogued my recipes in Google Sheets, downloaded it as a .csv file and populated a table using SQLiteStudio. I then exported the database, and using FMDB, plopped it in my app. Everything works fine there and I'm able to retrieve various fields.

What I'm trying to do is list out the measurements and ingredients so that it displays with line breaks:

0.5 oz. 1.0 oz. 1 jigger

And not as: 0.5 oz., 1.0 oz., 1 jigger which is how I wrote it into the Google doc.

I've tried using \n in the SQLite viewer but it outputs it as a String rather than encoding it as a new line. However, when I view the accompanying .sql file, TextMate2 reads it as new lines. I'm not sure if I have to apply some code within my tableviewcontroller implementation file where I call the FMDB or elsewhere.

I have been looking for a solution for awhile now but no luck. Any help in steering me in the right direction would be greatly appreciated. Thanks!

CocktailListTableViewController.m

- (NSMutableArray *)recipeCocktails {
recipeCocktails = [[NSMutableArray alloc] init];

NSString *databasePath = [(AppDelegate *) [[UIApplication sharedApplication] delegate] databasePath];

FMDatabase *fmDB = [FMDatabase databaseWithPath:databasePath];

if(![fmDB open])
{
    NSLog(@"Could not open DB, try again");
    return nil;
}

FMResultSet *results = nil;
results = [fmDB executeQuery:@"SELECT * FROM recipesCocktails"];
NSLog(@"result %@ ",results);
if ([fmDB hadError]) {
    NSLog(@"DB Error %d: %@", [fmDB lastErrorCode], [fmDB lastErrorMessage]);
}
while ([results next]) {
    Cocktails *cocktails = [[Cocktails alloc] init];
    cocktails.recipeName = [results stringForColumn:@"recipeName"];
    cocktails.recipeMeasure = [results stringForColumn:@"recipeMeasure"];
    cocktails.recipeIngred = [results stringForColumn:@"recipeIngred"];
    cocktails.recipeGlass = [results stringForColumn:@"recipeGlass"];
    cocktails.recipeShaker = [results stringForColumn:@"recipeShaker"];
    cocktails.recipeDirections = [results stringForColumn:@"recipeDirections"];

    [recipeCocktails addObject:cocktails];
}

[fmDB close];

return recipeCocktails;

CocktailsDetailTableViewController.m

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.title = cocktails.recipeName;
self.recipeIngred.text = cocktails.recipeIngred;
self.recipeMeasure.text = cocktails.recipeMeasure;

Solution

  • I can see you're trying to store all the ingredients as one long, pre-built string, and I think that approach is not the best.

    It's gonna work, but it's not future-friendly or simply... usual.

    I strongly suggest having a new table that knows all the possible ingredients, with ID's and other informations of your will (color, average weight, picture* and whatnot)

    ( please note that it's not advised to store images in a SQL database and you'd rather store references to where you saved them as files or URL's)*

    Once you have that table, you're golden. You simply reference an array of ingredients in your recipe table. For example [1,27,133], and with that you can do what you want. You have an array of ingredient objects, which you can treat how you see fit.

    I would, for example, loop over it and create labels under each other and you'd have your lines. I could also simply use an NSMutableString and fill it with the ingredients.name (again, using examples) You could fill a UITextView with newlines between each ingredient (by using the NSMutableString and adding newlines between each object name).

    And more importantly, you can modify everything without having to re-work your layouts or labels or re-write your whole database because you have static newlines ingredients for each recipe.

    That is the most important point I wanted to make. With that approach you can remove any ingredient from any recipe without having to think really far or risk forgetting something. You could also permanently destroy any ingredient to every recipe by removing it from the ingredient table. Same for adding new ones. Or saying you want to change the name of ingredient X, you dont' have to do it in every recipe, and so on.

    EDIT: Answering your question in comment

    To load the recipes in the tableview and the ingredients on the detail page, you can do it like so :

    • You load all your recipes in an array and display that (I think you're successful already on that part). Note that all the recipes have a property called "Ingredients" which is an array of ingredient keys/ids/something

    • On cell tap, you want to load the ingredients that you only know the ID of, you simply get them from the array of Id's that you stored in your recipe, and SELECT them from your db.

    Globally, you have no idea what the ingredients are until the user taps : if you don't need to display them in the table view, then you don't need to laod them yet. But you already know their id (otherwise you wouldn't be able to find them!).