Load custom class properly - objective-c

I have a custom class which I want to "load" inside the firstViewController and then access it from other classes by segues. My Problem is, I can't even access and change the instance variable inside the firstViewController. Somehow I'm "loading" it wrong. Here is the code I used until now:
inside viewController.h
#property (strong, nonatomic) myClass *newClass;
inside viewController.m
#synthesize newClass;
I then try to access it by:
self.newClass.string = #"myString";
if(newClass.string == #"myString"){
NSLog(#"didn't work");
}
Well, I get "didn't work". Why is that?
When I write
myClass *newClass = [myClass new];
It does work. But the class and its properties gets overwritten every time the ViewController loads again.
What would you recommend? Thank you very much.

Like Kaan said, you forgot to initialize your class, You have only declared and created a pointer for it but not the actual object, on your ViewDidLoad add
self.newClass = [[myClass alloc] init];
It does work. But the class and its properties gets overwritten every
time the ViewController loads again.
That's because every time that specific Viewcontroller loads you are reinitializing the class.
If you want a persistent class through all your program look for the singleton pattern.
This is used in the case when you want to have only 1 instance of a certain object, if you try to initialize another instance of that object you will just receive the one you already have.
PD: newClass.string == #"myString" is wrong.
Use the isEqualToString method when comparing strings.

Related

Using an allocated and initialised object outside of viewDidLoad?

I hope the question title is adequate
Just confused about something in a piece of code I have seen in an online tutorial. There is a generic ZHEDog class with declared properties, methods, etc. and from this class we have created several instances - firstDog, secondDog, fourthDog, and so on.
Now, when we created each instance we did so inside of the viewDidLoad method of our main(one)view controller with the line:
ZHEDog *fourthDog = [[ZHEDog alloc] init];
and then we set some of its properties like name, and so on, here after this line.
So we did this instance creation in the view controller's viewDidLoad and so far have not subclassed the generic ZHEDog class, so it is all deriving from the one class file.
Now, where I am confused is that apparently I cannot set a property of this instance in another method (other than viewDidLoad), so I can't say something like:
-(void) printHelloWorld
{
fourthDog.name = "something new";
}
It kind of makes sense but I can't explain why. I would have thought once the instance was allocated and initialised I could change its properties where I wanted to if necessary? But do the same rules of scope apply to viewDidLoad?
Use properties, they are like instance variables accessible from everywhere within the instance of the class
#property ZHEDog *firstDog, *fourthDog;
then instantiate them in viewDidLoad
self.firstDog = [[ZHEDog alloc] init];
self.fourthDog = [[ZHEDog alloc] init];
and change them in a method
-(void) printHelloWorld
{
self.firstDog.name = "woof";
self.fourthDog.name = "something new";
}
What #vadian has is correct, but using properties also allows other classes to see this variable. Say if you imported the header file and it contained #property ZHEDog *firstDog, *fourthDog;. These variables become public. unless they're in the implantation file.
But other approach is creating variables like so:
Header File
#interface ViewController : UIViewController {
ZHEDog *firstDog, *fourthDog;
}
#end
All will be the same expect now the values are private, or exclusive, to just the ViewController. therefore not allowing others to use or see these variables. And to access the variables in your function printHelloWorld:
- (void)printHelloWorld {
firstDog.name = #"woof";
fourthDog.name = #"something new";
}
Allocating
- (void)viewDidLoad {
//new is the combination of alloc and init. only use +new when using alloc and init, not alloc and initWith...
firstDog = [ZHEDog new];
fourthDog = [ZHEDog new];
}
i hope this would better your goal :)

Why is my array property being discarded after method execution?

