I am writing a sample code in order to understand message forwarding in Objective C (iOS).
I have two classes (class A and class B). I want to create an instance of class B and set a class A instance variable to it. I am calling the Forward Invocation method (Message Forwarding) in the following code.
// ViewController.h
// TestInvocation
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
// ViewController.m
// TestInvocation
#import "ViewController.h"
#import "TestInvocation.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[TestInvocation testRun];
[super viewDidLoad];
}
#end
// TestInvocation.h
// TestInvocation
#import <Foundation/Foundation.h>
#interface TestInvocation : NSObject
{}
+(void)testRun;
#end
// TestInvocation.m
// TestInvocation
#import "TestInvocation.h"
#import "ClassB.h"
#import "ClassA.h"
#implementation TestInvocation
+(void)testRun
{
ClassB* diplomat = [[ClassB alloc] init];
NSLog(#"value = %d",[diplomat value]);// Error shows up here on running:
//No visible #interface for 'ClassB' declares the selector 'value'
}
#end
// ClassA.h
// TestInvocation
#import <Foundation/Foundation.h>
#interface ClassA : NSObject
{
int value;
}
#property(readwrite,assign) int value;
#end
// ClassA.m
// TestInvocation
#import "ClassA.h"
#implementation ClassA
#synthesize value;
#end
// ClassB.h
// TestInvocation
#import <Foundation/Foundation.h>
#interface ClassB : NSObject
{}
#end
// ClassB.m
// TestInvocation
#import "ClassB.h"
#import "ClassA.h"
#implementation ClassB
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
return [ClassA instanceMethodSignatureForSelector:aSelector];
}
-(void)forwardInvocation:(NSInvocation *)anInvocation
{
ClassA* negotiate = [[ClassA alloc] init];
negotiate.value = 15;
[anInvocation invokeWithTarget:negotiate];
}
#end
I am expecting the above code to work. But instead I get the following build time error:
ARC Semantic Issue
TestInvocation.m:19:35: No visible #interface for 'ClassB' declares the selector 'value'
Class B should have the property in interface at least.
But you can make it #dynamic in implementation if you want to call forwardInvocation.
#interface ClassB : NSObject
#property (readwrite, assign) int value;
#end
#implementation ClassB
#dynamic value;
...
#end
I think it should work for you.
Related
I want to inherit my base class properties and methods which will be used by my several derived classes. I want these properties and methods to be exactly protected so that they will only be visible in derived class and not to any external class. But it always gives me some errors.
#interface BasePerson : NSObject
#end
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
#interface DerivedPerson1 : BasePerson
#end
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self.savedPersons = [NSMutableArray array];
self.shouldSavePerson = NO;
}
return self;
}
It always gives me an error that
Property 'savedPersons' not found on object of type 'DerivedPerson1 *'
Property 'shouldSavePerson' not found on object of type 'DerivedPerson1 *'
How i can make use of inheritance in Objective C, I don't want savedPersons and shouldSavePerson properties to be visible to external classes. I only want them to visible in my base class and all the derived classes.
Any help will be great. Thanks
This is not something that the objectiveC really support. There are some ways though. So lets see.
If you put a property in the source file class extension then it is not exposed and you can not access it in the subclass either.
One way is to put all of the subclasses into the same source file as the base class. This is not a good solution at all as you do want to have separate files for separate classes.
It seems logical to import the BaseClass.m in the SubClass source file but that will produce a linker error saying that you have duplicate symbols.
And the solution:
Separate the extension into a separate header. So you have a MyClass
Header:
#import <Foundation/Foundation.h>
#interface MyClass : NSObject
#end
Source:
#import "MyClass.h"
#import "MyClassProtected.h"
#implementation MyClass
- (void)foo {
self.someProperty = #"Some text from base class";
}
#end
Then you create another header file (only the header) MyClassProtected.h which has the following:
#import "MyClass.h"
#interface MyClass ()
#property (nonatomic, strong) NSString *someProperty;
#end
And the subclass MyClassSubclass
Header:
#import "MyClass.h"
#interface MyClassSubclass : MyClass
#end
And the source:
#import "MyClassSubclass.h"
#import "MyClassProtected.h"
#implementation MyClassSubclass
- (void)foo {
self.someProperty = #"We can set it here as well";
}
#end
So now if the user MyClassSubclass he will not have the access to the protected property which is essentially what you want. But the downside is the user may still import MyClassProtected.h after which he will have the access to the property.
Objective-C doesn't have member access control for methods, but you can emulate it using header files.
BasePerson.h
#interface BasePerson : NSObject
#property (strong,nonatomic) SomeClass *somePublicProperty;
-(void) somePublicMethod;
#end
BasePerson-Private.h
#import "BasePerson.h"
#interface BasePerson ()
#property (nonatomic, strong) NSMutableArray<Person*>* savedPersons;
#property (nonatomic) BOOL shouldSavePerson;
#end
BasePerson.m
#import "BasePerson-Private.h"
...
DerivedPerson1.h
#import "BasePerson-Private.h"
#inteface DerivedPerson1 : BasePerson
...
#end
Now any class that #imports BasePerson.h will only see the public methods. As I said though, this is only emulating access control since if a class #imports *BasePerson-Private.h" they will see the private members; this is just how C/Objective-C is.
We can achieve using #protected access specifier
#interface BasePerson : NSObject {
#protected NSMutableArray *savedPersons;
#protected BOOL shouldSavePerson;
}
DerivedPerson1.m
#implementation DerivedPerson1
- (instancetype)init
{
if (self = [super init]) {
self->savedPersons = [NSMutableArray array];
self->shouldSavePerson = NO;
}
return self;
}
#end
OtherClass.m
#import "OtherClass.h"
#import "BasePerson.h"
#implementation OtherClass
- (void)awakeFromNib {
BasePerson *base = [[BasePerson alloc]init];
base->savedPersons = #[];//Getting Error. Because it is not a subclass.
}
#end
I am new to Objective C and trying to grasp the concept of a delegate. I have the following code and have made comments where a warning and an error occur with the build.I am using the latest version of Xcode and using a Storyboard.
From MainViewController.h
#import <UIKit/UIKit.h>
#import "FinalViewController.h"
#class MainViewController;
#protocol MainViewControllerDelegate <NSObject>
- (void)sayHello;
#end
#interface MainViewController : UIViewController
#property (nonatomic, strong) id <MainViewControllerDelegate> delegate;
- (void)writeToMe;
. . .
#end
From MainViewController.m
#import "MainViewController.h"
#import "FinalViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)writeToMe
{
[self.delegate sayHello];
}
. . .
#end
From FinalViewController.h
#import <UIKit/UIKit.h>
#import "MainViewController.h"
#interface FinalViewController : UIViewController <NSCoding, MainViewController> //The ERROR below appears
//ERROR:Cannot find protocol declaration for ‘MainViewControllerDelegate’; did you mean ‘UIPageViewControllerDelegate’?
. . .
#end
From FinalViewController.m
#import "FinalViewController.h"
#interface FinalViewController ()
#end
#implementation FinalViewController
- (void)viewDidLoad
{
[super viewDidLoad];
MainViewController *mainVC;
mainVC.delegate = self; //causes WARNING below
//WARNING:Assigning to ‘id <MainViewControllerDelegate> from incompatible type ‘FinalViewController *const__strong’
[mainVC writeToMe];
. . .
}
- (void)sayHello
{
NSLog(#"sayHello called");
}
#end
I have researched problems and responses to a similar problem on this web site, but have not found a solution using Storyboard.
Change:
#import "MainViewController.h"
#import "FinalViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)writeToMe
{
[self.delegate sayHello];
}
. . .
TO:
#import "MainViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)writeToMe
{
[self.delegate sayHello];
}
. . .
ALSO:
#import <UIKit/UIKit.h>
#import "FinalViewController.h"
#class MainViewController;
#protocol MainViewControllerDelegate <NSObject>
- (void)sayHello;
#end
#interface MainViewController : UIViewController
#property (nonatomic, strong) id <MainViewControllerDelegate> delegate;
- (void)writeToMe;
. . .
#end
TO
#import <UIKit/UIKit.h>
#protocol MainViewControllerDelegate <NSObject>
- (void)sayHello;
#end
#interface MainViewController : UIViewController
#property (nonatomic, weak) id <MainViewControllerDelegate> delegate;
- (void)writeToMe;
. . .
#end
--------------------------- EDIT ------------------------------------
Change
#interface FinalViewController : UIViewController <NSCoding, MainViewController>
to
#interface FinalViewController : UIViewController <NSCoding, MainViewControllerDelegate>
This might be a typo but:
#interface FinalViewController : UIViewController <NSCoding, MainViewController>
should be:
#interface FinalViewController : UIViewController <NSCoding, MainViewControllerDelegate>
Also remove the import of "FinalViewController.h" from MainViewController.h.
And your other warning can be fixed by changing:
#interface FinalViewController ()
to:
#interface FinalViewController () < MFMailComposeViewControllerDelegate>
and change:
mainVC.delegate = self;
to:
mainVC.mailComposeDelegate = self;
Since I switched my iOS project to ARC, I keep getting this compiler error:
No visible #interface for 'CDViewController' declares the selector
'setUseAgof:'
In this line:
[self.viewController setUseAgof:false];
In this file:
AppDelegate.m
#import "AppDelegate.h"
#import "MainViewController.h"
#import <Cordova/CDVPlugin.h>
#import "NSString+MD5.h"
#implementation AppDelegate
#synthesize window, viewController;
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
// (...)
[self.viewController setUseAgof:false]; // <-- HERE
// (...)
return YES;
}
#end
Although the method is definitely defined:
MainViewController.h
#import <Cordova/CDVViewController.h>
#import <ADTECHMobileSDK/ADTECHMobileSDK.h>
#interface MainViewController : CDVViewController <ATInterstitialViewDelegate>{
ATInterstitialView *interstitial;
}
- (void)setUseAgof:(BOOL)useAgofParam;
#end
#interface MainCommandDelegate : CDVCommandDelegateImpl
#end
#interface MainCommandQueue : CDVCommandQueue
#end
MainViewController.m
#import "MainViewController.h"
#interface MainViewController()
- (void)setUseAgof:(BOOL)useAgofParam;
#end
#implementation MainViewController
BOOL useAgof = true;
- (void)setUseAgof:(BOOL)useAgofParam
{
NSLog(#"1.) Setting useAgof = %d", (int)useAgofParam);
useAgof = useAgofParam;
}
I don't get it. What's wrong?
Update:
AppDelegate.h
#import <UIKit/UIKit.h>
#import <Cordova/CDVViewController.h>
#import <INFOnlineLibrary/INFOnlineLibrary.h>
#interface AppDelegate : NSObject <UIApplicationDelegate>{}
#property (nonatomic, strong) IBOutlet UIWindow* window;
#property (nonatomic, strong) IBOutlet CDVViewController* viewController;
#end
viewController seems to be declared as pointer of CDVViewController. You are calling a method which is part of MainViewController the class derived from CDVViewController. Method being called is part of derived class and not the base class, hence make viewController pointer of MainViewController instead.
Make sure the viewController property in your AppDelegate has a type of CDVViewController * rather than UIViewController *.
I've a main class where I want to define two protocols (1 used by a class A, the other by class B) (ios 6.1, xcode 4.6.3 , ARK mode, storyboard project).
According to official syntax, all my code seems to be correct.
But when I try to use the second delegate , nothing work correctly, my 2nd delegate does not respond
**HEADER myProtocols.h**
#import ...
#class myProtocols;
#protocol myProtocol1 <NSObject>
// list of methods and properties
doStuff:(float) myValue;
#end
#protocol myProtocol2 <NSObject>
// list of methods and properties
doOtherStuff:(float) myValue2 andText:(NSString *)myText andType:(NSString *)myType;
#end
#interface myProtocols:NSObject
{
__unsafe_unretained id <myProtocol1> _myDelegate1;
__unsafe_unretained id <myProtocol2> _myDelegate2;
}
#property (nonatomic, assign) id <myProtocol1> myDelegate1;
#property (nonatomic, assign) id <myProtocol2> myDelegate2;
#end
**MESSAGES myProtocols.m**
#import myProtocols.h
#implementation myProtocols
#synthesize myDelegate1 = _myDelegate1
#synthesize myDelegate2 = _myDelegate2
...
if ([_myDelegate1 respondsToSelector:#selector(doStuff:)])
[_myDelegate1 doStuff:3.5]; **// THIS DELEGATE WORK VERY WELL**
...
if ([_myDelegate2 respondsToSelector:#selector(doOtherStuff:andText:andType:)])
[_myDelegate2 doOtherStuff:4.5 andText:#"YES MAN" andType:#"YES BRO"];
**// THIS DELEGATE DONT WORK, IT'S LIKE IT DOESNT INIT**
...
#end
**HEADER classA.h**
#import "myProtocols.h"
#interface classA: UIViewController <myProtocol1>
#property(strong, nonatomic) myProtocols *myProtoVC;
//-(void) doStuff:(float) myValue; according to comments, nothing to do :(
#end
**MESSAGES classA.m**
#import "classA.h"
#interface classA ()
#end
#implementation classA
- (void)viewDidLoad
{
[super viewDidLoad];
_myProtoVC = [[myProtocols alloc] init];
_myProtoVC.myDelegate1 = self;
}
-(void) doStuff:(float) myValue
{
NSLog(#" YES VALUE IS %f",myValue);
}
**HEADER classB.h**
#import "myProtocols.h"
#interface classB: UIViewController <myProtocol2>
#property(strong, nonatomic) myProtocols *myProtoVC;
//-(void) doOtherStuff:(float) myValue2 andText:(NSString *)myText andType:(NSString *)myType; according to comments, nothing to do :(
#end
**MESSAGES classB.m**
#import "classB.h"
#interface classB ()
#end
#implementation classB
- (void)viewDidLoad
{
[super viewDidLoad];
_myProtoVC = [[myProtocols alloc] init];
_myProtoVC.myDelegate2 = self;
}
-(void) doOtherStuff:(float) myValue2 andText:(NSString *)myText andType:(NSString *)myType;
{
NSLog(#" YES VALUE IS %f and text %# and type %#",myValue2,myText,myType);
}
So, my mistake is to call [_myDelegate2 doOtherStuff..] directly inside a function in myProtocols called only by classA.
Then, if I want to call a function in myProtocols using both delegate I MUST init both these delegates in the class (A or B doesnt matter) I use to call this function:
**MESSAGES myProtocols.m**
#import myProtocols.h
#implementation myProtocols
#synthesize myDelegate1 = _myDelegate1
#synthesize myDelegate2 = _myDelegate2
-(void) pleaseDoIt
{
if ([_myDelegate1 respondsToSelector:#selector(doStuff:)])
[_myDelegate1 doStuff:3.5]; **// THIS DELEGATE WORK VERY WELL**
...
if ([_myDelegate2 respondsToSelector:#selector(doOtherStuff:andText:andType:)])
[_myDelegate2 doOtherStuff:4.5 andText:#"YES MAN" andType:#"YES BRO"];
**// THIS DELEGATE NOW WORK VERY WELL**
}
#end
**HEADER classA.h**
#import "myProtocols.h"
#import "classB.h"
#interface classA: UIViewController <myProtocol1>
#property(strong, nonatomic) myProtocols *myProtoVC;
#property(strong, nonatomic) classB *classBVC;
//-(void) doStuff:(float) myValue;
#end
**MESSAGES classA.m**
#import "classA.h"
#interface classA ()
#end
#implementation classA
- (void)viewDidLoad
{
[super viewDidLoad];
_myProtoVC = [[myProtocols alloc] init];
_classBVC = [[myProtocols alloc] init];
_myProtoVC.myDelegate1 = self;
_myProtoVC.myDelegate2 = _classBVC // THIS IS THE POINT!!!
[_myProtoVC pleaseDoIt];
}
-(void) doStuff:(float) myValue
{
NSLog(#" YES VALUE IS %f",myValue);
}
I'm trying to access to another class from my viewcontoller but is not working:
viewcontroller.h
#import <UIKit/UIKit.h>
#class firstClass; //nsobject class
#interface ViewController : UIViewController
{
firstClass *firstclass;
}
#property (retain,nonatomic) LEMZfirstClass *firstclass;
---
firstClass.h:
#import "LEMZViewController.h"
#interface firstClass : NSObject
{
ViewController *viewController;
}
#property (retain,nonatomic) ViewController *viewController;
-(void)doSomenthing;
firstClass.m:
#synthesize viewController;
-(void)doSomenthing
{
viewController.firstclass=self;
viewController.outPutLabel.text=#"This is my Label";
}
viewcontroller.m:
#synthesize firstclass;
- (void)viewDidLoad
{
[super viewDidLoad];
[firstclass doSomenthing];
}
it compiles with no errors but the label is never updated and for that matter the first class is never call it all. What I'm doing wrong? I'll really appreciate your help.
A few things I'm noticing:
Generally you would have the ViewController class handle updating its own UI elements, not another class.
Where is your outPutLabel variable? Is it created by code or an IBOutlet that is wired up in InterfaceBuilder?
Before you can call something on firstclass, you must create it. Something like this:
firstclass = [[firstClass alloc] init];
[firstclass doSomenthing];
The viewController.firstclass=self; line would be redundant then.
Your firstClass.h
#import <Foundation/Foundation.h>
#interface firstClass : NSObject
+(NSString *)doSomenthing; //Instance Class
#end
firstClass.m
#import "firstClass.h"
#implementation firstClass
+(NSString *)doSomenthing
{
return #"This is my Label";
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "firstClass.h"
#interface ViewController : UIViewController
#end
ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[firstClass doSomenthing];
outPutLabel.text=[firstClass doSomenthing];;
// Do any additional setup after loading the view, typically from a nib.
}
Note: Here I am using instance class. Before you work this code you must study about Instance class.