referencing an Mutable array from ClassA to Class B - objective-c

could someone help me reference an array from a different class.
here is ClassA.h
#interface ClassA : UIViewController <MKMapViewDelegate> {
NSMutableArray *theArray;
}
#property (nonatomic, retain) NSMutableArray *theArray;
-(NSMutableArray *) pleaseReturnTheArray;
#end
ClassA.m
#import "ClassA.h"
#implementation ClassA
#synthesize theArray;
...
-(NSMutableArray *) pleaseReturnTheArray {
return theArray;
}
and here is ClassB.m (i want to reference ClassA array, i have #import "MapView.h" into this class, this is a different view that gets pushed onto the screen)
- (void)viewDidLoad {
[super viewDidLoad];
//first test
ClassA *firstTest = [[ClassA alloc] init];
NSMutableArray *firstTestArray = [firstTest.theArray mutableCopy];
NSLog(#"first test - %#", firstTestArray);
//second test
NSMutableArray *secondTestArray = [firstTest pleaseReturnTheArray];
NSLog(#"second Test - %#", secondTestArray);
...
the result in NSLog i get is ...
first test - (null)
second Test - (null)
I am sure i have used one of these methods before and it has worked fine. Is it something to do with the fact that ClassB is a different view pushed by a tab bar controller?
any help would be appreciated.
Chris

My initial guess here is that you are not initializing theArray to a real array in your init method of ClassA. By default it will be nil. So the mutableCopy will also be nil as is shown in your output. Or perhaps adding this line of code after allocating firstTest would help:
firstTest.theArray = [NSArray arrayWithObjects:#"A",#"B",nil];
Also the pleaseReturnTheArray method is redundant with the theArray getter. You might as well write the following line of code instead:
NSMutableArray *secondTestArray = firstTest.theArray;
Note that because you are taking a mutable copy for firstTestArray, firstTestArray and secondTestArray will be equal but they will not be the same arrays. That means that if you add something in firstTestArray it won't show up in secondTestArray and vice versa.

Related

Moving data from 1 class to another - same app

Need real help here!!!
I am trying to use data created in 1st class within the 2nd class. I have been searching Youtube and StackOverflow for over 1 week. Every time I think I am close, there is some element missing that I can not grasp. My latest attempt came from this site published in 2011 (Passing Data between classes objective-c) and while the application compiles, I can not see the data in the 2nd class.
More specific. I am using 2 classes because the data is gathered in groups (1st class) selected by the user and will be displayed on-screen in a table within the 2nd class. There are 6 NSMutable Arrays from the source passing to 6 different in the 2nd class. I will continue to try to solve, but I could use help.
Here is what I have devised from the 2011 article:
1st class .h code(partial):
#import <Cocoa/Cocoa.h>
#import <Foundation/Foundation.h>
#import "ReportsOutput.h"
//#class AppDelegate;
#class ReportsOutput;
#interface ReportsClass : NSWindowController<NSApplicationDelegate,NSMenuDelegate,NSWindowDelegate>{
ReportsOutput *ro;
//Shared Data arrays
NSMutableArray *tblYrScott;
NSMutableArray *tblYrExt;
NSMutableArray *tblYrYear;
NSMutableArray *tblYrType;
NSMutableArray *tblYrPrice;
NSMutableArray *tblYrDescription;
...... added code
#property(nonatomic,retain)NSMutableArray *tblYrScott;
#property(nonatomic,retain)NSMutableArray *tblYrExt;
#property(nonatomic,retain)NSMutableArray *tblYrType;
#property(nonatomic,retain)NSMutableArray *tblYrYear;
#property(nonatomic,retain)NSMutableArray *tblYrPrice;
#property(nonatomic,retain)NSMutableArray *tblYrDescription;
1st class .m code:
- (IBAction)btnShowDataOutput:(id)sender {
//pass data from Reports Class to Report Output Class
ReportsOutput *objReportsOutput = [[ReportsOutput alloc]init];
[objReportsOutput.tblScott setArray: tblYrScott];
[objReportsOutput.tblExt setArray:tblYrDescription];
[objReportsOutput.tblYear setArray:tblYrYear];
[objReportsOutput.tblType setArray:tblYrType];
[objReportsOutput.tblDescription setArray:tblYrDescription];
// open Reports Output Window
if (ro == nil){
ro = [[ReportsOutput alloc] initWithWindowNibName:#"ReportsOutput"];
}
[ro showWindow:nil];
}
2nd class .h code:
#import <Cocoa/Cocoa.h>
#import "ReportsClass.h"
#interface ReportsOutput : NSWindowController{
//shared data arrays
NSMutableArray *tblScott;
NSMutableArray *tblExt;
NSMutableArray *tblYear;
NSMutableArray *tblType;
NSMutableArray *tblPrice;
NSMutableArray *tblDescription;
}
#property(nonatomic,strong) NSMutableArray *tblScott;
#property(nonatomic,strong) NSMutableArray *tblExt;
#property(nonatomic,strong) NSMutableArray *tblYear;
#property(nonatomic,strong) NSMutableArray *tblType;
#property(nonatomic,strong) NSMutableArray *tblPrice;
#property(nonatomic,strong) NSMutableArray *tblDescription;
#end
2nd class .m code:
#import "ReportsOutput.h"
//#import "ReportsClass.h"
#interface ReportsOutput ()
#end
#implementation ReportsOutput
#synthesize tblScott;
#synthesize tblExt;
#synthesize tblType;
#synthesize tblPrice;
#synthesize tblYear;
#synthesize tblDescription;
- (void)windowDidLoad {
[super windowDidLoad];
}
-(void)awakeFromNib{
[self dataCheck];
}
-(void)dataCheck{
int a;
for (a=0; a<[self.tblScott count]; a++){
NSLog(#"#i,%d :%#: %#: %#: %#: %#: %#",a,[tblScott objectAtIndex:a],[tblExt objectAtIndex:a],[tblYear objectAtIndex:a],[tblType objectAtIndex:a],[tblPrice objectAtIndex:a],[tblDescription objectAtIndex:a]);
}
}
In btnShowDataOutput, you create objReportsOutput, but that object goes away as soon as the method ends. You don't need to create objReportsOutput. Instead, set the properties directly on the ReportsOutput window controller:
if (ro == nil){
ro = [[ReportsOutput alloc] initWithWindowNibName:#"ReportsOutput"];
}
ro.tblScott = self.tblYrScott
ro.tblExt = self.tblYrExt
ro.tblYear = self.tblYrYear
ro.tblType = self.tblYrType
ro.tblDescription = self.tblYrDescription
[ro showWindow:nil];

Class Method Exposure and Property Definition

I have an academic question about Class Method exposure. There is something that I obviously don't understand about this and would like some clarification from those in the know.
Background:
I have a simple example of two classes named ViewController and ClassB. Class B contains an array with a method named returnArray. The ViewController accesses the array's data. I have exposed the returnArray method in the ClassB.h file.
Question:
Why is it that I can access the array's data in ViewController without having to define a property? I thought that the property would create a getter to allow access to the array. My example (only exposing the method) allows me to access the data without the creation of the #property.
Class Method:
ClassB.h
#interface ClassB : UIViewController
+(NSArray *) returnArray;
//#property (nonatomic, strong) NSArray *returnArray;
ClassB.m
#implementation ClassB
+(NSArray *) returnArray
{
NSArray *locationArray = #[#"Place1", #"Place2"];
return locationArray;
}
ViewController.m
- (void)viewDidLoad
{
NSArray *location = [ClassB returnArray];
NSLog (#"The count of the location is %d", [location count]);
NSLog (#"The second item in testArray is %#", location[1]);
}
Instance method: After reviewing answers
ClassB.h
*/
{
#private
NSArray *returnArray;
}
- (void)setReturnArray:(NSArray*)returnArray;
-(NSArray *) returnArray;
*/
#property (nonatomic, strong) NSArray *returnArray;
#end
ClassB.m - no change
ViewController.h - no change
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
//Create instance of ClassB
ClassB *classB = [ClassB new];
//Access the instance of returnArray
NSArray *location = [classB returnArray];
NSLog (#"The count of the location is %d", [location count]);
NSLog (#"The second item in testArray is %#", location[1]);
}
#property is a shorthand notation for creating an instance variable and associated accessor methods (with defined access / modification criteria).
What you have is a class method, which internally creates an array and returns it.
That's why you call [ClassB returnArray]; instead of [instanceOfB array];.
These are completely different things. If you wanted to use a property then you would need to create an instance of ClassB and then access the property. This would work, assuming that the array was created when the instance of ClassB was created.
Wain's answer addresses the difference between #property and Class methods, so it's worth a read. My answer assumes you know the difference between class and instance methods, and focuses on the difference between creating a #property versus creating an instance variable with an associate setter and getter.
The reason is because returnArray is a public method that returns an NSArray object on your ClassB.
A #property is merely a convenient way of creating three things at the same time: an instance variable, a setter, and a getter. It has the added bonus of allowing dot-syntax.
But at the end of the day, dot-syntax aside, all you're doing by declaring a #property is equivalently equal to this:
#interface ClassB : NSObject {
#private
NSArray *returnArray;
}
- (void)setReturnArray:(NSArray*)returnArray;
- (NSArray*)returnArray;
This is the same as this:
#property NSArray *returnArray;
Except of course, the dot syntax.
When you do:
NSArray *myArray = classB.returnArray;
You're not actually directly accessing the array you created when you declared the #property.
What you're doing is calling the getter method that was automatically generated when you declared the #property.

Array loses all values after go trough its own method - Objective C

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]
}

NSArray getter method not returning right value

I'm making a program where one Class (classA) generates a random number and adds it to a mutable array. A view controller (viewControllerA) calls a method from classA and receives the array of random numbers and stores it in its own array.
I have another class (classB) that needs the same array. After viewcontrollerA is finished doing what it needs to do with the array, it calls the setter method for an array in classB. I call NSLog in the setter and getter methods for the array in classB to check to see if it loads.
-(void)setRandomNumberArray:(NSArray *)randomNumberArray{
_randomNumberArray = randomNumberArray;
NSLog(#"%# setter", _randomNumberArray);
}
-
-(NSArray *)randomNumberArray{
if (!_randomNumberArray) {
_randomNumberArray = [[NSArray alloc] init];
}
NSLog(#"%# getter", _randomNumberArray);
return _randomNumberArray;
}
When I call the setter method in viewControlerA, NSLog returns the value of the array.
When I call the getter method in viewControllerB, NSLog prints nothing from the getter method.
2012-05-29 23:57:43.589 SwipeGame[8603:f803] (
) getter
It's obviously setting the array but not retaining it for when i want to get it. What is going on? I've tried multiple other techniques and it always sets the array but doesn't retain it for when i want to "get" the array.
the property for my array is set to retain btw..
UPDATE:
Yes I am using ARC. my property declaration is:
#property (nonatomic, strong) NSArray *randomNumberArray
SOLVED:
Thanks for all your help! It was a problem with instances.
Your setter method does not mention viewControllerB. You are just setting an internal variable. How is viewControllerB going to know about the array having been set?
The easiest way is to just use #properties and #synthesize:
// in A
viewControllerB.array = _array;
As for the retain question: if you use ARC you should not worry about it.
Do you use ARC?
ARC version bellow:
#interface Foo : NSObject {
NSMutableArray *_randomNumberArray;
}
#property (nonatomic, strong) NSMutableArray *randomNumberArray;
#end
#implementation Foo
#synthesize randomNumberArray = _randomNumberArray;
- (void)setRandomNumberArray:(NSMutableArray *)randomNumberArray {
_randomNumberArray = randomNumberArray;
NSLog(#"%# setter", _randomNumberArray);
}
- (NSMutableArray *) randomNumberArray {
if ( _randomNumberArray == nil )
_randomNumberArray = [[NSMutableArray alloc] init];
NSLog(#"%# getter", _randomNumberArray);
return _randomNumberArray;
}
#end
Not ARC version bellow:
#interface Foo : NSObject {
NSMutableArray *_randomNumberArray;
}
#property (nonatomic, strong) NSMutableArray *randomNumberArray;
#end
#implementation Foo
#synthesize randomNumberArray = _randomNumberArray;
- (void)setRandomNumberArray:(NSMutableArray *)randomNumberArray {
[_randomNumber release];
_randomNumberArray = randomNumberArray;
[_randomNumberArray retain];
NSLog(#"%# setter", _randomNumberArray);
}
- (NSMutableArray *) randomNumberArray {
if ( _randomNumberArray == nil )
_randomNumberArray = [[NSMutableArray alloc] init];
NSLog(#"%# getter", _randomNumberArray);
return _randomNumberArray;
}
- (void)dealloc {
[_randomNumberArray release];
}
#end
If you are creating this random number array using an NSMutableArray, and passing that to the setter, the array could be mutated later by the caller (e.g. all items removed) and the array can change from under your feet.
For types like NSArray and NSString which have mutable subtypes, you should declare your property as copy instead of strong. This will ensure the array passed to you cannot be mutated at a later date by somebody else. Copy performance is not a problem because the regular immutable types handle copies very efficiently.

After setting one NSManaged object to another it returns Null

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.