NULL Custom Class Objects when outside viewDidLoad? - ios

u1Option is an Option (custom class) object which is
declared and called in my ViewController viewDidLoad as:
- (void)viewDidLoad {
[super viewDidLoad];
Option *u1Option = [[Option alloc]init];
[u1Option setName: #"test"];
NSLog(#"Test1 Result: %#", u1Option.name);
}
Option is a custom class inheriting from NSObject and has a property declared in Option.h:
#property NSString *name;
However, if try to use u1Option in a IBAction, nothing is passed and while I get the "test" string in the Test1 NSLOG, on the contrary I get NULL in the Test2 NSLOG.
- (IBAction)addFirstOption:(UIButton *)sender {
NSLog(#"Test2 Result: %#", u1Option.name);
}

The Option instance is destroyed as soon as viewDidLoad returns. You need to put it in a property or instance variable. If it's already a property or instance variable then you are re-defining it, so use:
u1Option = [[Option alloc] init];
And this issue can be avoided in future by using self.u1Option or _u1Option.

Related

How to Access instance Variable of one class to another class in objective c?

I had tried accessing value of IVAR of one viewcontroller to another viewcontroller by making use of property , but i am getting null value.
please let me know how to get value displayd in my secondviewcontroller.
You are doing the right way to get value of property. But you need to make sure myString has been assigned a value in init method of ViewController.
Try in ViewController.m:
- (instancetype)init {
self = [super init];
if (self) {
self.myString = #"My String";
}
return self;
}
Beside of it, make sure that myMetod of SecondViewController is called. If myMetod is called, "Print value My String" will be printed.

Using Text Field to add String to NSMutableArray

I am looking to get an NSString value from a Text Field and add it to an array, I want to build an array with many strings in it ex:
[hello, goodbye, too soon].
This is my current solution:
- (IBAction)submitButton:(id)sender {
NSMutableArray *wordArray = [[NSMutableArray alloc] init];
NSString *input = textField.text;
[wordArray insertObject:input atIndex:arrayIndex];
arrayIndex++;
}
This works for the first item in the array, but when I press submit again it reinitializes.My issue is how do I initialize the NSMutableArray to use in the button function, without having it in there so that it doesn't initialize every time. Thank you
Your are using a local array that disappears as soon as the submitButton method is finished.
Make your wordArray an instance variable and initialize it once in viewDidLoad. Then in your submitButton: method (and any others), you reference the instance variable instead of creating local arrays.
Honey's answer is almost, but not, correct.
Your code uses a local variable in your submitButton method, and creates a new, empty array each time the method gets called. Both of those things are wrong.
Honey's answer has you create a different local variable in viewDidLoad. That's also wrong.
You need to make wordArray an instance variable or property of your class. If you class is called ViewController, say, it might look like this
#interface ViewController: UIViewController;
#property (nonatomic, strong) NSMutableArray *wordArray
...
#end
And then initialize it in viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.wordArray = [[NSMutableArray alloc] init];
}
Then in the rest of your program refer to self.wordArray, the property.
Here's the solution,
#implementation ViewController{
NSMutableArray *_wordArray;
}
- (void)viewDidLoad {
[super viewDidLoad];
_wordArray = [[NSMutableArray alloc] init];
}
- (IBAction)submitButton:(id)sender {
NSString *input = textField.text;
[wordArray addObject:input];
}
You was re init the array each time you make the action, which will let you always save the last value of the textfield.
but this creates an array as global variable so that you can add all the values entered in textfield.
Hope this help you :)

NSMutableArray addObject is nil?

