I have a class for which I have created a category. Now I want to access category method inside original class but I am getting error:
error: instance method '-hasSound' not found (return type
defaults to 'id') [-Werror,-Wobjc-method-access]
// Animal.h
#interface Animal: NSObject
- (void)sound;
#end
// Animal.m
#import "Animal+Additions.h"
#implementation Animal
- (void)sound {
[self hasSound];
}
#end
// Animal+Additions.h
#interface Animal (Additions)
- (BOOL)hasSound;
#end
// Animal+Additions.h
#implementation Animal (Additions)
- (BOOL) hasSound {
return YES;
}
#end
I have been doing same thing in Swift but not sure how to achieve the same thing in Objective C.
Category and original class are in separate files. I have imported Category interface file inside original class but that didn't work.
You have not shown sufficient #import statements, so I have to assume they don't exist. You need them.
Another possible issue is that, at least according to your comments, you seem to have two Animal+Additions.h files but no Animal+Additions.m file.
This complete code in four files compiles for me:
// Animal.h
#import <Foundation/Foundation.h>
#interface Animal: NSObject
- (void)sound;
#end
// Animal.m
#import "Animal.h"
#import "Animal+Additions.h"
#implementation Animal
- (void)sound {
[self hasSound];
}
#end
// Animal+Additions.h
#import "Animal.h"
#interface Animal (Additions)
- (BOOL)hasSound;
#end
// Animal+Additions.m
#import "Animal+Additions.h"
#implementation Animal (Additions)
- (BOOL) hasSound {
return YES;
}
#end
Note all the #import statements, and note that the Animal.m file must be part of the target.
Related
In my code I have the following compiler warning:
Initializing 'MyClass *__strong' with an expression of incompatible type '__strong id<MyProtocol>'
My question is this, why does the compiler warning go away if I remove the protocol from the category?
As in, when when I replace
#interface MyClass (CategoryNameHere) <SomeOtherProtocol>
With
#interface MyClass (CategoryNameHere)
I have found minimal piece of code which reproduces this scenario:
#interface MyWidget ()
#end
#protocol MyProtocol
#end
#protocol SomeOtherProtocol
#end
#interface MyClass <MyProtocol>
#end
#interface MyClass (CategoryNameHere) <SomeOtherProtocol>
#end
#implementation MyWidget
- (MyClass *)sampleMethod:(id<MyProtocol>)v {
MyClass *instance = v;
return instance;
}
#end
The compiler warning is on the line which contains
MyClass *instance = v;
#interface Factory : NSObject #end
#protocol First #end
#protocol Second #end
#protocol Third #end
#interface Base <First, Second> #end
#interface Custom : Base #end
#interface Base (CategoryNameHere) <Second>
#end
#implementation Factory
- (Custom *)sampleMethod:(id<First, Second>)v {
return v;
}
#end
Consider example that you have provided with several renaming.
You can play with it by adding/removing protocols as requirement for Factory's method or by adding/removing protocols as extensions for classes.
The corner stone of this example is bare ( without superclass ) class Base.
It is considered as id<First, Second> by compiler.
I have class A which has this declaration in it's .m file:
#implementation A {
NSObject *trickyObject;
}
And class B which has this declaration in it's .h file:
#interface B : A
#end
Is there any possibility to access the trickyObject from a method declared in the class B?
If you have a property or method that is private, but you want to make accessible to subclasses, you can put the declaration in a category.
So consider A:
// A.h
#import Foundation;
#interface A : NSObject
// no properties exposed
#end
And
// A.m
#import "A.h"
// private extension to synthesize this property
#interface A ()
#property (nonatomic) NSInteger hiddenValue;
#end
// the implementation might initialize this property
#implementation A
- (id)init {
self = [super init];
if (self) {
_hiddenValue = 42;
}
return self;
}
#end
Then consider this category:
// A+Protected.h
#interface A (Protected)
#property (readonly, nonatomic) NSInteger hiddenValue;
#end
Note, this extension doesn’t synthesize the hiddenValue (the private extension in A does that). But this provides a mechanism for anyone who imports A+Protected.h to have access to this property. Now, in this example, while hiddenValue is really readwrite (as defined in the private extension within A), this category is exposing only the getter. (You obviously could omit readonly if you wanted it to expose both the getter and the setter, but I use this for illustrative purposes.)
Anyway, B can now do things like:
// B.h
#import "A.h"
#interface B : A
- (void)experiment;
// but again, no properties exposed
#end
And
// B.m
#import "B.h"
#import "A+Protected.h"
#implementation B
// but with this category, B now has read access to this `hiddenValue`
- (void)experiment {
NSLog(#"%ld", (long)self.hiddenValue);
}
#end
Now A isn’t exposing hiddenValue, but any code that uses this A (Protected) category (in this case, just B) can now access this property.
And so now you can call B methods that might be using the hiddenValue from A, while never exposing it in the public interfaces.
// ViewController.m
#import "ViewController.h"
#import "B.h"
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
B *b = [[B alloc] init];
[b experiment]; // this calls `B`’s exposed method, and that method is using the property not exposed by `A.h`
}
#end
If you’re interested in a real-world example of this, consider UIKit’s:
#import UIKit.UIGestureRecognizerSubclass;
Generally the state of a UIGestureRecognizer is readonly, but this UIGestureRecognizer (UIGestureRecognizerProtected) category exposes the readwrite accessors for state (to be used, as the name suggests, by gesture recognizer subclasses only).
Is it possible to encapsulate the fact that my class is derived from a certain superclass? Something like:
#class NoneOfYourBusiness;
#interface MyClass : NoneOfYourBusiness
#end
The compiler doesn’t like this: Attempting to use the forward class 'NoneOfYourBusiness' as superclass of 'MyClass'.
You could add some indirection; a dummy superclass in the inheritance tree, between MyClass and RealSuperclass:
Private header, HiddenSuperclass.h, with corresponding implementation file
#import <Foundation/Foundation.h>
#interface HiddenSuper : NSObject
- (void)makePancakes;
#end
Header for dummy class, corresponding empty implementation
#import <Foundation/Foundation.h>
#import "HiddenSuper.h"
#interface DummySuper : HiddenSuper
// Nothing to see here, folks!
#end
Then your public class's header:
#import "DummySuper.h"
#interface PublicSubclass : DummySuper
- (void)fixBreakfast;
#end
And the implementation, hidden by compilation:
#import "PublicSubclass.h"
#import "HiddenSuper.h"
#implementation PublicSubclass
- (void)fixBreakfast
{
[self makePancakes];
}
#end
Two answers
The requirement makes no sense. Client code can see the super class does not mean anything because it should be empty.
i.e. Thats all they can see
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClass : NoneOfYourBusiness
- (void)publicMethod;
#end
because you should put all private / internal method / variable in private header / implementation file.
Ok you really need to hide it for some reason, then hide everything
public header
#interface MyClass : NSObject
- (void)publicMethod;
#end
private header / implementation file
#interface NoneOfYourBusiness : NSObject
#end
#interface MyClassImpl : NoneOfYourBusiness
- (void)publicMethod;
#end
#interface MyClass ()
#property (strong) MyClassImpl *impl;
#end
#implementation
- (id)forwardingTargetForSelector:(SEL)aSelector
{
return self.impl;
}
#end
you can even make MyClass inherited from NSProxy to make it a real proxy object
So I've been trying to organize my Objective-C code because as of now everything is in one huge file.
In a hypothetical situation:
Class A has methods "alertCompleted" and "prepareAlert".
Class B has a method "submitPost".
Let's say I'm in the A's method, "prepareAlert" from which I want to call B's method "submitPost". Then, from the "submitPost" method I need to call "alertCompleted" in A.
As you can see A calls methods in B and B calls methods in A. It's obviously ideal if I can have all the methods in the same class but I really need to organize my code (the methods above were just examples). How can I accomplish this? As far as I know categories only let the category class call the main class or vice verse but not both ways and importing each others headers gives me circular dependancy.
This is not really that big of a problem. You can use #class <classname> to create a forward.
ClassA.h
#class B;
#interface A : NSObject
- (void)needsB:(B *)b;
#end
ClassB.h
#class A;
#interface B : NSObject
- (void)needsA:(A *)a;
#end
It's in the .m file where you will need to import ClassA.h and ClassB.h
Here's One Way, although it feels a bit excessive:
ClassA.h
#import <Foundation/Foundation.h>
#import "ClassB.h"
#interface ClassA : NSObject
- (void) prepareAlert;
#end
ClassA.m
#implementation ClassA
- (void) prepareAlert {
NSLog(#"Class A: Preparing Alert");
ClassB * bClass = [ClassB new];
[bClass submitPostWithTarget:self andCallback:#selector(handleCompletion)];
}
- (void) handleCompletion {
NSLog(#"Class A: Handled Completion");
}
#end
ClassB.h
#import <Foundation/Foundation.h>
#interface ClassB : NSObject
- (void) submitPostWithTarget:(id)target andCallback:(SEL)callback;
#end
ClassB.m
#import "ClassB.h"
#implementation ClassB
- (void) submitPostWithTarget:(id)target andCallback:(SEL)callback {
NSLog(#"Class B: Submitting Post");
// Callback
IMP imp = [target methodForSelector:callback];
void (*func)(id, SEL) = (void *)imp;
func(target, callback);
}
#end
Then When I want to call it:
#import "ClassA.h"
And Run Like So:
ClassA * aClass = [ClassA new];
[aClass prepareAlert];
Will Print:
2014-03-14 20:25:05.207 MyApp[52877:60b] Class A: Preparing Alert
2014-03-14 20:25:05.208 MyApp[52877:60b] Class B: Submitting Post
2014-03-14 20:25:05.209 MyApp[52877:60b] Class A: Handled Completion
This way, if you have a specific instantiation of ClassA that you want called from within ClassB, it will still work.
this is my h file:
#import <Foundation/Foundation.h>
#interface Base : NSObject
#end
this is my m file:
#import "Base.h"
#interface Base()
#property (nonatomic) int number;
#end
#implementation Base
-(void) setNumber: (int) p_number
{
self.number = p_number;
}
#end
this is what i want to accomplish
an h file:
#import <Foundation/Foundation.h>
#import "Base.h"
#interface Derived : Base
#end
and to do this in the m file
#import "Derived.h"
#implementation Derived
- (void) foo
{
self.number= 7;
}
#end
this of course results in error, please answer with a code that allows me to call the base property without placing the definition in the h file
thanks
Asking people to answer only with code is not a good idea. Why not ask for an explanation of what's wrong, so that you can fix this error and tons of similar errors in the future yourself?
The problem here is that you don't declare your property in the base header. If you don't want to do that, you can declare it in your subclass' implementation file as an extension of your base class:
Derived.m
#import "Derived.h"
#interface Base ()
#property (nonatomic) int number;
#end
#implementation Derived
- (void) foo
{
self.number= 7;
}
#end
You could use the same approach that Apple uses with UIGestureRecognizerSubclass.h
e.g. Create
// BaseSubclass.h
#interface Base (ForSubclassEyesOnly)
#property (nonatomic, assign) NSInteger number;
#end
You'll need to silence the compiler with
#implementation Base (ForSubclassEyesOnly)
#dynamic number;
#end
Now any class that want's to use these properties/call methods just includes this header.
e.g
#import "Derived.h"
#import "BaseSubclass.h"
#implementation Derived
- (void) foo
{
self.number = 7;
}
#end