How to story multiple values for one object in NSMutableDictionary? - ios

I would like to story many items in one object (the name of the user, their photo, and the time the photo was taken). I have tried to use three different arrays to do this and it somewhat works, however since I am loading this into a tableview its not the best way to do this. I am thinking about using a NSMutableDictionary but I can't seem to do it. Any help would be appreciated!

You can do like this.
NSDictionary *dic = [[NSDictionary alloc]initWithObjectsAndKeys:
#"Jone",#"UserName",
#"Jone.png",#"Photo",
[NSDate date],#"Time",nil];
NSMutableArray *userArray = [[NSMutableArray alloc] init];
[userArray addObject:dic];
//NSLog(#"%#",userArray);
for (int i=0; i<userArray.count; i++) {
NSDictionary *userDictionary = [userArray objectAtIndex:i];
NSLog(#"UserName:%#",[userDictionary valueForKey:#"UserName"]);
NSLog(#"Photo:%#",[userDictionary valueForKey:#"Photo"]);
NSLog(#"Time:%#",[userDictionary valueForKey:#"Time"]);
}
Note:I think you need to use "NSMutableArray" of NSDictionary. if you all user property (username,photo,time...) are unpredictable the only you need to use NSMutableDictionary.

What you want to do is create a User Entity (Swift/Objective-C Class) with username, photo and photoTime fields.
Create the users, put drop them in an array and then read from it while you are creating the table in cellForRowAtIndexPath.
#interface User : NSObject
#property (nonatomic, retain) NSString *userName;
#property (nonatomic, retain) NSString *photoURL;
#property (nonatomic, retain) NSString *photoTime;
#end
Then somewhere within your code where you create users...
NSMutableArray *usersArray= [[NSMutableArray alloc] init];
User *user= [[Useralloc] init];
user.userName=#"someUserName"
user.photoURL=#"http://somephotourl.com";
user.photoTime=#"1231232132121";
[usersArray addObject:user];

The data structure behind a UITableView is usually NSArray or a list of some kind. Each object in the array should represent a row in the table.
Following this pattern your structure should look like that:
var users = [User]()
struct User {
let name: String
let photo: UIImage
let date: NSDate
}
// This struct could also be a dictionary
var user = [String: AnyObject]()
user["name"] = ..
user["photo"] = ..
user["date"] = ...
Instantiate User objects and add them to the users array when appropriate.
Your UITableView should find the correct user and update the cell accordingly in the dataSource method:
func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = .. // Dequeue cell
let user = users[indexPath.row] // Get the user for this row
cell.textLabel.title = user.name // Update cell properties
// etc..
// OR using a dictionary
cell.textLabel.title = user["name"]
// etc..
return cell

Related

iOS - JSONModel with dynamic key

I am calling a web service which returns dictionary to render the graph. Dictionary structure is
{"1":0,"2":0,"8":0,"9":2,"10":3,"11":0,"12":0}
The problem is keys are dynamic values like 1,2,3 etc which indicates month. Is it possible to represent this in JsonModel?
See you cant create properties at run time as per response structure. But we can smartly use pre-defined things and achieve this. Do following steps:
Create one model class. So your MyCustomModel.h file will look like this
#import <Foundation/Foundation.h>
#interface MyCustomModel : NSObject
#property (nonatomic, retain) NSString * myCustomKey;
#property (nonatomic, retain) NSString * myCustomValue;
#end
This will be your MyCustomModel.m file
#import "MyCustomModel.h"
#implementation MyCustomModel
#synthesize myCustomKey, myCustomValue;
-(id)init {
self = [super init];
myCustomKey = #"";
myCustomValue = #"";
return self;
}
#end
Now lets suppose {"1":0,"2":0,"8":0,"9":2,"10":3,"11":0,"12":0} is NSDictionary and lets say its name is dictionaryResponse
Now do this stuffs:
NSArray *responseKeys = [[NSArray alloc]init];
responseKeys = [dictionaryResponse allKeys];
So your responseKeys will have all keys of response like ["1","2","8","9","10","11","12",]
Now you can iterate loop and create NSMutableArray of model objects as
NSMutableArray *arrayMonthList = [[NSMutableArray alloc]init];
for (int i = 0; i < responseKeys.count; i++) {
MyCustomModel *myModelObject = [[MyCustomModel alloc]init];
myModelObject.myCustomKey = [NSString stringWithFormat:#"%#",[responseKeys objectAtIndex:i]];
myModelObject.myCustomValue = [dictionaryResponse valueForKey:[NSString stringWithFormat:#"%#",[responseKeys objectAtIndex:i]]];
[arrayMonthList addObject:myModelObject];
}
Now arrayMonthList will consist of objects of type MyCustomModel
So you can use it and parse it. Even you can use it to show on UITableView. Following code is written to print values of model properties, you can customise at your expected level.
for (int i = 0; i < arrayMonthList.count; i++) {
MyCustomModel *myModelObject = [arrayMonthList objectAtIndex:i];
NSLog(#"Month is %# and its value is %#",myModelObject.myCustomKey,myModelObject.myCustomValue);
}

Objective C property passed reset to null after use

In my root view controller (named rootViewController.h) I have a property
#property (nonatomic, strong) NSDictionary *contactList;
Im trying to store value in this dictionary. Im passing the property to my function
AddContact *addContact = [[AddContact alloc]init];
NSString *result = #"";
result = [addContact addContact:user :[self contactList]];
When I go to my AddContact Function and breakpoint, the contactList is null even though I added 5x on the contactList using this code.
User *newUser = [[User alloc]init];
newUser.name = user.name;
newUser.phoneNumber = user.phoneNumber;
newUser.companyName = user.companyName;
[contactList setValue:newUser forKey:newUser.name];
Help
Try to use NSMutableDictionary, if you want to change it. NSDictionary can't be edited after initialization.
If you want to change your dictionary you need to create is as mutable like
#property (nonatomic, strong) NSMutableDictionary *contactList;
as per rule if you are using Mutable objects you need to alloc ,init it
so in view's didLoad method
_contactList = [[NSMutableDictionary alloc] init] ;
You have to initialise contactList. You have not initialise contactList and so the value is not set. And you can use mutable dictionary if you want to change values later on. Please make sure the values being added to contactList are not null else they will not be added to contactList and so dictionary will not have any objects in it.

How to Sort object by alphabet order for UITableViewCell?

I want to sort objects that i created & stored in NSMutableArray in AppDelegate.m.
Stations is NSObject Class
I want to show station names in another UIViewController in alphabet order(in UITableViewCell) & when i click on them i want to pass the object that contains station name,latitude,longitude to next UIViewController
Currently i have extracted station name from stationList(Global NSMutableArray) to another NSMutableArray on UIViewControllers Cell & sorted it via
[sortedArray sortUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
but when didSelectRowAtIndexPath is being called i have to get this name from cell & search it in the stationList array to pass lat,long which is not good i think.
stationList Array Log(It has 100 objects):-
<__NSArrayM 0x79a2f110>(
<Stations: 0x78743540>,
<Stations: 0x78743630>,
<Stations: 0x78743670>,
<Stations: 0x78743750>,
<Stations: 0x78743830>,
<Stations: 0x78743910>,
<Stations: 0x78743a10>,
<Stations: 0x78743af0>
}
-(void)loadStations
{
stationList = [[NSMutableArray alloc]init];
NSString *path = [[NSBundle mainBundle] pathForResource:#"stations" ofType:#"txt"];
NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
// NSLog(#"%#",content);
NSArray *tempArr = [content componentsSeparatedByString:#"\n"];
for (int i =0; i<[tempArr count]; i++)
{
NSString *rawData = [tempArr objectAtIndex:i];
if (rawData !=nil)
{
Stations *newStation = [[Stations alloc]init];
NSArray *data = [rawData componentsSeparatedByString:#"\t"];
newStation.sId = i+1;
newStation.name = [NSString stringWithFormat:#"%#",[data objectAtIndex:0]];
newStation.latitude = [[data objectAtIndex:1] doubleValue];
newStation.longitude = [[data objectAtIndex:2] doubleValue];
[stationList addObject:newStation];
}
}
}
Suggest me good practice/way for this, or maybe use Dictionary?
I see two solutions here:
1) you can retrieve object from your stationList based on indexPath.row
- (void) tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
Stations* station = stationsList[indexPath.row];
...
}
2) you can create custom UITableViewCell and store referenced object there:
#interface StationCell : UITableVIewCell
#property(weak) Stations* station;
#end
...
- (UITableViewCell*) tableView:(UITableVIew*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
StationCell* cell;
// dequeue StationCell
...
cell.station = stationList[indexPath.row];
}
...
- (void) tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
StationCell* cell = [tableView cellAtIndexPath:indexPath];
Stations* station = cell.station;
...
}
I would choose between solutions based on complexity of data displayed in cell - using custom UITableViewCell gives oportunity to move configuration of cell from view controller to cell implementation.
edit
As far as sorting stationsList, you can use e.g.:
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES];
stationsList = [stationsList sortedArrayUsingDescriptors:#[sort]];
I would advise against sorting an array of station names separate from your array stationList. Instead I would suggest sorting your stationList (or a copy of it if you only want to change the oder in the table view and need to maintain some other ordering elsewhere)
There are methods like sortUsingComparator: that takes comparator block as a parameter. You write a block that compares 2 elements in your array, and the method uses that block to figure out the ordering of your objects and sort the array. In your case it would simply be a matter of writing a block that compares the name properties of 2 station objects.

NSMutableArray not printing correct data - iOS/Objective C

I'm struggling to get my array to print the correct data.
I've got it linked to a button, so it gets the textfield data and adds it to a Person class which has a subclass called PhoneBookEntry which contains firstName, and then adds it to an NSMutableArray called entries. here's the button code:
PhonebookEntry *person = [[PhonebookEntry alloc] init];
self.firstName.text = person.firstName;
[self.entries addObject:person];
NSLog(#"%#", self.entries);
Here's the start where I initialise everything:
#interface ViewController ()
#property (nonatomic, strong) PhonebookEntry *person;
#property (nonatomic, strong) NSMutableArray *entries;
#end
in my viewDidLoad, this is the code to create the NSArray.
self.entries = [NSMutableArray arrayWithCapacity:1];
I've tested and it works fine when adding normally and prints etc, just not with the array.
Thanks
The output
test,
test2,
"<PhonebookEntry: 0x8c69770>"
It is printing correctly.
Actually you want something more from your code or Objective-C.
For this you need to override description in PhonebookEntry class to break to the level where NSLog can print. NSLog can't print person object values.
-(NSString *)description{
return [NSString stringWithFormat:#"%# , %#", self.firstName, self.lastName];
}
This self.firstName.text = person.firstName; should be the other way around, so change it to this:
person.firstName = self.firstName.text;

NSMutableArray removeObjectAtIndex causing unexpected SIGABRT

I have looked at numerous posts which state various ways in which to remove an object from an array correctly, but I am not sure which method is best to use in my instance. I am loading a dictionary from a plist, this dictionary contains numerous arrays, and these arrays contain another dictionary. So I have 3 storage devices setup, 1 to hold the overall dictionary, another for an array, and finally a dictionary to hold the object from the array:
Header:
NSMutableDictionary *questionsDictionary;
NSMutableArray *questionsArray;
NSDictionary *currentQuestion;
#property (nonatomic, retain) NSMutableDictionary *questionsDictionary;
#property (nonatomic, retain) NSMutableArray *questionsArray;
#property (nonatomic, retain) NSDictionary *currentQuestion;
So my first question is to do with the above, are (nonatomic, retain) the right things to use for the following code.
Next I load in my dictionary from the plist:
.m:
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"MultipleChoice.plist"];
self.questionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:finalPath] retain];
I then setup my question array based upon type based upon my question type:
- (void)setupQuestionType : (NSString *)qType
{
if ([self.questionsDictionary objectForKey:qType])
{
self.questionsArray = [self.questionsDictionary objectForKey:qType];
[self pickRandomQuestion];
}
}
Finally (this is where I get the error), I want to grab the a question at random from this question category:
// Pick a random question number based upon amount of questions
int randomQuestionNum = [[NSNumber numberWithInt:(arc4random() % [self.questionsArray count])] intValue];
// Grab the dictionary entry for that question
currentQuestion = [self.questionsArray objectAtIndex:randomQuestionNum];
// Remove the question from the available questions
[self.questionsArray removeObjectAtIndex:randomQuestionNum]; (Error here)
// Set the question text
self.question.text = [currentQuestion objectForKey:kQuestionkey];
Now if I comment out the removeObjectAtIndex line then the code runs fine, and my question is displayed on the screen. This leads me to believe that it isn't a null pointer. So the logical answer points to the fact that self.questionsArray isn't a NSMutableArray. So I tried the following when setting the array:
- (void)setupQuestionType : (NSString *)qType
{
if ([self.questionsDictionary objectForKey:qType])
{
NSMutableArray *temp = (NSMutableArray *)[self.questionsDictionary objectForKey:qType];
self.questionsArray = (NSMutableArray *)temp;
[self pickRandomQuestion];
}
}
Purely to see if I could type_cast it but the error still occurs. Can anyone shed some light on what I'm doing wrong, or the best approach to take?
Don't typecast NSArray to NSMutableArray. Instead:
NSArray *temp = [self.questionsDictionary objectForKey:qType];
self.questionsArray = [NSMutableArray arrayWithArray:temp];
// code not tested.

Resources