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];
Related
I'm very new to objective-c so be easy :-) I have a container object, "Data", who has a number of NSMutableArrays.
Data.h
#interface Data : NSObject{
NSMutableArray *one;
NSMutableArray *two;
}
#property (nonatomic, retain) NSMutableArray *one;
#end
and would like to pass it to a load method in which case it will update each corresponding array in the Data class.
Parser.h
+ (Parser *)load:(Data*) store;
Parser.m
+ (Parser *)load:(Data *) store {
...
[store.one addObject:name.stringValue];
}
But no matter what I do the string in "name.stringValue" doesn't get appended to the array. Is there something I'm missing when passing in the "Store" data object to the parse method? Let me know if I should provide more details but I feel this covers the issue.
Check in your implementation of Data that you are properly initializing the mutable arrays - here is a simple example below given your Data interface:
#import "Data.h"
#implementation Data
{
#pragma mark - Properties
- (NSMutableArray *)one
{
if (!_one) {
_one = [[NSMutableArray alloc] init];
}
return _one;
}
- (NSMutableArray *)two
{
if (!_two) {
_two = [[NSMutableArray alloc] init];
}
return _two;
}
}
Use one = [NSMutableArray array]; before you start using it. This will create an empty mutable array.
I declare the following in ViewController.h
#property (nonatomic, strong) NSMutableArray *locations;
and the following in ViewController.m
#implementation GHViewController
#synthesize locations;
...
for (FSFourSquareVenueObject *object in array) {
locations = [[NSMutableArray alloc] init];
[locations addObject:object.locationName];
NSLog(#"%#", locations);
}
This successfully logs all the string locations that have been placed in the locations NSMutableArray. How can I access this NSMutableArray in a different class?
I am trying to access it in my TableViewController class in order to display all the elements in the array. I have tried importing the ViewController.h file into my TableViewController.h file, yet I still cannot access the array from the ViewController class.
Remove the line
locations = [[NSMutableArray alloc] init];
from your for loop and place it somewhere like viewDidLoad or init. You're wiping out your array every time before adding a new object.
To access a single object across classes, you want to look into creating a singleton. There are many tutorials online.
Do as #Stonz2 suggests, but also modify your headers as follows:
In GHViewController.h:
#property (nonatomic, strong) NSArray *locations;
In GHViewController.m
#implementation GHViewController
#synthesize locations;
...
NSMutableArray *array = [[NSMutableArray alloc] init];
for (FSFourSquareVenueObject *object in array) {
[array addObject:object.locationName];
NSLog(#"%#", array);
}
self.locations = [array copy];
You can then access the array from another class using GHViewController -locations. You can edit the locations using the following snippet (or by creating a similar method in GHViewController):
NSMutableArray *array = [gh_viewController.locations mutableCopy];
[array addObject: newLocation];
gh_viewController.locations = [array copy];
Exposing a mutable array allows other class to modify the array without notifying GHViewController and vice versa. This can lead to unpredictable and hard to debug problems, such as if GHViewController removes some elements while TableViewController is iterating through all the objects. Using a non-mutable array prevents these sorts of bugs and ensures everyone has a consistent view of what's inside.
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];
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:
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.