using dictionary as model - ios

I have created a small app with several views. For this I use the storyboard and for each view a viewcontroller. Now, I have to store data, which the user can enter on the view. I want to use a Dictionary for this. I now, how to create a dictionary:
NSMutableDictionary *globalData = [[NSMutableDictionary alloc] init];
//add keyed data
[globalData setObject:#"Object One" forKey:#"1"];
[globalData setObject:#"Object Two" forKey:#"2"];
I am searching now the right place to add and instantiate this dictionary, that it can be used as model in all views.

You can use a singleton model object to keep the global data. If you are using this in almost all viewControllers declare in *.pch file. If you are using dictionary you define some constants for ease of use.
GlobalDataModel *model = [GlobalDataModel sharedDataModel];
//Pust some value
model.infoDictionary[#"StoredValue"] = #"SomeValue";
//read from some where else
NSString *value = model.infoDictionary[#"StoredValue"];
.h file
#interface GlobalDataModel : NSObject
#property (nonatomic, strong) NSMutableDictionary *infoDictionary;
+ (id)sharedDataModel;
#end
.m file
#implementation GlobalDataModel
static GlobalDataModel *sharedInstance = nil;
- (id)init{
self = [super init];
if (self) {
self.infoDictionary = [NSMutableDictionary dictionary];
}
return self;
}
+ (id )sharedDataModel {
if (nil != sharedInstance) {
return sharedInstance;
}
static dispatch_once_t pred; // Lock
dispatch_once(&pred, ^{ // This code is called at most once per app
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}

Declare the NSMutableDictionary as a property in .h file for all ViewControllers concerning the model
In your .m file, implement the getter of the NSMutableDictionary using lazy instantiation.
..
-(NSMutbaleDictionary *) globalData{
if (_globalData == nil){
_globalData = [[NSMutableDictionary alloc]init];
}
return _globalData;
}
transfer the dictionary to other viewControllers of other views in prepareForSegue:

Related

Populating an array of custom model crashes in objective c

There is a variable in my class. which is the array of a custom model. I want to populate this variable in method 1. but app crashes at this line: [inboxMessagesArray addObject:entity]
Thread 1: EXC_BAD_ACCESS
In .m file:
#synthesize inboxMessagesArray;
In .h file:
#property (nonatomic,retain) NSMutableArray<InboxMessagesResponseEntity *> *inboxMessagesArray;
Mehod1
for (NSDictionary *responseEntityDictionary in dictionary)
{
InboxMessagesResponseEntity *entity = [[InboxMessagesResponseEntity alloc] initWithDictionary:responseEntityDictionary error:&err];
[inboxMessagesArray addObject:entity];
}
You need to init the array inboxMessagesArray before adding objects to it
self.inboxMessagesArray = [NSMutableArray new]; // OR [[NSMutableArray alloc] init];

How can I pass a NSMutableDictionary value to multiple controllers in my storyboard?

I have an Objective-C controller called LinkedInLoginController and inside it I have a function that contains an NSDictionary called newResult as shown below:
- (void)requestMeWithToken:(NSString *)accessToken {
[self.client GET:[NSString stringWithFormat:#"https://api.linkedin.com/v1/people/~?oauth2_access_token=%#&format=json", accessToken] parameters:nil success:^(AFHTTPRequestOperation *operation, NSDictionary *result)
{
NSLog(#"current user %#", result);
NSMutableDictionary *newResult = [result mutableCopy]; //copies the NSDictionary 'result' to a NSMutableDictionary called 'newResult'
[newResult setObject: [newResult objectForKey: #"id"] forKey: #"AppUserID"]; //copies the value assigned to key 'id', to 'AppUserID' so the database can recognize it
[newResult removeObjectForKey: #"id"]; //removes 'id' key and value
LinkedInLoginJSON *instance= [LinkedInLoginJSON new]; //calls LinkedInPost method from LinkedInLoginJSON controller
[instance LinkedInPost:newResult];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"failed to fetch current user %#", error);
}
];
[self performSegueWithIdentifier:#"toHotTopics" sender: self]; //Sends user on to Trending page after they sign in with LinkedIn
}
I am trying to pass the key value for AppUserID to four different Swift ViewControllers. What is the best way to do this? Passing it over with a segueway? I tried calling it directly from NSDictionary using this guide but was unsuccessful: http://mobiforge.com/design-development/using-objective-c-and-swift-together-ios-apps
Fortunately Obj-C and Swift are co-compatible at the moment (from what I understand).
In Obj-C I would create a new subclass of NSObject, maybe MySharedValues, so the header would look like this:
#interface MySharedValues : NSObject
#property (nonatomic, strong) id appUserId;
+(instancetype)defaultInstance;
#end
And the implementation would look like:
#implementation
+(instancetype)defaultInstance{
static MySharedValues *obj = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
obj = [[self alloc] init];
});
return obj;
}
#end
Then you can import #import "MySharedValues.h" into the headers of all your controllers. To access or set the value, you would call
[MySharedValues defaultInstance].appUserId;
Create a singleton, new file->cocoaclass subclass of nsobject
in .h file
#import <Foundation/Foundation.h>
#interface ShowTimer : NSObject
{
NSMutableDictionary *passed;
}
#property (nonatomic, retain) NSMutableDictionary *passed;
+ (id)sharedManager;
#end
.m file
#import "ShowTimer.h"
#implementation ShowTimer
#synthesize passed;
#pragma mark Singleton Methods
+ (id)sharedManager {
static ShowTimer *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
}
return self;
}
- (void)dealloc {
// Should never be called, but just here for clarity really.
}
#end
in your view controllers import #import "ShowTimer.h" then set or get the object it.
set your object
ShowTimer *timer=[ShowTimer sharedManager];
timer.passed=newResult;
get your object
ShowTimer *timer=[ShowTimer sharedManager];
NSMutableDictionary *newResult =timer.passed;
Sorry about the naming, I just copy and pasted another class to answer your question but you can change the naming if you want....
EDIT:
When you add an objective-c class to swift it will as you to bridging options then if you say yes it will add -Bridging-Header.h to your project in that header just call #import "ShowTimer.h"
in your swift view controller use the code like this
var companies:NSMutableDictionary = ["AAPL" : "Apple Inc", "GOOG" : "Google Inc", "AMZN" : "Amazon.com, Inc", "FB" : "Facebook Inc"]
var instance:ShowTimer = ShowTimer.sharedManager() as ShowTimer
instance.passed=companies
var dict:NSMutableDictionary=instance.passed
NSLog("%#", dict);
I have never written swift code before but just research lit bit if my approach doesnt work for you

Hash Table Code Explanation

I found this implementation of a hash table written in objective-c. I can follow almost all of it, but am struggling to understand how exactly the -(id) init function works. This is the method in the HashTable.m file with 3 lines (I repasted it below right after the question). Could someone explain what exactly it is doing? I included some of the other relevant code although for the most part I think I can follow the rest. Despite that I'm unclear as to the specifics of the init method. Thanks
-(id)init
{
self =[super init];
self.othercontainer = [[NSMutableArray alloc]init];
return self;
}
HashTable.h
#import <Foundation/Foundation.h>
#interface HashTable : NSObject
#property(nonatomic) NSMutableArray* othercontainer;
-(id)objectForKey:(NSString*)name;
-(void)setObject:(id)object forKey:(NSString*)name;
-(id)init;
#end
HashTable.m
#import "HashTable.h"
#import "Person.h"
#implementation HashTable
-(id)init
{
self =[super init];
self.othercontainer = [[NSMutableArray alloc]init];
return self;
}
-(id)objectForKey:(NSString*)name
{
Person* tempPerson = nil;
for (id item in self.othercontainer)
{
NSString* tempName = [((Person*)item) name];
if ([tempName isEqualToString:name])
{
tempPerson = item;
break;
}
}
return tempPerson;
}
-(void)setObject:(id)object forKey:(NSString*)name
{
[self.othercontainer addObject:object];
}
#end
Part of ViewController.m
NSData *data;
NSFileHandle *fh;
NSString *inBoundFile = #"/Users/user/Desktop/names.txt";
NSString *fileString;
fh = [NSFileHandle fileHandleForReadingAtPath:inBoundFile];
data = [fh readDataToEndOfFile];
fileString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
NSArray *PersonArray = [fileString componentsSeparatedByString:#"\n"];
self.container = [[HashTable alloc]init];
for (int x= 0; PersonArray.count > x ;x++) {
NSArray* tempNameandAddress = [PersonArray[x] componentsSeparatedByString:#" "];
Person *personA = [[Person alloc]init]; //could be other ways of defining an instance of an object
personA.name = tempNameandAddress[0];
personA.address = tempNameandAddress[1];
if ([self.container objectForKey:personA.name] == nil)
[self.container setObject:personA forKey:personA.name];
else
NSLog(#"%# already exists \n",personA.name);
}
This is simply an almost right common init.
self is set to the object returned by the superclass init.
Then they miss one proper step.
The next step should be if (self) { ...additional setup... }
Basically only creating ivars/properties if self as returned from super init is not nil.
If self is nil at that point you would normally just bypass additional code and go straight to return self. (Returning nil)
The next line is just creating the NSMutableArray ivar for the othercontainer property.
This is also not quite right.
In init, this is when you should use the synthesized ivar directly.
_othercontainer = [[NSMutableArray alloc] init];
Nothing special here.

how to store classobject that returns self

I am making a NSObjectClass that has a method in it that returns self.
This is what it looks like roughtly
storageclass.h
// storageclass vars go here
- (storageclass)assignData:(NSDictionary *)dictionary;
storageclass.m
//#synthesise everything
- (storageclass)assignData:(NSDictionary *)dictionary {
//assign values from dictionary to correct var types (i.e. NSString, Int, BOOL)
//example
Side = [dictionary valueForKey:#"Side"];
return self;
}
Then what I want to do is use this class by passing a NSDictionary var through its method to return a object of type storageclass that I can then use to access the vars using dot notation.
this is how I am trying to access this class at the moment
accessorViewController.h
storageclass *store;
#property (strong, nonatomic) storageclass *store;
accessorViewController.m
#synthesize store;
- (void)getstoreready {
[store assignData:someDictionary];
nslog(#"%#", store);
}
this NSLog returns nothing and in the debugger all of stores class vars are empty showing nothing has been assigned. I am 100% positive the dictionary vars being used in the assignData method have the correct valueForKey values.
I think it has something to do with how I am using it here [store assignData:someDictionary]; how do i catch the turned data so I can use it?
any help would be appreciated.
The store object is never initialized so it will be nil thats obvious isn't it. Initialize the store object first, then call its instance methods onto it. And by doing that, you'll have a storageclass object which is properly assigned with some dictionary already.
And if you want to have a storageclass object like your code shows, you should make your (storageclass)assignData:(NSDictionary *)dictionary method a class method instead of an instance method by putting a + sign
+(storageclass*)assignData:(NSDictionary *)dictionary;
Then properly initialize it and assign the data (dictionary to variables) accordingly and return it to the caller. For example :-
in .m file
+(storageclass*)assignData:(NSDictionary *)dictionary{
storageclass *test = [[storageclass alloc] init];
if (test) {
test.someDict = dictionary;
}
return test;
}
Then use this class method in your view controller as
- (void)getstoreready {
store = [storageClass assignData:someDictionary];
nslog(#"%#", store);
}
Also Do follow the naming convention for classes and instances. A class's name must start with a capital letter only and the opposite for any class instances.
In User.h
#interface User : NSObject
#property (nonatomic, copy) NSString *name;
- (id)initWithDictionary:(NSDictionary *)dictionary;
+ (NSArray *)usersFromArray:(NSArray *)array;
#end
In User.m
- (id)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
if (dictionary)
{
self.name = dictionary[#"kUserName"];
}
}
return self;
}
+ (NSArray *)usersFromArray:(NSArray *)array
{
NSMutableArray *users = [NSMutableArray array];
for (NSDictionary *dict in array) {
User *user = [[User alloc]initWithDictionary:dict];
[users addObject:user];
}
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"name"
ascending:YES];
return [users sortedArrayUsingDescriptors:#[descriptor]];
}
In ViewController.m
import "User.h"
self.currentArray = [User usersFromArray:array];

How to store data in class in iOS programming?

The goal, to create a class which contains an array of data to be used throughout the application by other classes.
I have this GlobalObject.h
It declares the array to be used to store the data.
#import <Foundation/Foundation.h>
#interface GlobalObjects : NSObject
#property (retain) NSMutableArray *animals;
-(id)init;
#end
I have this GlobalObject.m.
It contains the NSDictionary data and stores in to the array.
#import <Foundation/Foundation.h>
#interface GlobalObjects : NSObject
#property (retain) NSMutableArray *animals;
-(id)init;
#end
#import "GlobalObjects.h"
#implementation GlobalObjects
#synthesize animals;
-(id)init{
self = [super init];
if (self) {
// Define the data
NSArray *imagesValue = [[[NSArray alloc] initWithObjects:#"dog.wav",#"cat.png",#"bird.png",nil] autorelease];
NSArray *audioValue =[[[NSArray alloc] initWithObjects:#"dog.wav",#"cat.wav",#"bird.wav",nil] autorelease];
NSArray *descriptionValue = [[[NSArray alloc] initWithObjects:#"Dog",#"Cat",#"Bird",nil] autorelease];
// Store to array
for (int i=0; i<8; i++) {
NSDictionary *tempArr = [NSDictionary dictionaryWithObjectsAndKeys:[imagesValue objectAtIndex:i],#"image", [audioValue objectAtIndex:i],#"audio", [descriptionValue objectAtIndex:i], #"description", nil];
[self.animals addObject:tempArr];
}
}
return self;
}
#end
Here's how I call it.
// someOtherClass.h
#import "GlobalObjects.h"
#property (nonatomic, retain) GlobalObjects *animalsData;
// someOtherClass.m
#synthesize animalsData;
self.animalsData = [[[GlobalObjects alloc] init] autorelease];
NSLog(#"Global Object %# ",self.animalsData.animals);
Now the problem is, when I call this array in another class, it always returns null.
I'm new to iOS programming. So probably my method is wrong?
You forgot to allocate the animals array in the init method of "GlobalObjects":
self.animals = [[NSMutableArray alloc] init];
If you don't do this, self.animals is nil and addObject has no effect.
Since you do not use ARC, remember to release the array in dealloc.
EDIT: As #H2CO3 and #Bastian have noticed, I forgot my pre-ARC lessons. So the correct way to allocate self.animals in your init method is
self.animals = [[[NSMutableArray alloc] init] autorelease];
and in dealloc you have to add
self.animals = nil;
before calling [super dealloc]. I hope that I got it right now!
Yes, it's wrong - an instance variable isn't tied to a class itself, but to a particular instance of the class. The Cocoa-standard solution to this problem is creating a shared instance of the class - instead of
elf.animalsData = [[[GlobalObjects alloc] init] autorelease];
write
elf.animalsData = [GlobalObjects sharedInstance];
and implement the + sharedInstance method like this:
+ (id)sharedInstance
{
static shared = nil;
if (shared == nil)
shared = [[self alloc] init];
return shared;
}
As #MartinR pointed out, you make another mistake: you don't create the array you're adding objects to - then it remains nil, cancelling out the effect of all method calls on itself. You have to alloc-init a mutable array for it in the - init method.

Resources