Adding to NSDictionary in while loop - objective-c

I'm adding Annotations to a map, and in order to call them I need to store their Database ID value in an Dictionary
int i = 0;
...
while(sqlite3_step(statement) == SQLITE_ROW) {
int thisvenueid = sqlite3_column_int(statement, 4);
NSNumber *vid = [[NSNumber alloc] initWithInt:thisvenueid];
if (dict == nil) {
dict = [[NSMutableDictionary alloc] init];
}
[dict setObject:vid forKey:[NSNumber numberWithInt:i]];
}
And then I'm using it like this:
[self.mapView selectAnnotation:[dict objectForKey:selectedVenue] animated:YES];
However, this just crashes (Sigbart .. how I don't like Sigbart). I'm very thankful for any advise.

you are trying to select Annotation and passing NSNumber instead of object of MKPlacemark
please refer to documentation:
selectAnnotation:animated:
Selects the specified annotation and displays a callout view for it.
- (void)selectAnnotation:(id < MKAnnotation >)annotation animated:(BOOL)animated
Parameters
*annotation*
The annotation object to select.
animated
If YES, the callout view is animated into position.
Discussion
If the specified annotation is not onscreen, and therefore does not have an associated annotation view, this method has no effect.

Why are you using setObject? From what it looks like, you should be using addObject:
[dict addObject: vid forKey: [NSNumber numberWithInt:i]];
Forgive me if this is not the problem - haven't worked with Objective-C for some time.

Related

Getting valueForKey returns (null)

I am trying to put a value in a NSArray and receive it again later. Here is my code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[_system setValue:[_objects objectAtIndex:indexPath.row] forKey:#"selected"];
NSLog(#"%#", [_objects objectAtIndex:indexPath.row]);
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"%#", [_system valueForKey:#"selected"]);
}
Here is the log result:
2013-11-01 23:38:04.210 ClassPoints[187:60b] test
2013-11-01 23:38:04.211 ClassPoints[187:60b] (null)
What I find odd is even creating the array in the void doesn't properly load the value.
NSArray *testArray;
[testArray setValue:#"test" forKey:#"test"];
NSLog(#"%#", [testArray valueForKey:#"test"]);
Could anyone shed some light on this? I am completely lost. Thanks!
Make your NSArray an NSMutableArray so you can edit objects in it and in your viewDidLoad do not forget to initialize it.
-(void)viewDidLoad {
myMutableArray = [[NSMutableArray alloc] init];
}
Once an NSArray has been initialized, you won't be able to add/remove/edit objects on it. That is what an NSMutableArray is for.
First you need to use the mutable versions of the collection type you want to use, then you need to alloc and init them. Then unless your _system (NSArray?) contains objects that are key value coding compliant for "selected". setValue:forKey calls setValue:forKey on each of your arrays elements. The same applies for valueForKey:. Thats why your isolated example wont work either. I think you want a NSMutableDictionary then you can get/set objects through keys while arrays only works with indexes.
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setObject:yourObject forKey:yourKey];
id obj = [dictionary objectForKey:yourKey];
Try like this use NSMutableArray and for setting use setObject api inspite of setting setValue.
NSMutableArray *testArray = [NSMutableArray array];
[testArray setObject:#"test" forKey:#"test"];
NSLog(#"%#", [testArray objectForKey:#"test"]);

NSString, matchig name of an NSArray

I am new to Objective C coming from C# .NET, I have this scenario :
Assume I have 5 NSArrays corresponding to 5 UIButtons. the UIButtons have the exact same name
as the NSArray, so for example one UIButton is called mainScreen, and there is an NSArray called mainScreen.
Those Five buttons are linked to one IBAction where I do the following :
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSLog(category);
//Here I need to call the NSArray which has the same name as category
}
Now I can get the actual name of the UIButton, but how can I get the NSArray same as that title? without getting into a lot of if else or switch statements?
What I would do is store the arrays inside an NSDictionary. You can then set the 'key' as the name of your array and then the value would be the array itself.
That way you could say:
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSLog(category);
//Here I need to call the NSArray which has the same name as category
NSArray *theArray = (NSArray*)[self.myDictionary valueForKey:category];
}
Hope this helps!
The easiest way to associate names with objects is using an NSDictionary (or it's mutable subclass NSMutableDictionary). Dictionaries map a unique key to an object. Keys can be any object (that implements the NSCopying protocol), but are very often NSStrings
Have a look at the NSDictionary Reference and the Programming with Objective-C guide.
Note that if you use the button title this might break if you localise your app.
What you do is not the best way. You should provide tag for each button, say from 1 to 5. Also you should put your five arrays into one array. Now all you need is:
- (IBAction)btnClick:(id)sender
{
NSInteger index = [sender tag] - 1;
NSArray *array = [bigArray objectAtIndex:index];
}
That's it.
Assign different tags to all UIButtons and then access them explicitly using their tags.
- (IBAction)btnClick:(id)sender {
int tagIs = [(UIButton *)sender tag];
switch (tagIs) {
case 1:
// Access first button array
break;
case 2:
// Access second button array
break;
default:
break;
}
}
Or you can use AssociationObjects method for associating data with objects as following:
Firstly import :
#import <objc/runtime.h>
then create keys as :
static char * firstBtnKey = "firstBtnKey";
static char * secondBtnKey = "secondBtnKey";
-- - other keys same way ---
then use :
// Do any additional setup after loading the view, typically from a nib.
NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects:#"object1",#"object 2", nil];
objc_setAssociatedObject((UIButton *)[self.view viewWithTag:1],
firstBtnKey,
firstArray,
OBJC_ASSOCIATION_RETAIN);
NSMutableArray *secondArray = [[NSMutableArray alloc] initWithObjects:#"object1",#"object 2", nil];
objc_setAssociatedObject((UIButton *)[self.view viewWithTag:2],
secondBtnKey,
secondArray,
OBJC_ASSOCIATION_RETAIN);
`
and then access these arrays as :
- (IBAction)btnClick:(id)sender {
int tagIs = [(UIButton *)sender tag];
switch (tagIs) {
case 1:
// Access first button array
NSMutableArray *tempArr = (NSMutableArray *)objc_getAssociatedObject((UIButton *)sender, firstBtnKey);
break;
case 2:
// Access second button array
NSMutableArray *tempArr = (NSMutableArray *)objc_getAssociatedObject((UIButton *)sender, secondBtnKey);
break;
default:
break;
}
}
Hope it helps.
In most programming languages objects don't have names.[1] Just because UIButtons have the exact same name as the NSArray(mainScreen), doesn't mean that your object is "called" mainScreen.
Use NSDictionary , array as object and button title as key.
or use button tag
title1= [[NSArray alloc] initWithObjects:#"1",nil];
title2= [[NSArray alloc] initWithObjects:#"2",nil];
title3= [[NSArray alloc] initWithObjects:#"3",nil];
title4= [[NSArray alloc] initWithObjects:#"4",nil];
title5= [[NSArray alloc] initWithObjects:#"5",nil];
dict = [[NSDictionary alloc] initWithObjectsAndKeys:title1,#"title1",title2,#"title2",title3,#"title3",title4,#"title4",title5,#"title5",nil];
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSArray *arr = [dict objectForKey:category];
}

Add cell to UITableView

Can't handle simple problem - adding cells to UITableView.
I have single-view application, with added from Objects - Table View and simple NSArray (deseriliazed json from internet-grabbed data).
- (void) didLoadMusicList:(APIDownload *)request
{
NSLog(#"Music list loaded");
CJSONDeserializer *deserializer = [CJSONDeserializer new];
NSDictionary *dict = [deserializer deserializeAsDictionary:request.downloadData error:nil];
NSArray *response = [dict objectForKey:#"response"];
NSArray *audios = [response subarrayWithRange:NSMakeRange(1, response.count-1)];
for(int i = 0; i < audios.count; i++)
{
NSDictionary *audio = [audios objectAtIndex:i];
// add a cell?
}
}
So, how do I add cell for each element?
You need to implement the UITableViewDatasource on your view controller. You can use the same array to provide the data to the cells, and return them using the cellForRowAtIndexPath datasource method. You also need to provide with the count of cells on your tableView.
Check this documentation: http://developer.apple.com/library/ios/#documentation/uikit/reference/UITableViewDataSource_Protocol/Reference/Reference.html

NSArray crashes the app when accessing it

I have a problem with accessing/setting an object from/to a NSArray returned with the CFPreferencesCopyAppValue() method. My app crashes in this case whereas when I alloc/init it myself, everything works well.
CFArrayRef cfArray;
if ((cfArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("buttonsOrder"), appID))) {
NSArray *castedArray = [(NSArray *)cfArray retain];
NSLog(#"castedArray : %#", castedArray);
buttonsOrder = [castedArray mutableCopy];
NSLog(#"buttonsOrder : %#", buttonsOrder);
CFRelease(cfArray);
[castedArray release];
castedArray = nil;
}
else {
buttonsOrder = [[NSMutableArray alloc] init];
for (NSMutableDictionary *info in togglesInfo) {
[buttonsOrder addObject:[info objectForKey:#"buttonIdentifier"]];
}
}
PS : NSLog() shows me that CFArray is returned well and is casted to NSArray and then NSMutableArray well too.
Any idea ?
Edit :
Here is how I modofy the array :
- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
NSUInteger fromIndex = [fromIndexPath row];
NSUInteger toIndex = [toIndexPath row];
if (fromIndex == toIndex)
return;
NSString *movedButtonId = [[[buttonsOrder objectAtIndex:fromIndex] retain] autorelease];
[buttonsOrder removeObjectAtIndex:fromIndex];
[buttonsOrder insertObject:movedButtonId atIndex:toIndex];
}
If you crash while trying to add an object to a mutable array, that usually means you're attempting to add a nil object. The only place (in your code snippet above) where I see you adding anything to your mutable array is in the case where you didn't get a valid "cfArray" from CFPreferences. You should make sure "[info objectForKey:#"buttonIdentifier"]" isn't returning nil.
Check to make sure you're not throwing an exception. Or if that's not it, say what your crash really is (it'll say in the Console log of Xcode).

Three20 TTTableViewController reload data

How can I reload the data in the TTTableViewController? I tried to
call reloadData but it doesn't display the new data.
I have created the datasource file, which is a subclass of
TTListDataSource. Basically, the init function looks like this.
- (id) initWithObject:(NSArray *)objects {
if (self = [super init]) {
NSMutableArray *priceItems = [[[NSMutableArray alloc] init] autorelease];
for (int i = 0; i < [objects count]; i++) {
[priceItems addObject:
[PriceItem itemWithName:
[[objects objectAtIndex:i] objectAtIndex:0]
lastDone:[[objects objectAtIndex:i] objectAtIndex:1] change:[[objects objectAtIndex:i] objectAtIndex:2]]];
}
self.items = [NSArray arrayWithArray:priceItems];
}
return self; }
After the view is loaded, i start to streaming some data, thus the
objects passed to initWithObject is changed, so I call 'reload' in the
subclass of the TTTableViewController in order to update the data, but
the data is not updated. It doesn't work for refresh method too. Do I need to implement any other method in
the subclass of TTListDataSource?
Try
[self invalidateModel];
That should do the trick.
invalidateModel will rebuild the model, that's not efficient.
Try [TTTableViewController refresh], your table will be reloaded.