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.
Related
When a class of properties (let's call it class_X) is being instantiated from another class, all of class_X's methods and functions are also included in every instance.
Q1: Wouldn't that add substantial overheads, especially if there are multiple instances of that class?
The class instance (class_X) could then be passed to other methods and functions in other classes as a parameter.
Q2: Is it safe to pass it as a parameter to a C-style function (let's call it function_C) which resides in the same class (function_C resides in class_X)?
Thanks in advance.
UPDATE: Here's some code to illustrate:
class_X header:
//class_X.h
#interface class_X : NSObject
#property (nonatomic, assign) NSInteger intProp;
#property (nonatomic, strong) NSArray *arrProp;
void function_C (class_X *cx);
#end
class_X implementation:
//class_X.m
#import "class_X.h"
#implementation class_X
void function_C (class_X *cx)
{
//code...
}
#end
instantiating class_X:
#implementation someOtherViewController
- (void) viewDidLoad {
[super viewDidLoad];
class_X *cx = [[class_X alloc] init];
cx.intProp = 123;
cx.arrProp = #[#"one", #"two", #"three"];
function_C (cx); //does this not cause some sort of recursion?
}
#end
To have some naming conventions: "class instances" is akin of ambiguous. There are
instances (or instance objects) having a class.
classes, akin of type for an instance object.
class objects
So I assume that you want to use "instance objects of class X", when you write "class instances".
To your Q:
No, there is no overhead. Objective-C is a class-based programming language in contrast to JS that is prototype-based. That has the consequence that every instance has all instance methods that are declared as instance methods by the class. Therefore they are stored only a single time for all instances. The memory footprint for the methods does not depend on the number of instances are created. It is a one-timer. (The memory footprint for properties depends heavily on the number of instances.)
It is completely safe to pass references to instances to a function. Moreover the function can be defined everywhere. Of course, it has to see the interface of the class f the passed instance, probably via an import.
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.
I have kind of an abstract class for my UIViewControllers (lets call it MyViewController) which overrides some basic methods like viewDidLoad or viewDidDisappear. In this methods some preparations are made, like setting up colors for the navigation bar, or preparing the bar buttons or something like that.
Now I want this basic behaviour for my UITableViewControllers also. So I made a new class that inherits UITableViewController (lets call it MyTableViewController) and copied 99% of the code from MyViewController.
In this image you see my current architecture. Listed are the overriden methods, in which other private methods are called. Again, MyViewController and MyTableViewController share 99% codebase (only difference is the name of the class and the super class).
For obvious reasons this is crap.
Is there an elegant solution to make MyTableViewController a subclass of both MyViewController and UITableViewController?
This is one suggestion, but I don't know how useful it is because I don't know your code.
You could implement a bunch of methods in a category for the UIViewcontroller class. For example:
#implementation UIViewController (myCategory)
- (void)setupColors;
...
#end
Since both MyViewcontroller and MyTableViewcontroller inherit from UIViewController, they would inherit your methods.
The only thing that you would copy in both implementation is the invocation of those functions, but the duplicate code would be much less.
- viewDidLoad...
{
[self setupColors];
}
Just be careful if you override methods, because you can't call [super ... ] on a category as you can in an inherited class
Shared implementation for your common methods could be done either with a category or with composition. Since a category can't be used to directly override existing interface (e.g. viewDidLoad:) you would need to put your private methods into the category and call them from your subclass overrides. Another option would be to put your shared implementation in a separate class (which might be a singleton) and compose an instance of that as a property of both MyViewController and MyTableViewController, e.g.:
#interface MyViewController : UIViewController
#property (nonatomic, strong) MyControllerStyler *controllerStyler;
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
[controllerStyler viewDidLoad];
}
...etc...
The composed class's methods could reference the controller if needed, e.g.:
#interface MyControllerStyler : NSObject
- (void)viewDidLoadInController: (UIViewController *)controller;
...etc...
While a category seems perfectly fine for this example, if your extensions collectively represent a meaningful unit of your design (such as a collection of visual styling attributes) that might argue for a separate object (or objects) to better represent your intent.
I have a class that essentially acts as a light weight wrapper class around another class. It holds that other class as an iVar. I want to be able to expose certain properties (quite a few actually) of the iVar, but to do so I have to write out each property accessor like so:
- (void) setProperty:(Class *)value{
_iVar.property = value;
}
- (Class *) property{
return _iVar.property;
}
Of course, I have to do this for every single property, which is a pain (there are about 30 of them). I would love to be able to synthesize this but I haven't been able to figure out how.
Is it possible to synthesize?
Also, I can't subclass....well, I might be able to but it's really not recommended. The iVar class is really quite heavy (it implements CoreText). I'd rather write out the methods by hand.
Ok, so here's the solution I found...ended up being pretty simple once you knew what to do. First overwrite '- (id) forwardingTargetForSelector:(SEL)aSelector' and return the iVar:
- (id) forwardingTargetForSelector:(SEL)aSelector{
return iVar;
}
When the runtime is looking for a method and cannot find one, it will call this method to see if there is another object to forward the message to. Note that this method normally returns nil and if you return nil here, your program will crash (which is the appropriate behavior).
The second part of the problem is to shush the compiler errors/warnings you'll get when you try to send a message that's not declared. This is easily done by declaring a category you don't implement.
#interface Class (iVarClassMethods)
#propoperty (strong) Class *property1;
......more properties
#end
As long as you don't put in an implementation anywhere, aka #implementation Class (category), the compiler won't complain (it'll assume that the implementation is somewhere....).
Now the only drawback I see is if you change any of the properties in the interface of the iVar Class, you need to make sure you update all other classes that use the method described above, otherwise you'll crash when another class tries to send what is now the wrong method (and the compiler won't warn you beforehand). However, this can be gotten around. You can declare protocols in a category. So instead you create a separate protocol for the iVar class and move the methods/properties you wish out of the iVar class into the protocol.
#protocol iVarClassProtocol
#propoperty (strong) Class *property1;
......more properties
#end
Add that protocol to the iVar subclass so it has those methods declared through the protocol now.
#interface iVarClass <iVarClassProtocol>
....other methods/properties you don't need forwarded
#end
Finally, simply add the protocol to the category. So instead of the aforementioned category with explicit declarations you'll have:
#interface Class (iVarClassMethods) <iVarClassProtocol>
#end
Now, if you need to change any of the to-be-fowarded properties/methods, you change them in the protocol. The compiler will then warn you when you try to send the wrong method to the forwarding class.
I think you can forward the messages to the ivar:
- (void) forwardInvocation: (NSInvocation*) invocation
{
[invocation invokeWithTarget:ivar];
}
- (NSMethodSignature*) methodSignatureForSelector: (SEL) selector
{
NSMethodSignature *our = [super methodSignatureForSelector:selector];
NSMethodSignature *ivars = [ivar methodSignatureForSelector:selector];
return our ? our : ivars;
}
Then you have to hide or fake the type of your object, for example by casting to id, otherwise the compiler will complain that your class does not implement those methods.
Of course it would be best if you could come up with some better design that would do without such tricks.
I have two classes, named Parent and Child, as below. Parent is the superclass of Child I can call a method of the superclass from its subclass by using the keyword super. Is it possible to call a method of subclass from its superclass?
Child.h
#import <Foundation/Foundation.h>
#import "Parent.h"
#interface Child : Parent {
}
- (void) methodOfChild;
#end
Child.m
#import "Child.h"
#implementation Child
- (void) methodOfChild {
NSLog(#"I'm child");
}
#end
Parent.h:
#import <Foundation/Foundation.h>
#interface Parent : NSObject {
}
- (void) methodOfParent;
#end
Parent.m:
#import "Parent.h"
#implementation Parent
- (void) methodOfParent {
//How to call Child's methodOfChild here?
}
#end
Import "Parent.h" in app delegate's .m file header.
App delegate's application:didFinishLaunchingWithOptions: method..
Parent *parent = [ [Parent alloc] init];
[parent methodOfParent];
[parent release];
You can, as Objective C method dispatch is all dynamic. Just call it with [self methodOfChild], which will probably generate a compiler warning (which you can silence by casting self to id).
But, for the love of goodness, don't do it. Parents are supposed to provide for their children, not the children for their parents. A parent knowing about a sub-classes new methods is a huge design issue, creating a strong coupling the wrong way up the inheritance chain. If the parent needs it, why isn't it a method on the parent?
Technically you can do it. But I suggest you to alter your design. You can declare a protocol and make your child class adopt that protocol. Then you can have to check whether the child adopts that protocol from the super class and call the method from the super class.
You could use this:
Parent.m
#import "Parent.h"
#implementation Parent
- (void) methodOfChild {
// this should be override by child classes
NSAssert(NO, #"This is an abstract method and should be overridden");
}
#end
The parent knows about the child and child has a choice on how to implement the function.
super means "invoke a method dispatching on the parent class", so can use super in the subclass because a subclass only has one parent class. A class can have many _sub_classes though, so how would you know which method implementation to call, in the general case? (Hence there is no such thing as a sub keyword.)
However, in your example you have two separate methods. There's nothing stopping you (assuming you have very good reasons for doing something like this!) from saying, in the parent,
- (void) methodOfParent {
[self methodOfChild];
}
if your super has multiple subs then go for this one for the specific
sub's method
if ([super isKindOfClass:[specificsub class]]) {
[specificsub methodName];
}
if your super is dealing with that object (that sub) so sub's method
loggedin will be called an other way is in you super class
super *some = [[sub alloc] init];
[some methodName];
This can be done by over riding the method in subclass. That is create a method in parent class and over ride the same in subclass.