Calling a method from another class WITHOUT creating a new instance - objective-c

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.

Related

ObjC accessing properties within C function

Why can't I access properties of my class from within a C function?
This is what I mean:
This is my code:
#interface MandelGenerator : NSWindow <NSWindowDelegate>
{
//Displays the image
IBOutlet JSImageView *imageView;
}
#end
/
#import "MandelGenerator.h"
#implementation MandelGenerator
void test(void) {
imageView = nil;
}
#end
A C function, unlike the instance method of a class, has no association with an Objective-C class. Just being in the same .m file as the class means nothing -- unlike an instance method, which is called on an instance by means of sending a message to it (thus providing the context necessary to know which imageView of all the imageViews that might exist as properties of instances of MandelGenerators), a C function isn't called on anything and can only "see" global variables and variables that are passed in to it as parameters. If you want this to work, you would need to change that C method to
void test(MandelGenerator* generator) {
generator.imageView = nil;
}
Assuming that imageView is actually a property (it looks like an ivar to me).

Call a method in the class that created the current class?

This one's trickier to explain: I have ClassA which has MethodA, that does some stuff to some objects in ClassA, let's say it sets a couple of labels.
ClassA has also created an instance of ClassB, which is a sidebar view. I need ClassB to perform the same stuff to objects in ClassA as MethodA, updating those labels inside that instance of ClassA.
I need ClassB to be able to call MethodA, but have it act on the specific instance of ClassA that created that instance of ClassB.
The classes (at present at least) do not inherit from one another, since they don't actually share anything yet. I fill some data from ClassA into ClassB's labels, and now I need to do the opposite.
I can't call [super MethodA] from within ClassB, because they don't inherit. What I need is something analogous to a [parent methodA], which would call that method in the class that created this ClassB object, and have it act on that specific instance of ClassA.
Does such a thing exist? Apologies, jumbled post, and I'm not sure what to search for for a vague question like this.
No, if you are using composition then you need an external way to refer to the class the contains the client one.
The easier way to do it would be to pass the parent while instantiating the object:
#interface ClassB {
ClassA *parent;
}
-(id)initWithA:(ClassA*)parent;
#property (readonly, retain) ClassA *parent;
#end
#implementation ClassB
-(id)initWithA:(ClassA*)parent {
if ((self = [super init])) {
self.parent = parent;
}
return self;
}
#end
so that you can have in ClassB:
-(void)method {
[parent updateThings:params];
}
Mind that in this case, since both class declarations are cross referenced you will need a forward declaration (eg. #class ClassA) in header file to make it compile.
You need to create this yourself. The general pattern is to create a listener assignment in your child class, and the "parent" (more generically, the object wanting to receive notification) calls the method you establish to assign a listener. You can allow your child to maintain multiple listeners if you wish, or only a single listener. The listener should implement some protocol that is appropriate for how you plan to pass data.

NSArrayController adding categories

I'm trying to add new categories to the NSArrayController class: it can select the first and the last item. I did so:
#import "NSArrayController+selectEnds.h"
#implementation NSArrayController (selectEnds)
- (void)selectFirst:(id)sender {
if (self.arrangedObjects !=nil){ BOOL ignore = [self setSelectionIndex:0];}
}
- (void)selectLast:(id)sender {
if (self.arrangedObjects !=nil){
NSUInteger lastItem = [self.arrangedObjects count]-1;
BOOL ignore = [self setSelectionIndex:lastItem];}
}
#end
I get no errors, but I would like to put this object in IB, using a blue cube and binding buttons to its "selectFirst" and "selectLast" methods.
But I'm a bit lost: which standard object to start with? A standard ArrayController? And then, which class name to choose to have the new methods listed?
Thanks for your help…
Since you didn't show NSArrayController+selectEnds.h (which is what IB actually looks at), just NSArrayController+selectEnds.m, it's hard to know exactly what you got wrong, but there's two plausible guesses.
First, if you want these new methods to be part of the interface of the class NSArrayController, you have to add them to the interface declaration, not just to the implementation.
Second, if you want Xcode (or IB) to know that these new methods are actions, you have to label them as such: in the interface, instead of marking them plain void methods, mark them IBAction methods. (In the implementation, you can do either; it doesn't matter.)
So, NSArrayController+selectEnds.h should be:
#import <Cocoa/Cocoa.h>
#interface NSArrayController (selectEnds)
- (IBAction)selectFirst:(id)sender;
- (IBAction)selectLast:(id)sender;
#end

Link class properties to UIControls values in Objective-C

basicaly I am a C# developer but started learning Objective-C couple of last days.
Now I have to do an exercise which need to create a class and link instance variables (properties) to the UIControls values of the View (e.g. UITextField string value).
Meaning I have already implemented the desired IBOutlets in the ViewControler and inside this controler I will create an instance of the created class. In C# a class could implement the INotifyPropertyChanged interface, bind the class to the controls and notify the object when the Datasource value has changed.
Is there anything equal to this concept in Objective C? Or how can I achieve something like that, only through events when value changed for every Control?
Thank you.
Your question and grammar is a bit ambiguous but it seems to me what you want is custom (manual) property getters/setters. Try this:
#intrface AClass: NSObject {
int iVar;
}
#property (nonatomic, assign) int iVar;
#end
#implementation AClass
- (int)iVar
{
// notify object of value being read, then:
return iVar;
}
- (void)setIVar:(int)_iVar
{
iVar = _iVar;
// then notify object about property being set
}
#end
Not 100% sure what you're asking for from your question. Are you asking whether the ViewController views can auto-update when your model changes?
There are a bunch of different mechanisms for providing notifications between objects/classes/etc. The main ones are as follows (I've included IBAction which you probably know for completeness):
1) IBAction - For UI controls just as you've connected IBOutlets in your UIViewController class, you can also fire events (touch up/touch down/etc) on user interaction.
2) NSNotification - you can post these pretty much anywhere:
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSNotificationCenter_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003701
3) Key-Value Observing:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i

Load custom class properly

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.