Objective-c categories - objective-c

I'm learning Objective-C and now I'm stuck with categories. Here is the code
#import <Foundation/Foundation.h>
#interface NSMutableArray (NSMutableArrayCategory)
-(NSMutableArray *)removeLastObject;
#end
#import "NSMutableArrayCategory.h"
#implementation NSMutableArray (NSMutableArrayCategory)
-(NSMutableArray *)removeLastObject
{
return [self removeObjectAtIndex:[self count] - 1];
}
#end
The problem is that I get
Returning void from a function with incompatible result type 'NSMutableArray' *
What is wrong here ?

You probably want to declare removeLastObject as returning void, not NSMutableArray.
#interface NSMutableArray (NSMutableArrayCategory)
- (void)removeLastObject;
#end
Then the implementation will look like this:
- (void)removeLastObject
{
[self removeObjectAtIndex:[self count] - 1];
}
This matches the other mutation methods on NSMutableArray.

The underlying problem is that removeLastObject is already defined and does what you want (so people don't recreate it). Some of the answers here are a little confusing, however, in that they suggest it's ok to use a category to override an existing method (or at least don't explicitly state that you must not do this). You must not do this. It is poorly defined behavior, and in some cases it is completely undefined behavior. You generally should subclass to override a method.
There is an advanced technique called swizzling that will allow you to do this without a subclass, but it is a very specialized and sometimes fragile technique, not for general use.
But in no case should you use a category to override an existing method.

Im not familiar with objective c. but i imagine that removeObjectAtIndex returns void. so I would try
[self removeObjectAtIndex:[self count] -1];
return self;
return self after removing item..

Related

How is dictionary[#"key"] implemented in objective c?

If we want to override [dictionary objectForKey:#"key"] it can be done by subclassing NSDictionary class. How to override dictionary[#"key"]? In this context I want to know how dictionary[#"key"] is implemented.
Thanks!
Edit:
I wanted to find a scalable way to parse an API response while preventing [NSNull null] from crashing my app. I have written category for NSDictionary, but I wanted a way to parse in this syntax: data[#"key"]
So, I was evaluating the feasibility of subclassing NSDictionary.
When you use dictionary[#"key"] this gets converted into a call to [dictionary objectForKeyedSubscript:#"key"]. objectForKeyedSubscript: has the same behaviour as objectForKey:.
If you want to change the behaviour of dictionary[#"key"] then you will need to override objectForKeyedSubscript:.
Apple's NSDictionary API Reference has a little more information.
EDIT: This question is pretty old now, but it just recently came to my attention again, so I thought I would add an example of wrapping NSDictionary as I would recommend. This could be made more robust and feature rich, but it's an okay place to start.
#interface NilSafeDictionary: NSObject
-(instancetype)initWithDictionary:(NSDictionary*)dictionary;
#end
/** Category on NSDictionary to create a nil-safe wrapper. */
#interface NSDictionary <NilSafeConvenience>
- (NilSafeDictionary*)nilSafe;
#end
#implementation NilSafeDictionary {
NSDictionary* _internalDict;
}
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
self = [super init];
if (self) {
_internalDict = [dict copy];
}
return self;
}
- (id)objectForKeyedSubscript:(id<NSCopying>)key {
id obj = _internalDict[key];
if ([obj isKindOfClass:[NSNull class]]) {
return nil;
}
return obj;
}
#end
#implementation NSDictionary <NilSafeConvenience>
- (NilSafeDictionary*)nilSafe {
return [[NilSafeDictionary alloc] initWithDictionary:self];
}
#end
CAVEAT: You don't explain here what problem you're trying to solve, but for anyone who comes across this question in the future, subclassing NSDictionary is almost certainly never what you want.
NSDictionary is a class cluster. Class clusters are tricky to subclass correctly with guidance, plus Apple's documentation explicitly tells you not to subclass, so there's no guidance on how to do it correctly.
Even if you're able to use your subclass and have it "work correctly" for your purposes, every other piece of code in the system will still be returning the original NSDictionary class, not your subclass, so it doesn't benefit you.
If you're hell bent on modifying the way NSDictionary works, create your own wrapper class that has an NSDictionary inside and create your own objectForKeyedSubscript: implementation.
Yes, you can add subscript indexing to your own custom class just like NSDictionary!
dictionary[#key] is short hand for calling [dictionary objectForKeyedSubscript:#"key"]. Therefore to override the functionality of dictionary[#"key"] you can subclass NSDictionary.
#interface MyDictionary : NSDictionary
- (id) objectForKeyedSubscript:(id)key;
#end
#implementation MyDictionary
- (id) objectForKeyedSubscript:(id)key
{
/*
...
*/
}
#end
Original answer using categories, however this approach isn't advised as it will override the original method removing access to super and potential of clashes should multiple categories be loaded overriding the same method. The last category to be loaded will be used at runtime, therefore you cannot guarantee which that will be.
dictionary[#key] is short hand for calling [dictionary objectForKeyedSubscript:#"key"]. Therefore to override the functionality of dictionary[#"key"] you would create a new category for NSDictionary.
//Category in NSDictionary+CustomKeyedSubscript.h and NSDictionary+CustomKeyedSubscript.m
#interface NSDictionary (CustomKeyedSubscript)
- (id) objectForKeyedSubscript:(id)key;
#end
#implementation NSDictionary (CustomKeyedSubscript)
- (id) objectForKeyedSubscript:(id)key
{
/*
...
*/
}
#end

Setting default values for inherited property without using accessor

I always see people debating whether or not to use a property's setter in the -init method. My problem is how to create a default value in a subclass for an inherited property. Say we have a class called NSLawyer -- a framework class, that I can't change -- with an interface that looks like this:
#interface NSLawyer : NSObject {
#private
NSUInteger _numberOfClients;
}
#property (nonatomic, assign) NSUInteger numberOfClients;
#end
And an implementation that looks like this:
#implementation NSLawyer
- (instancetype)init
{
self = [super init];
if (self) {
_numberOfClients = 0;
}
return self;
}
#end
Now let's say I want to extend NSLawyer. My subclass will be called SeniorPartner. And since a senior partner should have lots of clients, when SeniorPartner gets initialized, I don't want the instance to start with 0; I want it to have 10. Here's SeniorPartner.m:
#implementation SeniorPartner
- (instancetype)init
{
self = [super init];
if (self) {
// Attempting to set the ivar directly will result in the compiler saying,
// "Instance variable _numberOfClients is private."
// _numberOfClients = 10; <- Can't do this.
// Thus, the only way to set it is with the mutator:
self.numberOfClients = 10;
// Or: [self setNumberOfClients:10];
}
return self;
}
#end
So what's a Objective-C newcomer to do? Well, I mean, there's only one thing I can do, and that's set the property. Unless there's something I'm missing. Any ideas, suggestions, tips, or tricks?
You should do exactly has you have; call the accessor. The declaring class typically avoids calling its own accessors in init to avoid accidentally calling an overridden accessor in a subclass that might rely on the consistency of data you haven't initialized yet. Your superclass on the other hand should be completely consistent by the time the subclass's init is run, so there is no problem using superclass accessors at that time.
Consider the common and general case: you want to set your transform in a UIView subclass. How would you solve that other than call setTransform:? Subclassing non-Apple code is no different.
Make it #protected. It is very rare to make an ivar or property private these days. Private ivars and/or properties are better declared in the implementation. For that matter #protected ivars/properties are rarely seen in Objective-C but perfectly fine.
Using a setter either as a method or with dot notation is just wrong (yes it works but is really bad form), if you want use setters/getters declare a property.

Force obj-c to throw an exception when accessing a nil property

I get caught out way too many times by creating eg an NSMutableArray* myArray property and then forgetting to assign self.myArray = [NSMutableArray array]; in -init. My app of course never complains in such cases because [self.myArray addObject:foo] is perfectly legal if self.myArray is nil, so I'm left scratching my head and going "double you tee eff".
I realise this is a long shot, but is there an lldb attribute or property specifier that would cause obj-c to ensure that properties are non-nil after completing -init?
I don't believe there is a compiler flag that will help you, however you could change the semantics of your array access so it goes through your own methods instead of directly to the NSMutableArray.
So instead of
#interface MyClass : NSObject
#property NSMutableArray *array
#end
use:
#interface MyClass : NSObject
- (void)addObject:(id)object;
- (NSUInteger)objectCount;
- (id)objectAtIndex:(NSUInteger)index;
- (void)removeObjectAtIndex:(NSUInteger)index;
#end
and you can add whatever checks you like to those array access methods (as well as lazily creating the array, of course).
However, as you can see, this could be add significant effort just to solve a small issue, and I wouldn't do this myself :)
- (NSMutableArray*) myArray
{
NSAssert(nil != _myArray);
return _myArray;
}
You can write this implementation of myArray accessor.
Also you can add in yours class method something like that:
- (void) AssertValid
{
NSAssert(nil != _myArray);
}
I am not aware of such mechanism and don't think it exists, because it would make little practical sense as there are many classes whose properties are nil most of the time by design.
It is possible to perform this check using class_copyPropertyList() from objc-runtime and then reading every property by name (for example, using valueForKey:). In simplest case, you would create a category method like [self logNilProperties] on NSObject and call it at the end of init... methods of classes that you want to check.
What you want is not possible. It's a language feature. You can't just change the behavior of the language.
Probably the best solution you can get is to introduce unit tests for the values of your properties. Or asserts:
assert(self.property != nil)
Here is a small piece of code which is used to throw an Exception.
NSException *exception=[[NSException alloc]initWithName:#"no result" reason:#"array empty" userInfo:nil];
[exception raise];
The exception can be caught in the AppDelegate file
void exceptionHandler(NSException *exception){
}
Before this method write
NSSetUncaughtExceptionHandler(&exceptionHandler);
in the - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
Happy Coding :)

Objective C Subclassing: Is this proper?

So I'm working on an iPad game using the cocos2d framework.
My game requires different buildings to be spawned at the beginning of a "level". The user gets to choose which buildings they want to use.
An important functionality here is that different buildings will perform different actions when pressed.
I have a parent class that looks something like this:
BaseBuilding.h
#interface BaseBuilding : NSObject {
CGRect _hitBox;
NSString *_name;
CCSprite *_sprite;
int _identifier;
int _health;
int _coolDownDuration;
}
#property (atomic, retain) CCSprite *sprite;
#property (atomic, assign) int identifier;
#property (atomic, assign) int health;
- (void) onBuildingPressed;
- (id) initWithName:(NSString*)baseName;
- (id) initBuilding;
- (CGRect) hitBox;
- (void) sustainDamage;
So most of my buildings are very similar. Each building has their own initBuilding method which overrides the parent. The initBuilding method calls the super initWithName method which then looks up a plist with information about that building (sprite name, etc).
Each building also has their own onBuildingPressed method, which also overrides the parent method. This is very important functionality.
The part that I'm having trouble with:
I want to spawn the buildings based on what the player selects. What I'm currently doing is something like this:
BaseBuilding *building;
switch (choice) {
case 1:
building = [BuildingX alloc];
[building initBuilding];
break;
case 2:
building = [BuildingY alloc];
[building initBuilding];
break;
case 3:
building = [BuildingZ alloc];
[building initBuilding];
break;
}
return building;
Since BuildingX, BuildingY, BuildingZ are all subclasses of BaseBuilding, initBuilding does call the correct method.
Later on I can call [rightBuilding onBuildingPressed]; and it works as expected.
BuildingX has a removeAmmo method that the other buildings don't have, so I have to do this to call it: [(BuildingX*)centerBuilding removeAmmo].
Is this proper, or this a better way of doing this?
The only thing that I notice is that, if you have many subclasses - provided that all subclasses have some alphabetical order - you do it faster and more elegantly by getting a class object according to the value of choice:
NSString* className= [NSString stringWithFormat: #"Building%c",'X'-1+choice];
Class class= NSClassFromString(className);
BaseBuilding* building= [[class alloc] initBuilding];
But this is just a matter of style and rapidity (writing the code, I mean). Your method is perfectly fine and there's nothing wrong with it.
You can verify the class at run time to guarantee there's no room for error here like so:
if ( [centerBuilding respondsToSelector:NSSelectorFromString(#"removeAmmo")] ) {
[centerBuilding performSelector:NSSelectorFromString(#"removeAmmo"];
}
Seems logical to me. I don't know if it's stylish, the snobs can determine that for you. If it works, it works. I don't see the point in fixing things that aren't broken.
Yes, it's correct.
But:
1) If you are casting all your subclasses to the parent class, and you need to use a particular method of your subclass, then it's useless casting to the right subclass ONLY in certain circumstances. Try to make the removeAmmo a base method...
or
2) make your building subclass calling the removeAmmo method from its inside, and declare the removeAmmo method in a category
From an external point of view, the BaseClass has not the removeAmmo method, so it's not logic to declare a public method which could be called only re-casting your object to a specific subclass.

Instance Variables for Objective C Categories

I have a situation where it seems like I need to add instance variables to a category, but I know from Apple's docs that I can't do that. So I'm wondering what the best alternative or workaround is.
What I want to do is add a category that adds functionality to UIViewControllers. I would find it useful in all my different UIViewControllers, no matter what specific UIViewController subclass they extend, so I think a category is the best solution. To implement this functionality, I need several different methods, and I need to track data in between them, so that's what led me to wanting to create instance methods.
In case it's helpful, here's what I specifically want to do. I want to make it easier to track when the software keyboard hides and shows, so that I can resize content in my view. I've found that the only way to do it reliably is to put code in four different UIViewController methods, and track extra data in instance variables. So those methods and instance variables are what I'd like to put into a category, so I don't have to copy-paste them each time I need to handle the software keyboard. (If there's a simpler solution for this exact problem, that's fine too--but I would still like to know the answer to category instance variables for future reference!)
Yes you can do this, but since you're asking, I have to ask: Are you absolutely sure that you need to? (If you say "yes", then go back, figure out what you want to do, and see if there's a different way to do it)
However, if you really want to inject storage into a class you don't control, use an associative reference.
Recently, I needed to do this (add state to a Category). #Dave DeLong has the correct perspective on this. In researching the best approach, I found a great blog post by Tom Harrington. I like #JeremyP's idea of using #property declarations on the Category, but not his particular implementation (not a fan of the global singleton or holding global references). Associative References are the way to go.
Here's code to add (what appear to be) ivars to your Category. I've blogged about this in detail here.
In File.h, the caller only sees the clean, high-level abstraction:
#interface UIViewController (MyCategory)
#property (retain,nonatomic) NSUInteger someObject;
#end
In File.m, we can implement the #property (NOTE: These cannot be #synthesize'd):
#implementation UIViewController (MyCategory)
- (NSUInteger)someObject
{
return [MyCategoryIVars fetch:self].someObject;
}
- (void)setSomeObject:(NSUInteger)obj
{
[MyCategoryIVars fetch:self].someObject = obj;
}
We also need to declare and define the class MyCategoryIVars. For ease of understanding, I've explained this out of proper compilation order. The #interface needs to be placed before the Category #implementation.
#interface MyCategoryIVars : NSObject
#property (retain,nonatomic) NSUInteger someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance;
#end
#implementation MyCategoryIVars
#synthesize someObject;
+ (MyCategoryIVars*)fetch:(id)targetInstance
{
static void *compactFetchIVarKey = &compactFetchIVarKey;
MyCategoryIVars *ivars = objc_getAssociatedObject(targetInstance, &compactFetchIVarKey);
if (ivars == nil) {
ivars = [[MyCategoryIVars alloc] init];
objc_setAssociatedObject(targetInstance, &compactFetchIVarKey, ivars, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[ivars release];
}
return ivars;
}
- (id)init
{
self = [super init];
return self;
}
- (void)dealloc
{
self.someObject = nil;
[super dealloc];
}
#end
The above code declares and implements the class which holds our ivars (someObject). As we cannot really extend UIViewController, this will have to do.
I believe it is now possible to add synthesized properties to a category and the instance variables are automagically created, but I've never tried it so I'm not sure if it will work.
A more hacky solution:
Create a singleton NSDictionary which will have the UIViewController as the key (or rather its address wrapped as an NSValue) and the value of your property as its value.
Create getter and setter for the property that actually goes to the dictionary to get/set the property.
#interface UIViewController(MyProperty)
#property (nonatomic, retain) id myProperty;
#property (nonatomic, readonly, retain) NSMutableDcitionary* propertyDictionary;
#end
#implementation UIViewController(MyProperty)
-(NSMutableDictionary*) propertyDictionary
{
static NSMutableDictionary* theDictionary = nil;
if (theDictionary == nil)
{
theDictioanry = [[NSMutableDictionary alloc] init];
}
return theDictionary;
}
-(id) myProperty
{
NSValue* key = [NSValue valueWithPointer: self];
return [[self propertyDictionary] objectForKey: key];
}
-(void) setMyProperty: (id) newValue
{
NSValue* key = [NSValue valueWithPointer: self];
[[self propertyDictionary] setObject: newValue forKey: key];
}
#end
Two potential problems with the above approach:
there's no way to remove keys of view controllers that have been deallocated. As long as you are only tracking a handful, that shouldn't be a problem. Or you could add a method to delete a key from the dictionary once you know you are done with it.
I'm not 100% certain that the isEqual: method of NSValue compares content (i.e. the wrapped pointer) to determine equality or if it just compares self to see if the comparison object is the exact same NSValue. If the latter, you'll have to use NSNumber instead of NSValue for the keys (NSNumber numberWithUnsignedLong: will do the trick on both 32 bit and 64 bit platforms).
This is best achieved using the built-in ObjC feature Associated Objects (aka Associated References), in the example below just change to your category and replace associatedObject with your variable name.
NSObject+AssociatedObject.h
#interface NSObject (AssociatedObject)
#property (nonatomic, strong) id associatedObject;
#end
NSObject+AssociatedObject.m
#import <objc/runtime.h>
#implementation NSObject (AssociatedObject)
#dynamic associatedObject;
- (void)setAssociatedObject:(id)object {
objc_setAssociatedObject(self, #selector(associatedObject), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (id)associatedObject {
return objc_getAssociatedObject(self, #selector(associatedObject));
}
See here for the full tutorial:
http://nshipster.com/associated-objects/
It mentioned in many document's online that you can't create create new variable in category but I found a very simple way to achieve that. Here is the way that let declare new variable in category.
In Your .h file
#interface UIButton (Default)
#property(nonatomic) UIColor *borderColor;
#end
In your .m file
#import <objc/runtime.h>
static char borderColorKey;
#implementation UIButton (Default)
- (UIColor *)borderColor
{
return objc_getAssociatedObject(self, &borderColorKey);
}
- (void)setBorderColor:(UIColor *)borderColor
{
objc_setAssociatedObject(self, &borderColorKey,
borderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.layer.borderColor=borderColor.CGColor;
}
#end
That's it now you have the new variable.
Why not simply create a subclass of UIViewController, add the functionality to that, then use that class (or a subclass thereof) instead?
Depending on what you're doing, you may want to use Static Category Methods.
So, I assume you've got this kind of problem:
ScrollView has a couple of textedits in them. User types on text edit, you want to scroll the scroll view so the text edit is visible above the keyboard.
+ (void) staticScrollView: (ScrollView*)sv scrollsTo:(id)someView
{
// scroll view to someviews's position or some such.
}
returning from this wouldn't necessarily require the view to move back, and so it doesn't need to store anything.
But that's all I can thinkof without code examples, sorry.
I believe it is possible to add variables to a class using the Obj-C runtime.
I found this discussion also.