I have this piece of code below and I'm trying to add Objects(String elements) to an array, problem is that every time I'm out its adding's method, it goes to nil, it doesn't retain the objects.
I know I'm doing wrong, even that I already tried lot of combinations and variations, even with my own constructor _MyArray etc etc, same result... it works, but not further...
Could you help me please?
#interface ArraysModel()
#property (nonatomic, retain) NSMutableArray *MyArray;
#end
#implementation ArraysModel
#synthesize MyArray;
-(void)AddObjectToTheList:(NSString *)object {
if(!MyArray) MyArray = [[NSMutableArray alloc] init];
[MyArray addObject:object];
NSLog(#"%#",self.MyArray);
NSLog(#"Object added %u",[self.MyArray count]);
}
-(NSMutableArray *)ObjectList {
return self.MyArray;
NSLog(#"%#",self.MyArray);
NSLog(#"Object added %u",[self.MyArray count]);
}
#end
The header is like this:
#interface ArraysModel : NSObject
-(void)AddObjectToTheList:(NSString *)object;
And here is my call from my ViewController:
- (IBAction)AddToTheList {
ArraysModel *MyObjectToAdd = [[ArraysModel alloc] init];
[MyObjectToAdd AddObjectToTheList:TextArea.text];
[self.view endEditing:YES];
Well, there's your problem -- you're alloc init'ing a new instance of ArraysModel, and therefore a new array with every call. You need to create a strong reference to your instance, and check for whether it exits, and only init if it doesn't.
In the .h:
#property (strong, nonatomic) ArraysModel *myObjectToAdd;
in the .m:
-(IBAction)AddToTheList {
if (! self.myObjectToAdd) {
self.myObjectToAdd = [[ArraysModel alloc] init];
}
[self.myObjectToAdd AddObjectToTheList:TextArea.text];
[self.view endEditing:YES]
}
Related
I have looked all over the place for anyone who has experienced this issue but have yet to find anything relevant, so I thought I'd ask it myself...
I have a custom object (HitterData) which I will use to populate cells in a UITableView, then two ViewControllers (one is hitterTableViewController, the other is a "detail" view controller labeled "AddPlayerViewController").
The problem is that I can add HitterData objects to the NSMutableArray in my Table VC, but only one, and then when I add another one using the detail view controller, the Mutable array is "reinitialized" and I can again only have one object at a time.
HitterObject:
#implementation HitterData.m
#synthesize hitterName = _hitterName;
#synthesize position = _position;
-(id)initWIthNameAndPosition:(NSString *)hitterName position:(NSString *)position {
if ((self = [super init])) {
self.hitterName = _hitterName;
self.position = _position;
}
return self;
}
HitterTableViewController.h
#import "HitterData.h"
#import "HitterDoc.h"
#import "AddPlayerViewController.h"
#interface HitterTableViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *hitters;
- (IBAction)backButton:(id)sender;
- (IBAction)addPlayerView:(id)sender;
-(void)addHitterObject:(HitterData *)hitter;
HitterTableViewController.m (only relevant to make this more readable)
#implementation HitterTableViewController
#synthesize hitters = _hitters;
- (void)viewDidLoad {
[super viewDidLoad];
self.hitters = [NSMutableArray array];
}
-(void)addHitterObject:(HitterData *)hitter {
if(_hitters != nil) {
[_hitters addObject:hitter];
} else {
_hitters = [NSMutableArray array];
[_hitters addObject:hitter];
NSLog(#"MutableArray is not valid");
}
}
AddPlayerViewController.h
#interface AddPlayerViewController : UIViewController <UITextFieldDelegate, UINavigationControllerDelegate>
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *positionTextField;
#property (nonatomic) HitterTableViewController *hitterTable;
#property (nonatomic) NSString *hitterName;
#property (nonatomic) NSString *position;
//-(void)addNewHitterToHittersArray:(HitterData *)hitter;
- (IBAction)addPlayerToRoster:(id)sender;
AddPlayerViewController.m
#implementation AddPlayerViewController
#synthesize hitterTable;
- (void)viewDidLoad {
[super viewDidLoad];
hitterTable = [[HitterTableViewController alloc] init];
}
- (IBAction)addPlayerToRoster:(id)sender {
self.hitterName = [self.nameTextField text];
self.position = [self.positionTextField text];
HitterData *hitter = [[HitterData alloc] init];
hitter.hitterName = self.hitterName;
hitter.position = self.position;
[hitterTable addHitterObject:hitter];
ArraySingleton *arrayS = [[ArraySingleton alloc] init];
[arrayS initializeArray];
[arrayS addToHittersArray:hitter];
if (arrayS) {
NSLog(#"arrayS exists in AddPlayerVC");
} else {
NSLog(#"arrayS does not exist");
}
[self performSegueWithIdentifier:#"backToTeamTableViewController" sender:self];
}
Am I missing something here?
Guess based just on the code shown:
Every time you wish to add a player it looks like you create a new AddPlayerView/AddPlayerViewController. In turn that controller creates, in its viewDidLoad, a new HitterTableViewController - which of course has its own empty array. The code should instead be referencing the existing HitterTableViewController.
BTW: The common design pattern is MVC - model, view, controller - consider whether you are in your current situation because you've stored part of your model, the array, in your controller, and maybe both controllers should be referencing a common shared model object containing that array.
BTW: All those #synthesise statements are unneeded. In modern Obj-C synthesis is automatic and you rarely need these statements. Also it is generally recommended to not use the property backing variable directly, and certainly not when storing into the property as this breaks KVO. (There also appears to be a related typo in HitterData.m but as you don't report that as not working it is probably just a typo in your question and not code.)
HTH
AddPlayerViewController should know nothing about HitterTableViewController, return the new HitterData object with a delegate method.
- (IBAction)addPlayerToRoster:(id)sender
{
Hitter *hitter = [[Hitter alloc] init];
hitter.name = [self.nameTextField text];
hitter.position = [self.positionTextField text];
[self.delegate didAddHitter:hitter];
}
Then back in HitterTableViewController
- (void)didAddHitter:(Hitter *)hitter
{
[self.hitters addHitter:hitter];
[self dismissViewControllerAnimated:YES completion:nil];
}
i'm getting "use of undeclared identifier" errors in my .m file with the code below and can't seem to work it out.
NSArray *imageViews = [NSArray arrayWithObjects:img1, img2, img3, img4, img5, img6, img7, img8, img9, img10, img11, img12, img13, img14, img15, img16, img17, img18, img19, img20, img21, img22, img23, img24, img25, img26, img27, img28, img29, img30, img31, img32, img33, img34, img35, img36, img37, img38, img39, img40, nil];
In my .h file i have 40 images, all with referencing outlets:
#property (weak, nonatomic) IBOutlet UIImageView *imgX;
where X is a number from 1-40. In my .m file, the NSArray *imagesViews works fine as long as it's inside a method, but i can't declare it outside the method so that it is available to all methods. As an Objective-C novice, I don't where to go from here. I'd appreciate any help.
You don't have to initialize the array outside of a method to make it accessible from all methods. What you should do instead is declare it as a property and initialize it inside the viewDidLoad method.
In the .h file:
#property (strong, nonatomic) NSArray *imageViews;
#property (weak, nonatomic) IBOutlet UIImageView *img1;
// ...
In the .m file:
#synthesize imageViews, img1, img2, ...
// ...
- (void)viewDidLoad
{
[super viewDidLoad];
// ...
self.imageViews = [NSArray arrayWithObjects:self.img1, self.img2, ... , nil];
}
Also, note that because you have 40 image views, you should probably avoid declaring a property for each one of them. You can assign tags to them, and then retrieve them using the method viewWithTag.
In the header:
#interface MyClass : NSObject {
NSArray *imageViews;
}
#end
In the implementation:
#implementation MyClass
- (id) init
{
self = [super init];
if (self != nil) {
imageViews = [[NSArray arrayWithObjects:img1, nil] retain];
}
return self;
}
// now you can use imageViews also from other methods
- (void) dealloc
{
[imageViews release];
[super dealloc];
}
#end
#interface SimataDetailViewController ()
#property Simata *simata;
#property (nonatomic, copy) NSMutableArray *simataList;
#end
#implementation SimataDetailViewController
#synthesize simataDataController=_simataDataController;
#synthesize category=_category;
#synthesize simata=_simata;
#synthesize simataList=_simataList;
#pragma mark - Managing the detail item
- (void) getSimataForCategory: (NSString *) inputCategory {
unsigned count = [self.simataDataController.masterList2 count];
while (count--) {
if ([[[self.simataDataController objectSimataInListAtIndex:count] categoryCode] isEqual:inputCategory]){
self.simata= [self.simataDataController objectSimataInListAtIndex:count];
[self.simataList addObject:self.simata];
}
}
NSLog(#"count, %u", [self.simataList count]);
}
Hello this is my first post, so please be patient.
I am trying to add object self.simata to array self.simataList but the array stays with zero objects. The object self.simata is not nil and I don't get any error.
What am I doing wrong?
Are you sure you have created an instance of the array before you use it?
self.simataList =[NSMutableArray array];
It could also be your self.simata being nil...
EDIT
You could create the array instance in the default init method:
-(id)init
{
self = [super init];
if(self)
{
//do your object initialization here
self.simataList =[NSMutableArray array];
}
return self;
}
Most likely self.simataList is nil. Try NSLogging self.simataList itself, rather than its count.
I am trying to pass the selected object in my coredata from the rootviewcontroller to the edit view. The selected object is being passed but is then becoming null after the theObject=selectedObject is being called. Anyone know what im doing wrong?
This is in the edit.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
#import "LearningAppDelegate.h"
#interface edit : UIViewController <UITextViewDelegate, UITableViewDelegate, UITableViewDataSource, UIActionSheetDelegate>{
UITableView *tableView;
NSManagedObject *theObject;
UITextView *messageView;
}
#property(nonatomic, retain) IBOutlet UITableView *tableView;
#property(nonatomic, retain) IBOutlet UITextView *messageView;
#property(nonatomic, retain) NSManagedObject *theObject;
-(id)initWithObject:(NSManagedObject *)selectedObject;
#end
This is in the edit.m:
-(id)initWithObject:(NSManagedObject *)selectedObject {
self = [super init];
if (nil == self) {
return nil;
}
NSLog(#"selectedObject: %#", selectedObject);
NSLog(#"selecetedObject.message: %#", [[selectedObject valueForKey:#"message"] description]);
theObject=selectedObject;
NSLog(#"theObject 1: %#", theObject);
NSLog(#"theObject.message 1: %#", [[theObject valueForKey:#"message"] description]);
return self;
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
NSLog(#"theObject 2: %#", theObject);
NSLog(#"theObject.message 2: %#", [[theObject valueForKey:#"message"] description]);
messageView.text=[[theObject valueForKey:#"message"] description];
[super viewDidLoad];
}
I am actually amazed that doesn't crash for you. You're assigning the variable selectedObject into the instance variable theObject without retaining it for your own use. By accessing the instance variable directly in the assignment 'theObject=selectedObject', you're bypassing the behavior granted by the #property declaration. This means that once selectedObject is finally dealloc'd, theObject will point to garbage memory.
The correct way to do this is to put theObject = [selectedObject retain]; in the -initWithObject: method and in -viewDidLoad to access it via self.theObject rather than just theObject.
In my own usage I prefer to give instance variables names different from the actual property name to avoid confusion. For example:
#interface SomeClass : NSObject
{
#private
NSManagedObject *_theObject;
}
#property (nonatomic, retain) NSManagedObject *theObject;
...
#end
#implementation SomeClass
#synthesize theObject = _theObject
...
- (void)dealloc
{
[_theObject release], _theObject = nil;
[super dealloc];
}
#end
I only have experience with Coredata on the desktop, but the problem looks like it would be with your initWithObject method. At no point do you actually insert the new object into the managed object context. You should be using this method to make new objects:
- (id)initWithEntity:(NSEntityDescription *)entity insertIntoManagedObjectContext:(NSManagedObjectContext *)context
As an example in pseudocode:
NSManagedObject *newObject = [[NSManagedObject alloc] initWithEntity:NSENTITYDESCRIPTION insertIntoManagedObjectContext:MANAGEDOBJECTCONTEXT];
[newObject setValue:#"VALUE_OF_SELECTED_OBJECT" forKey:#"APPROPRIATE_KEY"];
//REPEAT AS NECESSARY
[MANAGEDOBJECTCONTEXT save];
*Code not tested, naming conventions are ignored, etc.
The save is important. If you don't do this the object won't persist.
Im attempting to pass an array that is created in one class into another class. I can access the data but when I run count on it, it just tells me that I have 0 items inside the array.
This is where peopleArray's data is set up, it's in a different class than the code that is provided below.
[self setPeopleArray: mutableFetchResults];
for (NSString *existingItems in peopleArray) {
NSLog(#"Name : %#", [existingItems valueForKey:#"Name"]);
}
[peopleArray retain];
This is how I get the array from another class, but it always prints count = 0
int count = [[dataClass peopleArray] count];
NSLog(#"Number of items : %d", count);
The rest of my code:
data.h
#import <UIKit/UIKit.h>
#import "People.h"
#class rootViewController;
#interface data : UIView <UITextFieldDelegate>{
rootViewController *viewController;
UITextField *firstName;
UITextField *lastName;
UITextField *phone;
UIButton *saveButton;
NSMutableDictionary *savedData;
//Used for Core Data.
NSManagedObjectContext *managedObjectContext;
NSMutableArray *peopleArray;
}
#property (nonatomic, assign) rootViewController *viewController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSMutableArray *peopleArray;
- (id)initWithFrame:(CGRect)frame viewController:(rootViewController *)aController;
- (void)setUpTextFields;
- (void)saveAndReturn:(id)sender;
- (void)fetchRecords;
#end
data.m(some of it at least)
#implementation data
#synthesize viewController, managedObjectContext, peopleArray;
- (void)fetchRecords {
[self setupContext];
// Define our table/entity to use
NSEntityDescription *entity = [NSEntityDescription entityForName:#"People" inManagedObjectContext:managedObjectContext];
// Setup the fetch request
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
// Define how we will sort the records
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"Name" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
// Fetch the records and handle an error
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (!mutableFetchResults) {
// Handle the error.
// This is a serious error and should advise the user to restart the application
}
// Save our fetched data to an array
[self setPeopleArray: mutableFetchResults];
for (NSString *existingItems in peopleArray) {
NSLog(#"Name : %#", [existingItems valueForKey:#"Name"]);
}
[peopleArray retain];
[mutableFetchResults release];
[request release];
//NSLog(#"this is an array: %#", eventArray);
}
login.h
#import <UIKit/UIKit.h>
#import "data.h"
#class rootViewController, data;
#interface login : UIView <UITextFieldDelegate>{
rootViewController *viewController;
UIButton *loginButton;
UIButton *newUser;
UITextField *entry;
data *dataClass;
}
#property (nonatomic, assign) rootViewController *viewController;
#property (nonatomic, assign) data *dataClass;
- (id)initWithFrame:(CGRect)frame viewController:(rootViewController *)aController;
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField;
#end
login.m
#import "login.h"
#import "data.h"
#interface login (PrivateMethods)
- (void)setUpFromTheStart;
- (void)loadDataScreen;
-(void)login;
#end
#implementation login
#synthesize viewController, dataClass;
-(void)login{
int count = [[dataClass peopleArray] count];
NSLog(#"Number of items : %d", count);
}
Is it the same object? If so, what you have should work. Check to see how you are getting the dataClass instance -- if you alloc a new one, you don't get the array from the other object.
Edit: From your comments below, it appears that you are having some confusion on the difference between classes and objects. I will try to explain (I'm going to simplify it):
A class is what you write in Xcode. It's the description that lets your application know how to create and access objects at run-time. It is used to figure out how much memory to allocate (based on instance variables) and what messages can be sent, and what code to call when they are. Classes are the blueprints for creating objects at runtime.
An object only exists at run-time. For a single class, many objects of that class can be created. Each is assigned its own memory and they are distinct from each other. If you set a property in one object, other objects don't change. When you send a message to an object, only the one you send it to receives it -- not all objects of the same class.
There are exceptions to this -- for example if you create class properties (with a + instead of a - at the beginning), then they are shared between all objects -- there is only one created in memory, and they all refer to the same one.
Also, since everything declared with a * is a pointer -- you could arrange for all pointer properties to point to the same data. The pointer itself is not shared.
Edit (based on more code): dataClass is nil, [dataClass peopleArray] is therefore nil, and then so is the count message call. You can send messages to nil, and not crash, but you don't get anything useful.
I don't see how the login object is created. When it is, you need to set its dataClass property.
Try running the code in the debugger, setting breakpoints, and looking at variables.
From the code, it looks like you are passing a mutable array.
[self setPeopleArray: mutableFetchResults];
Probably the items of the array are removed somewhere in your calling class / method. Or the array is reset by the class from which you get the mutableFetchResults in the first place.