Edit: the first answer has guessed it is because I am not using a protocol to "pass data backwards." I am currently implementing that and we'll see if it fixes it.
I'm very new to iOS/objective-C. I have this property on my class:
#interface GameController
#property (strong, nonatomic) NSMutableArray* targets;
#end
I was then using addObject on the array in the body of one of the GameController methods, and it didn't throw any errors, so I thought it was okay until I checked [_targets count] at the end of that method and found it was zero. So I initialized it at the beginning of that method:
if(self.targets == nil){
self.targets = [[NSMutableArray alloc] init];
}
And then count was 6. But as soon as I go to read self.targets in a different method, it's back to zero. Why is that happening? What am I doing wrong with initializing this?
Edit: Interestingly, in the other method, if I check, it is no longer nil-- it has been initialized. But it is nonetheless empty. Very confused!
Edit2: Okay, I've uploaded the code to pastebin, having cut out irrelevant stuff as much as possible.
So drawMainControls gets called first, when the app loads, and it draws a bunch of TileViews and TargetViews, instantiating self.targets in the process. Each TileView has a GameController property which is assigned to be the main GameController immediately after instantiation.
The TileView detects taps and calls addPossibleLetter on its controller. addPossibleLetter is the method that checks the self.targets array and comes up empty-handed.
Here is the GameController.h file: http://pastebin.com/C30Mi2LL
Here is the GameController.m file: http://pastebin.com/cvf2WmBs
Here is the TileView.m file: http://pastebin.com/gehJGYBD
There are fair chances that you are calling the other method before the method in which this method is being initialized.
I guess when passing data backward the way you are doing you are properly aware of using protocols and delegates. You can have look at his link which explains this concept very clearly. Passing Data between View Controllers

Calling a method from another class WITHOUT creating a new instance

