How can I add and store data in a UITableView? - xcode

I'm creating an app that inserts values to a tableview. I also want to add the timestamp on when the value is added to the table. The scenario would be this:
I write some random text in a text field.
I push a button
The text from the text field is saved in the table together with the time I tapped the button.
Done.

(NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
(void)applicationWillTerminate:(NSNotification *)notification {
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:field1.text];
[array addObject:field2.text];
[array addObject:field3.text];
[array addObject:field4.text];
[array writeToFile:[self dataFilePath] atomically:YES];
[array release];
}

Depending on how large your data is, you can store it in a plist, or sqlite3.
Here's a link that might be useful:
http://www.bogotobogo.com/XcodeSDK-Chapter10.html

Related

NSManagedObject : having one answer of a loop instead of multiple answer from a loop Xcode

i have a problem when creating a txt file from a for statement. Here is the code of the statement on a CoreData.
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest * allTickets = [[NSFetchRequest alloc] init];
[allTickets setEntity:[NSEntityDescription entityForName:#"Place" inManagedObjectContext:context]];
[allTickets setIncludesPropertyValues:NO];
NSError * error = nil;
NSArray * ticks = [context executeFetchRequest:allTickets error:&error];
for (NSManagedObject * tick in ticks) {
NSArray *keys = [[[tick entity] attributesByName] allKeys];
NSDictionary *myDict = [tick dictionaryWithValuesForKeys:keys];
NSString *theDate = [myDict objectForKey:#"date"];
NSString *theName = [myDict objectForKey:#"name"];
NSString *theNumber = [myDict objectForKey:#"number"];
NSString * finalExport = [NSString stringWithFormat:#"%#%#%#", theDate, theName, theNumber];
NSLog(#"%#",finalExport);
the NSLog result print out all the entries in CoreData correctly, running each request one after the other.
My problem is that when i want to create a txt with the finalExport NSString, i only have the first request in the file.
For exemple i got an NSLog with :
01.01.2015 MYNAME 34555445
02.01.2015 MYNAME 34523445
03.01.2015 MYNAME 34115445
04.01.2015 MYNAME 34552345
But in the text file i only got
01.01.2015 MYNAME 34555445
So how can i have a text file with all the NSLog Results
Thanks in advance for your help ;)
EDIT ++++++++++++++
Here is the rest of the code :
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
NSError *error;
BOOL succeed = [finalExport writeToFile:[documentsDirectory stringByAppendingPathComponent:#"Number.txt"]
atomically:YES encoding:NSUTF8StringEncoding error:&error];
if (!succeed){
NSLog(#"NOT WORKING");
}
You need to make sure you write an array of entries to the file, not just one entry.

Saving NSMutableArray and loading it in a UITableView

I want to save multiple NSMutableArray and load it because this array gets it content from a server and i don't want to reload that data every time the app is opened.
First I declared the paths:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *firstPath = [documentsDirectory stringByAppendingPathComponent:#"first"];
NSString *secondPath = [documentsDirectory stringByAppendingPathComponent:#"second"];
NSString *thirdPath = [documentsDirectory stringByAppendingPathComponent:#"third"];
NSString *fourthPath = [documentsDirectory stringByAppendingPathComponent:#"fourth"];
then save the NSMutableArrays:
[firstArray writeToFile:firstPath atomically:YES];
[secondArray writeToFile:secondPath atomically:YES];
[thirdArray writeToFile:thirdPath atomically:YES];
[fourthArray writeToFile: fourthPath atomically:YES];
then open these files in other NSMutableArrays:
firstArrayget = [NSMutableArray arrayWithContentsOfFile:firstPath];
secondArrayget = [NSMutableArray arrayWithContentsOfFile:secondPath];
thirdArrayget = [NSMutableArray arrayWithContentsOfFile:thirdPath];
fourthArrayget = [NSMutableArray arrayWithContentsOfFile:fourthPath];
then I try to load these Arrays (...Arrayget i.e. firstArrayget) into a TableView.
The data gets loaded into the TableView, but when I scroll down the App crashes with the Error:
*** -[CFArray objectAtIndex:]: message sent to deallocated instance 0x930fc80
and in the file:
Thread 1:EXC_BREAKPOINT(code=EXC_1386_BPT,subcode=0x0)
but if I say the TableView to load the data from the (...Array i.e. firstArray),so the data downloaded from the server unsaved.
Assuming you're using MRC and not ARC:
Looks like you're setting an ivar to an autoreleased NSMutableArray.
Try calling retainon the NSMutableArrays, otherwise your NSMutableArrays will just get released and thus deallocated when the autoreleasepool drains.
Another solution is to use a property for each of your NSMutableArrays like this:
// Create a property in your header file
#property (retain) NSMutableArray *firstArrayget;
// And set the property in your method
[self setFirstArrayGet:[NSMutableArray arrayWithContentsOfFile:firstPath]];
You can find more about Objective-C memory management at https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

Xcode: Remove objects from NSMutableArray based on NSDictionary

I am new to tableViews and dictionaries and i have a problem!
In ViewDidLoad i am initializing many MutableArrays and i am adding data using NSDictionary. Example:
- (void)viewDidLoad {
nomosXiou=[[NSMutableArray alloc] init];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Mary",#"name",#"USA",#"country", nil]];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Peter",#"name",#"Germany",#"country", nil]];
[super viewDidLoad];
// Do any additional setup after loading the view.}
In a previous ViewController the user selects a Country. Based on that selection, how could i remove from my arrays all the other entries???
Thanks in advance...
First note that your code fragment has an error. It should read:
NSMutableArray *nomosXiou= [[NSMutableArray alloc] init];
There are a number of ways to do what you want, but the most straightforward is probably the following:
NSString *countryName; // You picked this in another view controller
NSMutableArray *newNomosXiou= [[NSMutableArray alloc] init];
for (NSDictionary *entry in nomosXiou) {
if ([[entry objectForKey:#"country"] isEqualToString:countryName])
[newNomosXiou addObject:entry];
}
When this is done newNomosXiou will contain only the entries in nomosXiou that are from the country set in countryName.
Something like this will do the job:
NSMutableArray *nomosXiou = [[NSMutableArray alloc] init];
NSString *country = #"Germany"; // This is what you got from previous controller
// Some test data. Here we will eventually keep only countries == Germany
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Mary",#"name",#"USA",#"country", nil]];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"Peter",#"name",#"Germany",#"country", nil]];
[nomosXiou addObject:[[NSDictionary alloc] initWithObjectsAndKeys:#"George",#"name",#"Germany",#"country", nil]];
// Here we'll keep track of all the objects passing our test
// i.e. they are not equal to our 'country' string
NSIndexSet *indexset = [nomosXiou indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop){
return (BOOL)![[obj valueForKey:#"country"] isEqualToString:country];
}];
// Finally we remove the objects from our array
[nomosXiou removeObjectsAtIndexes:indexset];

Querying with spotlight

I'm working on a tiny project for LEOPARD (10.5) and I'm kinda rookie with Objective-C programming. I've been searching for some tutorials on internet but I'm still confused! I need to use Leopard's spotlight feature to search for every .app file installed at the user's computer. I also need its name, path and icon. All queried data must be saved in a text file. How can I do that???
Thank you!
Define the query, and observe the query termination.
- (void)searchApplications {
NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
query.predicate = [NSPredicate predicateWithFormat:#"kMDItemContentTypeTree == 'com.apple.application'"];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(queryDidFinish:)
name:NSMetadataQueryDidFinishGatheringNotification
object:query];
[query startQuery];
}
In the query termination function, loop through the results and extract the data you want.
- (void)queryDidFinish:(NSNotification *)notification {
NSMetadataQuery *query = (NSMetadataQuery *)[notification object];
[query stopQuery];
NSMutableArray *paths = [NSMutableArray array];
for(NSMetadataItem *mdItem in query.results) {
NSString *name = [mdItem valueForAttribute:(NSString *)kMDItemDisplayName];
NSString *path = [mdItem valueForAttribute:(NSString *)kMDItemPath];
NSImage *icon = [[NSWorkspace sharedWorkspace] iconForFile:path];
[paths addObject:path];
}
[query release];
[paths writeToFile:#"/tmp/applications.txt" atomically:YES];
}

Memory problems with NSMutableDictionary, causing NSCFDictionary memory leaks

Help me please with the following problem:
- (NSDictionary *)getGamesList
{
NSMutableDictionary *gamesDictionary = [[NSMutableDictionary dictionary] retain];
// I was trying to change this on the commented code below, but did have no effect
// NSMutableDictionary *gamesDictionary = [[NSMutableDictionary alloc] init];
// [gamesDictionary retain];
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *key = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
NSArray *gameDate = [key componentsSeparatedByString:#" "];
NSNumber *_id = [[NSNumber alloc] initWithInt:sqlite3_column_int(statement, 0)];
NSString *date_time = [NSString stringWithFormat:#"%#, %#",[gameDate objectAtIndex:0],[gameDate objectAtIndex:2]];
if (![gamesDictionary valueForKey:date_time]) [gamesDictionary setValue:[NSMutableArray array] forKey:date_time];
[[gamesDictionary valueForKey:date_time] addObject:[[_id copy] autorelease]];
[_id release];
}
sqlite3_reset(statement);
return gamesDictionary;
}
The leak starts in another method of another class, there the getGamesList method is called, like this:
NSMutableDictionary *gamesDictionary;
gamesDictionary = [[NSMutableDictionary dictionaryWithDictionary:[appDelegate getGamesList]] retain];
After that there are a lot of leaks that points to NSCFArray in the string:
NSArray *keys = [[NSArray arrayWithArray:[gamesDictionary allKeys]] retain];
in this method:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSArray *keys = [[NSArray arrayWithArray:[gamesDictionary allKeys]] retain];
if ([keys count] != 0) return [[keys objectAtIndex:section] uppercaseString];
return #"";
}
I assume these things are connected to each other, but I still can not understand all of the memory management tips.
Thanks a lot!
Didn't use Cocoa for years (that's why I can't tell you an exact answer :/). But I guess your problem is that you systematically use retain on your objects.
Since the object reference count never get to 0, all dictionaries are keep in memory and not freed.
Try to remove the retain on [NSArray arrayWithArray] and [NSMutableDictionary dictionaryWithDictionary
http://en.wikibooks.org/wiki/Programming_Mac_OS_X_with_Cocoa_for_beginners/Some_Cocoa_essential_principles#Retain_and_Release
It does look like you are over-retaining your array.
When you create the gamesDictionary it is created with an retain count of +1. You then retain it (count becomes +2). When you get the value outside this function you retain again (count becomes +3).
You are correct that if you create an object you are responsible for it's memory management. Also, when you get an object from a method, you should retain it if you want to keep it around for longer than the span of the function. In your case, you just want to get at some of the properties of the object, so you don't need to retain it.
Here is a suggestion:
- (NSDictionary *)getGamesList
{
NSMutableDictionary *gamesDictionary = [NSMutableDictionary dictionary]; // Remove the retain.
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *key = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 1)];
NSArray *gameDate = [key componentsSeparatedByString:#" "];
NSNumber *_id = [[NSNumber alloc] initWithInt:sqlite3_column_int(statement, 0)];
NSString *date_time = [NSString stringWithFormat:#"%#, %#",[gameDate objectAtIndex:0],[gameDate objectAtIndex:2]];
if (![gamesDictionary valueForKey:date_time]) [gamesDictionary setValue:[NSMutableArray array] forKey:date_time];
[[gamesDictionary valueForKey:date_time] addObject:[[_id copy] autorelease]];
[_id release];
}
sqlite3_reset(statement);
return gamesDictionary;
}
This next bit is messy. you create a new dictionary and retain it. The original dictionary is not autoreleased, so the count isn't decremented and it always hangs around. Just assign the dictionary rather than create a new one.
NSMutableDictionary *gamesDictionary = [[appDelegate getGamesList] retain];
// Retaining it, becuase it looks like it's used elsewhere.
Now, in this method:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString *returnString;
// Don't need to retain the keys because you are only using it within the function
// and since you didn't alloc, copy or retain the array it contains, you aren't responsible for it's memory management.
NSArray *keys = [NSArray arrayWithArray:[gamesDictionary allKeys]];
if ([keys count] != 0) {
returnString = [[NSString alloc] initWithString:[[keys objectAtIndex:section] uppercaseString]];
return [returnString autorelease];
}
return #"";
}

Resources