I am new to iOS dev,here is my first app-calculator,
But the NSMuteableArray "_numberArrayWaitingForCalculate" always be "nil",I don't know what to do???
Here is the interface
#interface demoViewController ()
#property (strong,nonatomic)NSString *valueString;
#property (strong,nonatomic)NSMutableArray *numberArrayWaitingForCalculate;
#end
here is the implement 1
#implementation demoViewController
#synthesize numberArrayWaitingForCalculate=_numberArrayWaitingForCalculate;
- (NSMutableArray *)numberWaitingForCalculate
{
if(!_numberArrayWaitingForCalculate)
_numberArrayWaitingForCalculate=[[NSMutableArray alloc]init];
return _numberArrayWaitingForCalculate;
}
here is the tapNumber method
- (IBAction)tapNumber:(UIButton *)numberButton {
if(LastButtonWasMode)
{
_valueString=#"";
LastButtonWasMode=NO;
}
NSString *numberAsString = numberButton.currentTitle;
_valueString=[_valueString stringByAppendingString:numberAsString];
result.text=[NSString stringWithFormat:#"%#",_valueString];
}
here is tapPlus method
- (IBAction)tapPlus:(id)sender {
[_numberArrayWaitingForCalculate addObject:[NSNumber numberWithInt:[_valueString intValue]]];
resultOfAllNumberInputBefore +=[_valueString intValue];
[self setMode:1];
}
The following line should be using the property and not the instance variable. i.e. you're not actually calling the getter that allocates the array.
Change this line:
[_numberArrayWaitingForCalculate addObject:[NSNumber numberWithInt:[_valueString intValue]]];
to:
[self.numberArrayWaitingForCalculate addObject:[NSNumber numberWithInt:[_valueString intValue]]];
You created a getter that "lazy loads" the mutable array (meaning that you create it if it doesn't exist already. That's a valid approach.
However, if you do that, you need to ALWAYS use the getter. You're using the iVar directly (_numberArrayWaitingForCalculate). Don't do that. Replace all instances of "_numberArrayWaitingForCalculate" with [self numberArrayWaitingForCalculate] except in the implementation of your getters/setters and probably your dealloc method.
So your tapPlus method should read:
- (IBAction)tapPlus:(id)sender
{
[[self numberArrayWaitingForCalculate] addObject:[NSNumber numberWithInt:[_valueString intValue]]];
resultOfAllNumberInputBefore +=[_valueString intValue];
[self setMode:1];
}
EDIT:
By the way, for something as lightweight as an empty mutable array, I think I would take a different approach. Rather than lazy-loading the array in a getter, I would create an init method for my class that created an empty mutable array and installed it in the iVar.
Objects like view controllers can be initialized more than one way. It might get initialized with initWithNibName:bundle: or with initWithCoder:
What I do in that case is to create a method doInitSetup, and call it from both places.

Trying to store values received in a ViewController and store them in a single instance of an NSMutableArray in another View Controller in iOS

I have an application where A View Controller (A)is called twice in close succession. Now each time it is called, an NSString object is created, and I need this value to be stored in an NSMutableArray that is a public property of ANOTHER View Controller (B).
In A, I create an instance of the second View Controller (B), and using that instance, add the NSString objects into the NSMutableArray which I've created as a public property. Later, when I am inside View Controller B and print the contents of the NSMutableArray property, the array is empty. Why? Here is the code that is inside View Controller A:
-(void)viewDidLoad {
ViewControllerA *aVC = [[ViewControllerA alloc] init];
if (aVC.stringArray == nil) {
aVC.stringArray = [[NSMutableArray alloc] init];
}
[aVC.stringArray addObject:#"hello"];
[aVC.stringArray addObject:#"world"];
for (NSString *wow in aVC.stringArray) {
NSLog(#"The output is: %#", wow);
}
}
Inside my View Controller B class, I have the following code:
- (IBAction)buttonAction:(UIButton *)sender {
NSLog(#"Button selected");
for (NSString *test in self.stringArray) {
NSLog(#"Here are the contents of the array %#", test);
}
}
Now the buttonAction method gets called, as I do see the line Button selected in the system output, but nothing else is printed. Why? One thing I want to ensure is that View Controller A is called twice, which means I would like to see in the output, "Hello World", "Hello World" (i.e. printed twice), and not "Hello World" printed just once.
The other thing I wish to point out is that View Controller B may not be called at all, or it may be called at a later point in time. In any case, whenever View Controller B is called, I would like to have the values inside the array available, and waiting for the user to access. How do I do this?
Your approach is not ideal, potentially leading to a memory cycle, with two objects holding strong pointers to each other.
You can instead achieve your goal in two ways;
Delegate Protocol
This method allows you to set delegates and delegate methods to pass data back and forth between view controllers
in viewControllerA.h
#protocol viewControllerADelegate <NSObject>
- (void)addStringToNSMutableArray:(NSString *)text;
#end
#interface viewControllerA : UIViewController
#property (nonatomic, weak) id <viewControllerADelegate> delegate;
in viewControllerB.m
// create viewControllerA class object
[self.viewControllerA.delegate = self];
- (void)addStringToNSMutableArray:(NSString *)text
{
[self.mutableArray addObject:text];
}
in viewControllerA.m
[self.delegate addStringToNSMutableArray:#"some text"];
Utility Classes
Alternatively you can use a utility class with publicly accessible methods (and temporary data storage). This allows both viewController classes to access a shared data store, also if you use class methods, you don't even need to instantiate the utility class.
in XYZUtilities.h
#import <Foundation/Foundation.h>
#interface XYZUtilities : NSObject
+ (void)addStringToNSMutableArray;
#property (strong, nonatomic) NSMutableArray *array;
#end
in XYZUtilities.m
+ (void)addStringToNSMutableArray
{
NSString *result = #"some text";
[self.array addObject:result];
}
+ (NSArray)getArrayContents
{
return self.array;
}
in viewControllerA.m
NSString *stringFromObject = [XYZUtilities addStringToNSMutableArray];
in viewControllerB.m
self.mutableArray = [[NSMutableArray alloc] initWithArray:[XYZUtilities getArrayContents]];
I'm not sure what kind of a design pattern you are trying to follow but from the looks of it IMHO that's not a very safe one. However, there are many, many ways this could be accomplished.
One thing though, you said that View Controller B may never get allocated and if it is alloc-ed, it will be down the road. So you can't set a value/property on an object that's never been created.
Since you already aren't really following traditional patterns, you could make a static NSMutableArray variable that is declared in the .m of your View Controller B Class and then expose it via class methods.
So it would look like this:
viewControllerB.h
+(void)addStringToPublicArray:(NSString *)string;
viewContrllerB.m
static NSMutableArray *publicStrings = nil;
+(void)addStringToPublicArray:(NSString *)string{
if (publicStrings == nil){
publicStrings = [[NSMutableArray alloc]init];
}
if (string != nil){
[publicStrings addObject:string];
}
}
Then it would be truly public. All instances of view controller B will have access to it. This, of course is not a traditional or recommended way of doing it—I'm sure that you will have many replies pointing that out ;).
Another idea would be to use a singleton class and store the values in there. Then, when or if view controller B is ever created, you can access them from there.

obj-c inherited variables are null

I have a base class which has a custom init method and then uses the value passed in through the init method to then call custom init methods on it's subclasses. problem is When i try to access variables that have had values assigned to them in the base class through the subclass Via super, the values are null, it's like the base class is a completely different object. Is it because the base class has not yet returned from it's init method yet? or am i going about the wrong way with inheritance here? code to follow.
Interface
#interface WTFGameBoard : NSObject
{
#protected
UIView *_answerView;
UIView *_keyboardView;
NSMutableArray* _answerSeperatedByCharacter;
WTFAnswerBoard *_answerBoard;
WTFGameKeyboard *_gameKeyboard;
OpenGameViewController *_weakGameViewRef;
GameInfo *_gameinfo;
}
-(id) initWithGameVC:(OpenGameViewController*)gameVC;
#property (nonatomic,unsafe_unretained)OpenGameViewController *weakGameViewRef;
#property (nonatomic,strong)GameInfo *gameInfo;
#end
Implementation
#implementation WTFGameBoard
#synthesize weakGameViewRef = _weakGameViewRef;
#synthesize gameInfo = _gameinfo;
-(id) initWithGameVC:(OpenGameViewController*)gameVC
{
if (self = [super init])
{
//[weakGameViewRef ]
_answerView = [gameVC answerView];
_keyboardView = [gameVC keyboardView];
self.weakGameViewRef = gameVC;
self.gameInfo = [[CurrentGamesInfo sharedCurrentGamesInfo]_selectedGame];
_answerBoard = [[WTFAnswerBoard alloc] initWithAnswer:[gameVC answer] blankSpaceImageView:[gameVC answerBox]];
_gameKeyboard = [[WTFGameKeyboard alloc] initWithButtons:[gameVC letterSelectButtons]];
}
return self;
}
#end
Interface
#interface WTFAnswerBoard : WTFGameBoard
{
NSMutableArray *WTFAnswerSpaces;
NSMutableArray *_answerBlankBlocks;
NSMutableArray *_answerGiven;
NSMutableArray *_answerBlankOriginalPosition;
NSString *_answer;
}
-(id)initWithAnswer:(NSString*)answer blankSpaceImageView:(UIImageView*)answerBox;
Implementation
-(id)initWithAnswer:(NSString*)answer blankSpaceImageView:(UIImageView*)answerBox
{
if ( self = [super init] )
{
_weakGameViewRef = [super weakGameViewRef];//WHY U NO NOT BE NULL?
_gameinfo = [super gameInfo];//WHY U NO NOT BE NULL?
_answerBlankBlocks = [_weakGameViewRef answerBlankBlocks];
_answerGiven = [_weakGameViewRef answerGiven];
_answerBlankOriginalPosition = [_weakGameViewRef answerBlankOriginalPosition];
[self SetupBlankAnswerSpacesForAnswer:answer withTemplate:answerBox];
}
return self;
}
Problem is the fact that you are not invoking your custom constructor in your derived class:
if ( self = [super init] )
You are calling the default one, which is not overridden, and that doesn't initialize the ivars that you are trying to access.
You should call your custom constructor:
if ( self = [super initWithGameVC:gameVC] )
Of course this means that you need to pass along the parameter, or override the default constructor by initializing what you want to initialize without the need of any parameter.
Another thing that I don't understant is why you are setting ivars of the derived class in your custom class:
_weakGameViewRef = [super weakGameViewRef];
This basically does nothing because the ivar is the same, if you set the one of your base class then you can directly access it.
EDIT
Since you have a strange dependency issue here a quick solution would be to have something like
WTFAnswerBoard initWithWTFGameBoard:(WTFGameBoard*)board {
self.board = board;
}
so that you can access the board that instantiates the WTFAnswerBoard and keep inheritance but switching the usage to composition (by adding a property to WTFAnswerBoard so that your recursive initialization doesn't occur.

Resources