NSArrayController adding categories - objective-c

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

Related

extend class in objective-c with variable based property [duplicate]

This question already has answers here:
Objective-C: Property / instance variable in category
(6 answers)
Closed 2 years ago.
I've got a form implementation in objective-c and I'd like to extend my widgets (NSButton, NSTextField, etc..) to contain additional string representing their unique identifier string to be used after submit event occur, which trigger generation of json contain all widget id/value pairs.
I've tried using categories to extend NSControl which is the common parent of all those widgets in the following way.
NSControl+formItemSupport.h
-------------------------------
#interface NSControl (formItemSupport)
#property NSString * formItemId;
#end
NSControl+formItemSupport.m
-------------------------------
#implementation NSControl (formItemSupport)
-(NSString *)formItemId {
return self.formItemId;
}
-(void)setFormItemId:(NSString *)formItemId {
self.formItemId = formItemId;
}
in the form.m file I import from NSControl+formItemSupport.m but when I try to set this field in NSButton : NSControl object. However, when I try to set the property formItemId, I get into infinite loop. Perhaps there's another way for extending objc class with variable based property without using inheritance ?
you can
#synthesize formItemId = _formItemId;
//synthesize needs local declaration of _formItemId;
#implementation ExtraWurst {
NSString *_formItemId;
}
but this is done behind the scene for you from Xcode without #synthesize.
Sometime it is still easier to define the use of an internal variable for a property in this way.
apart from that you can and have to change your setter and getter methods in the following way.
-(NSString *)formItemId {
return _formItemId;
}
-(void)setFormItemId:(NSString *)formItemId {
_formItemId = formItemId;
}
this will prevent you from ending up in a loop.
Why?
Because self.formItemId = refers to -(void)setFormItemId:
So you would call the setter inside the setter that will set with the same again and again aka an endless loop.
You can take care of the getter the same way as shown above.
Where to use self.yourProperty then?
You can use self.formItemId anywhere in the class but not inside getter and setter of formItemId.
Correctly mentioned, Instance variables may not be placed in categories.
Meaning if you need such you have to subclass UIControl but that breaks the inheritance of your used UIControls. You would have to subclass all your SpecialUIControls you are using later.
Another solution, you could define a constant in your implementation and go with objective-C runtime functions and associate this constant yourself. Beware because you transform the ObjectModel for all UIControl classes then..
#import "NSControl+formItemSupport.h"
#import <objc/runtime.h>
#implementation UIControl (formItemSupport)
NSString const *key = #"formItemSupport.forItemKey";
-(void)setFormItemId:(NSString *)formItemId {
objc_setAssociatedObject(self, &key, formItemId, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSString *)formItemId {
return objc_getAssociatedObject(self, &key);
}
#end
still, its much easier and safer and flexible to subclass your own UIControl instead to extent all subclasses inherited from UIControl.
Why is subclassing easier here?
As you mentioned you want to json later on with the given formItemId per Control you can make use of an archiver / unarchiver design pattern of your subclasses which are nice to jsonify later.

Any way to apply Objective-C category only to current class (or equivalent effect)?

Let's say I have a custom subclass of UIView called MyCustomView. Let's also say that I have a category on UIView called UIView+Dictionary that adds an NSDictionary property called dictionary to every UIView.
If I were to import UIView+Dictionary.h into MyCustomView.m then every view referenced within MyCustomView.m would have this added dictionary property, which in many situations is exactly the desired behavior.
However, if I wanted UIView+Dictionary applied only to MyCustomView itself and not to every UIView referenced within MyCustomView.m, is there a way to do so (or achieve a similar effect)?
I'd like to avoid making MyCustomView a subclass of another custom subclass (e.g., MyViewWithDictionary), as I'd ideally like to be able to import multiple categories for something akin to multiple inheritance (e.g., UIView+Dictionary, UIView+Border, UIView+CustomAnimations).
In my actual own scenario, I've written a category to automatically implement a custom UINavigationBar in a view controller, but I'd like that category to apply only to the view controller into which I am importing the category and not any other view controllers that may be referenced in that file.
Any and all insights are appreciated! And I apologize in advance as I am fairly certain there are more correct terminologies for the effect described above.
However, if I wanted UIView+Dictionary applied only to MyCustomView itself [...] is there a way to do so [...]?
Only by changing the category to be on MyCustomView and not UIView.
The header has nothing to do with whether the category's methods are present on any given instance. If the category is compiled into your program, the methods are there, no matter where the instance is created. This is the reason that prefixes are so important on methods that are added to framework classes: categories have global effect, and name collisions are undefined behavior.
The header only affects the visibility of the methods as far as the compiler is concerned. You can use the usual tricks to call them at runtime regardless.
The category takes effect on the class itself, when the runtime is initialized at launch. If you want the methods of the category to be available only on a certain class, the category must be defined on that class.
As Josh pointed out, any methods added in categories are basically inert unless you call them. The issue that I was having was for generated properties and swizzled methods in categories (since, as Josh also pointed out, there are no mixins in Objective-C).
I was able to solve this by adding in a custom BOOL in my category that defaults to NO and acts as a "switch" for whatever category methods and properties I want to specify.
E.g., if I wanted my dictionary property to be lazily instantiated but only within MyCustomView, I could do the following:
// UIView+Dictionary.h
#interface UIView (Dictionary)
#property (nonatomic) BOOL enableDictionary;
#property (nonatomic, strong) NSDictionary *dictionary;
#end
// UIView+Dictionary.m
#import "UIViewController+CustomNavigationBar.h"
#import <objc/runtime.h>
#implementation UIView (Dictionary)
- (void)setEnableDictionary:(BOOL)enableDictionary {
objc_setAssociatedObject(self, #selector(enableDictionary), #(enableDictionary), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)enableDictionary {
NSNumber *enableDictionaryValue = objc_getAssociatedObject(self, #selector(enableDictionary));
if (enableDictionaryValue) {
return enableDictionaryValue.boolValue;
}
objc_setAssociatedObject(self, #selector(enableDictionary), #NO, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return self.enableDictionary;
}
- (void)setDictionary:(NSDictionary *)dictionary {
objc_setAssociatedObject(self, #selector(dictionary), dictionary, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSDictionary *)dictionary {
if (!self.enableDictionary) {
return nil;
}
NSDictionary *dictionary = objc_getAssociatedObject(self, #selector(dictionary));
if (dictionary) {
return dictionary;
}
objc_setAssociatedObject(self, #selector(dictionary), #{}, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return self.dictionary;
}
#end
And then within -[MyCustomView viewDidLoad] I could simply call self.enableDictionary = YES. That way, only instances of MyCustomView will have a non-nil lazily instantiated NSDictionary. (Note that, in this example, all instances of UIViews will still respond to the selector #selector(dictionary), but our behavior will differ based on whether enableDictionary is YES or NO.)
While that is a trivial example, the same strategy can be used for methods that are swizzled within categories. (Again, swizzling methods within categories is probably bad form but a necessary evil in certain scenarios.)

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.

Extend class properties of a UIKit class (no access to #implementation) [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Subclass UIButton to add a property
I'm trying to find a way to extend UIButton so that it can have a property like
#property(assign, nonatomic) id userInfos;
without subclassing it...
Is this possible?
the button.tag is not enough in my situation...
Okay as always a better answer is available here
Subclass UIButton to add a property
This is very easy using Objective-C associated objects:
In your header:
#interface UIButton (MyCustomProperty)
#property (readwrite, retain, nonatomic) id myCustomProperty;
#end
In your implementation file:
#include <objc/runtime.h>
/* Associated objects need a unique memory location to use as a key. */
static char MyCustomPropertyKey = 0;
#implementation UIButton (MyCustomProperty)
/* Use #dynamic to tell the compiler you're handling the accessors yourself. */
#dynamic myCustomProperty;
- (id)myCustomProperty {
return objc_getAssociatedObject(self, &MyCustomPropertyKey);
}
- (void)setMyCustomProperty: (id)anObject {
objc_setAssociatedObject(self, &MyCustomPropertyKey, anObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
That's it!
What you want is to create a UIButton category. Categories are designed as a way to extend the functionality of an existing class. Once created an set up, you only need to import the category and you can use its function on any instance of the class it's designed for.
You can use the objective-c runtime's associated objects functions to associate an object with another object:
void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)
id objc_getAssociatedObject(id object, void *key)
Also, voting to close. Duplicate of:
How to add properties to NSMutableArray via category extension?
Adding custom behavior and state to all my classes
among many others.
Edit:
I also agree with the comment on your question by #Paul.s. Attaching data to a button sounds messy. Without knowing what you're doing, I would suggest tagging the button and then have your view controller handle fetching whatever data you need based on the button's tag.

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