This is a common topic but, in my case there is one thing I don't understand that I can't find explained in the other asked questions.
Here is the gist of what I'm trying to do:
User clicks a button and something like this is called:
#implementation FirstClass
-(void)clickedButton
{
[SecondClass changeText];
}
And then in SecondClass is:
#implementation SecondClass
- (void)changeText {
[myLabel setText:#"text"];
}
So when the user clicks the button, the text property in myLabel in SecondClass changes to "text".
The only problem I have with this is calling [SecondClass changeText] on the existing instance of SecondClass. Since I'm not initializing the CCNodes programmatically (they are all automatically loaded upon running the app), I don't know where or how SecondClass is initialized. I'm using SpriteBuilder to build this project.
Any help would be appreciated. Thanks!
So, you have two instaces -- one with a button, and one with a label. I'm assuming they are both descendants of NSViewController or otherwise manage underlying views.
The problem is, you found no way to address second instance containing label from the method of first instance.
You need to define a property in first instance's class:
#property(weak) SecondClass *secondInstance;
And then in button clicked method:
-(void)clickedButton
{
[self.secondInstance changeText];
}
There is one issue left: who is responsible to set first instance's property that we defined? This depends on who did create both of them, probably just app delegate or enclosing controller, you know that better.
UPD: If both of the controllers are created by AppDelegate:
#import "FirstClass.h"
#import "SecondClass.h"
#interface AppDelegate ()
// case A - manual
#property(strong) FirstClass *firstInstance;
#property(strong) SecondClass *secondInstance;
// case B - declared in xib
//#property(weak) IBOutlet FirstClass *firstInstance;
//#property(weak) IBOutlet SecondClass *secondInstance;
#end
#implementation AppDelegate
...
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
// Create them
self.firstInstance = [[FirstClass alloc] init...];
self.secondInstance = [[SecondClass alloc] init...];
// Or maybe they are declared in MainMenu.xib, then you do not create them
// by hand, but must have outlets for both. See case B above.
// Connect them
self.firstInstance.secondInstance = self.secondInstance;
...
}
Note that class is not the same as an object (instance). Class is a named collection of methods, mostly for the instance. In Objective-C, class is not just a name, but an object too, so you can call a method on it (i.e. send an message to the class object). But here we always talk about objects (instances), so forget about classes – we hold objects via strong properties or weak outlets, depending on how they were created, and operate on objects, never on classes.
In objective C, the methods are either instance methods or class methods. As the name suggests, the instance methods require an instance of the class to work, whereas the class methods can be used with just the name of the class. What you need here is a class method. Just change the following line in your code:
#implementation SecondClass
- (id)changeText {
to
#implementation SecondClass
+ (id)changeText {
This will change the method from an instance method to a class method.

Access another classes properties, returning 0

still having problems!
I have 2 classes, and i want to access the properties of one class from the other.
I have a class called MenuViewController, which is a Facebook styled popout menu, and depending on which cell is selected, i want to load different data.
I have created a property:
#property int rowSelected;
and synthesized it:
#synthesize rowSelected;
and in my other class, i have created an instance of the class:
MenuViewController *menu = [[MenuViewController alloc] init];
NSInteger rowValue = menu.rowSelected;
and when i NSLog it, it always returns 0...
NSLog(#"%i", menu.rowSelected);
Help is much appreciated!
The call to alloc creates a new MenuViewController instance. Unless you set a value for your property in its init method, then you should expect it to be 0.

Unable to access App Delegate property

I'm trying to access a property in my app delegate from another class (something I thought would be rather simply) but I'm having troubles in doing so. My files currently look like this:
LTAppDelegate.h
#import <Cocoa/Cocoa.h>
#import "Subject.h"
#interface LTAppDelegate : NSObject <NSApplicationDelegate, NSOutlineViewDelegate, NSOutlineViewDataSource, NSMenuDelegate> {
}
#property Subject *selectedSubject;
#end
LTAppDelegate.m
#synthesize selectedSubject;
The value for selectedSubject is then set inside applicationDidFinishLaunchingin LTAppDelegate.m. Now I'm wanting to get access to this from another class that I have, which is called LTTableViewController and is setup like so:
LTTableViewController.h
#import <Foundation/Foundation.h>
#import "LTAppDelegate.h"
#import "Subject.h"
#import "Note.h"
#interface LTTableViewController : NSObject{
NSMutableArray *notesArray;
LTAppDelegate *appDelegate;
Subject *s;
}
-(IBAction)currentSubjectDetails:(id)sender;
#end
LTTableViewController.m
#import "LTTableViewController.h"
#implementation LTTableViewController
- (id)init
{
self = [super init];
if (self) {
appDelegate = ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]);
s = [appDelegate selectedSubject];
NSLog(#"Test Subject: %#", [s title]);
}
return self;
}
-(IBAction)currentSubjectDetails:(id)sender{
NSLog(#"Selected Subject: %#", [s title]);
}
After inserting various NSLog() messages it would appear that the init method of LTTableViewController is called before applicationDidFinishLaunchingis called in LTAppDelegate. Based on that it makes sense that the "Test Subject" NSLog() in LTTableViewController.m init displays null; however, the 'currentSubjectDetails' method is linked to a button on the interface and when that is pressed after the app is finished loading, the NSLog() message still returns null.
Is there anything obvious I'm missing here. I feel like I'm being a little stupid and missing something really basic.
Similar issue is described here http://iphonedevsdk.com/forum/iphone-sdk-development/11537-viewcontroller-called-before-applicationdidfinishlaunching.html Adding this kind of functionality in the constructor is usually not recommended. Generally, I'd suggest using parameters and not relying on hidden dependencies as those will necessarily depend on the order of execution and you lose the help of the compiler to avoid invalid values. View controller initializers should not be used to store mutable references since view controllers are initialized automatically by predefined constructors, and you cannot pass parameters to them this way.
If you need to access the app delegate, then obtain it, perform operations on it and drop the reference. Try not to cache it, you'll very likely introduce hidden issues. I suggest you hook into the appear-disappear cycle if the viewed contents depend on any kind of current state.
Well, s does not exist, since it is set to null in init, so -currentSubjectDetails prints null. It is not a good idea to set your private variables in the constructor if they depend on other objects.
Rather, let the other objects explicitly tell your controller that it should use that Subject (e.g., treat s as a property).
Or, just query ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]); every time.
-applicationDidFinishLaunching called when e.g. all nib's object initialized, so launching will be ended after construction of views related stuff. This means that constructors of nib's objects wouldn't use any other nib's objects (your delegate and controller initializing with nib, right?).
Try to use -awakeFromNib instead of constructors, I think it will called after construction of both objects.
If you are trying to avoid often calls of ((LTAppDelegate *)[[NSApplication sharedApplication] delegate]) I'll recommend to pass it as method parameter, in function stack. Cyclic references defense and some flexibility.