Like the titles says, I want to specify the super of an NSArrayController, something along the lines of self = [super[NSArrayController] function], but have had no luck searching for this. Any ideas? Thanks in advance.
Edited to remove abstract examples as they're confusing people as to the nature of my question.
The purpose of this is to programmatically do what a simple binding of 'add' from an NSArrayController to an NSButton would do in IB. There are several arrayControllers in my application so I want to be able to specify which one I want to obtain the super of by code.
The reason I am looking for the super of an NSArrayController is because I am under the impression that one should address the model rather than the controller (NSArrayController) and my model is a Core Data model that I believe I could get to by using the super of an NSArrayController I specify by name. Perhaps there is a more direct way of adding to the data model.
You're asking a wrong question.
First, let's distinguish a class and an instance of the class. Note that there can be, and indeed often are, multiple instances of the same class.
A class C can be a subclass of another class A. Then A is the superclass of C. Suppose you have an instance c of the class C. Then, in the implementation of the methods of the class C, self stands for the instance of c itself, and super stands for the instance of c as an instance of its superclass A. In a sense, an instance of the class C is also an instance of the class A.
Objects can have other relationships than being super or subclasses. For example, a class C can have in its interface an instance variable B* b; In this case, an instance c of the class C has a pointer to an instance b of the class B. In this case, c is not an instance of the class B.
The relationship between NSArrayController and the managed object context is one of the latter. An instance of NSArrayController contains a pointer to an instance of NSManagedObjectContext (moc).
So what you want to do is not to get the super of your NSArrayController. Instead, you want to get the moc associated to the NSArrayController. Now, how do you get it? To find it out, you open the reference in XCode or on the web at the Apple Developer Connection, see here. Do that right now. Go through the methods. You don't find one giving you the moc.
Then, you go to the top of that page, and follow the superclass of NSArrayController. See this reference of NSObjectController. Now, go through the list of the methods. You find -[NSObjectController managedObjectContext], which does the job!
In conclusion: if you want the moc associated to the NSArrayController, you just need to do
NSManagedObjectContext* moc= [arrayController managedObjectContext];
where arrayController is the instance of the NSArrayController you want to deal with. e.g. If you have multiple instances of NSArrayControllers in the nib, you should have multiple IBOutlets in the app delegate, say, arrayController1, arrayController2, etc. (which are very bad variable names). Then you choose the one you want to deal with.
Related
I am having a lot of repeated code throughout my app classes given that some properties & method are stable across all my views.
I am looking to extend whatever class I am working with so that it automatically inherit all properties and methods that I think should be common to those classes.
I looked into the apple guide on extending classes. But I am left confused in the terms of the level of heritance that I can achieve.
I've successfully created Categories on lets say a UIViewController. But that limits me to only be able to declare Methods. I can not declare Properties on my Category and call them in side my Category or in the Extended Class. I want to be able to declare Properties and use it inside and outside my Extended-Class.
Its my first time trying to extend a class in objective-c taking full advantage of heritance but I do not know if it is possible. Am I missing something?
As an example in the code below every time I try to instantiate activityIndicatorView inside my method _activityIndicator it wouldn't recognise it. I've tried #syntetize and #dynamic but it doesn't work
NOTE: I am seeking an answer based on how to achieve heritance of methods and propeties. not highlighting what categories cant do (as I already tried and know I cant have properties there)
My attempt went as far of
#import <UIKit/UIKit.h>
#interface UIViewController (customViewController1)
#property (strong, nonatomic) UIView *activityIndicatorView;
- (void) _activityIndicator;
#end
#import "UIViewController+customViewController1.h"
#implementation UIViewController (customViewController1)
- (void) _activityIndicator {
//......
}
Your question is too broad, plus it is not clear what your problem is. Yes, you can subclass in Objective-C.
This is all very well documented in Apple's document "Object-Oriented Programming with Objective-C", section "The Object Model", subsection "Inheritance".
Categories are a nice way to add functionality while at the same time conforming to an object oriented principle to prefer composition over inheritance.
Categories only add methods, you can't add variables to a class using categories. If the class needs more properties, then it has to be subclassed.
When you use the term “extend”, you're talking about creating a subclass. This is, IIRC, how the term is used in Java and some other languages.
Apple uses the term differently (as Hermann Klecker hinted in his first comment). They literally mean extending an existing class with more functionality (in the form of methods)—that's what categories do. This is the normal English definition; extending something in the real world generally does not create a new thing.
Objective-C supports subclasses, too; it just doesn't call them “extending” the superclass. It's called creating a subclass, which inherits from the superclass.
Strctly spoken you cannot add a property to an existing class any differnt than creating a subclass.
If you cannot halp yourself and subclassing is not an option, then you can extend the class with getters and setters for the property that you want to store within the class.
Instead of really storing it as a member/instance variable/property, which you can't do, you could store the object (it cannto be a scalar, must be an object) in the global space using objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy).
This is some sort of global dictionary with two keys, the key itself and the ojbect to which you want to associat the stored object to. In your case that is the object of the type of the exended class. The setter stores it there and the getter receives it from there using objc_getAssociatedObject.
You delete an association by sending nil as value to objc_setAssociatedObject
AFAIK retained associated objects (values) are released shortly after the object that holds the associateion (object) is deallocated.
For further details see the Ojbective-C Runtime Reference https://developer.apple.com/library/ios/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
Just: I do not say that this is strictly following the OO paradigm. :-)
I don't think that what I want to do is possible, but there are people here that are more cunning than myself, so I thought I'd ask anyway....
Imagine we have a class A:
#interface A
#property (strong) NSArray *items;
// There'll be methods and stuff too
#end
Now, we need a drop in replacement for this class to change some behavioral aspects:
#interface B : A
#property (strong) NSArray *items;
// There'll be methods and stuff too
#end
In particular, we override the "items" property since we need it to return something different.
That works well until a method called on an instance of B, which is implemented in A and not overridden by B, tries to access "self.items". Rather than access it's own copy, it accesses B's overridden version and thus sees unexpected results - and indeed crashes the app in my real case :(
I can solve this by renaming the property in B - but then this is no longer a drop in replacement, and that's a shame.
Note that class B can access A's version of the property via super. Ideally any access to the property from class A would also access A's version of it. Any suggestions? In my getter is there a way to know who's requesting it, for example?
Tim
You can technically achieve what you want, but in a horrid round-about hack. Put this sort of thing into your production code at your own peril and don't expect any sympathy if it all falls apart.
Don't make B a subclass of A, make it merely a class that has an A. Implement those methods on B that you would otherwise have replaced in the subclass anyway. For dealing with items, make sure that B's setItems: makes an appropriate corresponding call to A — indeed make that the case for all methods you override but which you wish would also communicate something to A.
Then create a class C which has a B and an A. Don't implement anything on it. Follow the normal convention that alloc and init return (id) and perform the slightly odd task of:
A *instance = [[C alloc] init];
On C implement only your preferred forwarding logic:
#implementation C
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if([self.instanceOfB respondsToSelector:aSelector]) return self.instanceOfB;
return self.instanceOfA.
}
#end
Now every references A makes to self is a reference to an instance of A rather than a subclass. Nevertheless you have an instance of B in the system and it will act as though it inherits from A by getting any messages that the relevant instance of A would have serviced in preference to it, while being able to defer whatever it wants to up to A.
By giving those classes that would have had an instance of A an instance of C, they'll go through your unique inheritance logic rather than the default stuff. Furthermore, because you've returned (id) in the appropriate place and both are objects, it's a safe implicit cast and the compiler won't complain that you keep calling methods on C that aren't implemented.
Your question is quite confusing, but anyway...
Overriding a method/property doesn't change it globally; it changes it only for the class which does the overriding. If an instance of A accesses the property, it would still access its own property, it won't be magically taken over by the subclass' implementation.
(By the way, let me mention that your class is probably very badly designed if you need such a behavior...)
Hmm, well overriding the property in B means that any accessors in B will access the new property in B. The behavior of A remains unchanged, accessors in A will always access the original property in A. A class can not and should never be aware of it's sublasses.
If you want the subclass to continue to accesss the super classes property you can't override it. Period.
Also note that a property (or an accessor to it) must be declared in the interface (fundamentaly making it public) for its copy to be directly accessible in subclasses. That's necessary since there is no such thing as a 'protected property' in Objective-C.
Lastly let's say you put classes of type A, B or even C in a bag and then forget their types, just know that all share an is-a relationship, then you can use dynamic binding / introspection to decide which class's method will get called based on it's type.
I have a custom ViewController class and many instances of it, and I want them all to be able to message the same Model (another custom class, only one instance). Passing pointers to the Model along to new instances of the ViewController seems impractical, especially since the model is lazily instantiated. What is the cleanest, most idiomatic, ARC way to do this?
Usually a singleton in ObjC will have a class method that serves as an accessor for the single instance. The convention is for this to be called either defaultX or sharedX. If your model class is indeed a singleton, you should already have such a method. Since class names are globally available, all you have to do to access the instance anywhere in your program is [MyModelClass sharedModel].
I have done this successfully many times before, but this time it just won't work.
The code in my .h file:
#interface Images : NSView {
}
- (void) draw;
#end
The .m file (of another object):
- (IBAction) go: (id) sender; {
[Images draw:nil];
}
When I try to compile this, it says the following:
'*' may not respond to '*
Images may not respond to '+draw'
This has me quite confused. Shouldn't this be working?
Please Note: Yes, I have seen the other questions about messages, but none of those answers was even partially helpful for me. After reading them, I was even more confused.
Your draw method is an instance method: it can only be called on instances of the Images class. In your go: method you're trying to call it as a class method—if this is what you want, change it to:
#interface Images : NSView
+ (void)draw;
#end
I think a review of some of the basic concepts of object-oriented programming is in order; namely the difference between a class and an object or instance.
A class, in the general sense, is a collection of data and the functions which act upon it. A class defines the interface that one uses to access and manipulate data that is logically grouped together, and serves as a blueprint for creating objects or instances. See http://en.wikipedia.org/wiki/Class_(computer_programming)
Instances of a class (objects) are the typical things you manipulate in an object-oriented program, and they are created from the class "blueprint" and follow the behavior as specified by the class.
A typical example would be a fruit- take apples for example. An imaginary Apple class would represent all apples in the general sense and would model properties such as color and size and actions such as wash and eat. An instance would represent one, single physical apple- a Granny Smith or Pippin or whatever variety.
Just as it doesn't make sense to wash or eat apples in the general sense of the word (the concept of apples, not the agglomeration), typically it doesn't make sense to tell a class what to do. You tell objects (individual apples) what to do.
The code you present above defines the class Images. The "-" in front of -(void)draw indicates that the draw method only exists for specific objects. It is an instance method in typical OO parlance.
Of course, in Obj-C it is also possible to send a message to a class without requiring an object. This is denoted by a "+" in front of the method name, as other answers indicate. This is called a static method and it typically used to control some shared behavior or aspect of all objects of that particular class.
The problem with your code is that you are declaring -(void)draw as an instance method but calling it as a static method. Which way you want to do things is up to you, and it's difficult to determine from your code what the intent of the Images class is.
I have trouble understanding Cocoa Bindings. Can someone explain me what this is all about, in an way that is humanly perceivable?
Bindings is a system for connecting your views to your controllers without writing a lot of glue code to make them explicitly talk to each other. All you have to do is set up properties in both classes* and hook up the binding in IB.
The traditional approach is that the view has one or more outlets to talk to the controller (the most generic examples being delegate and target) and the controller has outlets to talk to the views. When the controller updates the model, it sends (for example) [view modelChange:newModelObject]. When the view wants to update the model, it sends some delegate message to its delegate (the controller), such as NSText's textDidChange:.
With Bindings, all you have to do in code is implement properties on the view and properties on the controller, then expose one or more properties of the view as bindings*. Then you only need to hook up the binding. If it's a Cocoa class, this is cake: just set it up in IB. If it's a custom class of your own, you'll probably write the bind:toObject:withKeyPath:options: message yourself (not much harder).
Let me restate that: With Bindings, your entire glue code (most of the time) is [view bind:#"viewProperty" toObject:self withKeyPath:#"controllerProperty.modelProperty" options:options]; in the controller. Everything else is handled by the Bindings and KVO systems behind the scenes, and by your properties' accessors.
The disadvantage is that you must strictly conform to Cocoa Bindings' requirements. These are simple, but a lot of older applications are designed in a way that doesn't fit Cocoa Bindings.
You must create real model objects, not just pass primitive objects (e.g., arrays of dictionaries) around. If you're using Core Data, this is easy: your managed objects are model objects.
You must either write your accessors correctly or synthesize the correct accessors. For example, an NSString property should always be #property(copy), never #property(retain) (because otherwise, you will find yourself retaining someone else's mutable string, which they will then mutate while you're holding it).
You must only change properties of your model objects by their properties (model.foo = bar) or by accessor messages ([model setFoo:bar]), never by direct instance variable access. (Obvious exception for accessor methods themselves, if you've written your own, because they must access the instance variable directly.)
There are two advantages:
You can write a brand new view class without having to rip out a lot of glue code. The most you'll have to delete is some bind:::: messages for the old view's properties. If, a couple of years down the road, you decide that your current view just can't scale to your application's forthcoming capabilities, this gives you the flexibility to rip it out and start afresh with the minimum of pain.
More importantly, the less code you have to read, the easier it is to read it.
*And, according to the documentation, implement a KVO observation method in the view class, but I've never actually had to do this. I filed a documentation bug.
Added 2009-03-07: Ah, found a citation. “NSView subclasses can expose additional key-value-coding/key-value-observing compliant properties as bindings by calling the class method exposeBinding: for each of the properties.” —NSKeyValueBindingCreation So you shouldn't need to implement a KVO observation method.
Previous answer is very comperhensive and good, I'd just thought I'd add an answer explains what it is at its core without involving Cocoa or Objective-C specifically. That is because the concept itself is language agnostic although dynamic languages like Objective-C makes it a lot easier than more static language like C++.
Example
Say you have two objects M and V. M has methods:
setX(int x);
setY(int y);
int getX();
int getY();
While V has methods:
setA(int x);
setB(int y);
int getA();
int getB();
One way of looking at this is that M has properties x and y and V has properties a and b. You want a change of property x to cause a change in property b and a change in y to cause a change in a.
By change in property x we mean e.g.:
M.setX(10)
where previously
M.getX() != 10
So we want a call of setX on M to cause a call to setA on V.
What bindings allow you to say is that property b on object V is bound to property x on object M. And then this updating is handled automatically. You as a coder don't have to write code that checks if x is changed and then call setB on V. Bindings takes care of this automatically.
Summary
Bindings allows you to bind two properties together that exist on two different objects, so that changing the value of one of the properties causes the dependant property in the other object to change to the same value.