I created a class called Datahandler with 2 methods. In my LoginViewController, I can use them, but in another ViewController they cannot be found.
This is my DataHandler.h file:
#import <Foundation/Foundation.h>
#interface DataHandler : NSObject
- (int) loginOnServer:(NSString *)username password:(NSString *)password;
- (NSString *) getJsonFromServer;
#end
In my LoginViewController, both methods are found.
LoginViewController.m:
#import "DataHandler.h"
...
#interface LoginViewController ()
...
#end
#implementation LoginViewController
- (void) checkLogin:(NSString *)email password:(NSString *) password
{
DataHandler *dataHandler = [[DataHandler alloc] init];
int result = [dataHandler loginOnServer:email password:password];
...
}
...
#end
FirstViewController.m:
#import "DataHandler.h"
...
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad
{
...
DataHandler *dh = [[DataHandler alloc] init];
NSString *json = [dh getJsonFromServer];
...
}
What I get there is:
FirstViewController.m:32:23: No visible #interface for 'DataHandler' declares the selector 'getJsonFromServer'
What am I doing wrong?
Thank you.
Edit 1:
There was another old class called DataHandler in my project folder, which was used instead of the this one.
Please delete your or rename your another DataHandler file and give the reference in your buildPhases (Compile sources)
As you can see log is showing no visible interface that means definition of method is not available in your another DataHandler.h, therefore receiver isn't able to get the declaration of your method.
Related
I have a DataHandler class which acts like a singleton, and it has sharedHandler object method. I use it throughout the whole project, but for some reason, I can't use it in AppDelegate.
DataHandler.h
#import <Foundation/Foundation.h>
#interface DataHandler : NSObject
+ (id)sharedHandler;
- (void)logout;
#end
DataHandler.m
#import "DataHandler.h"
/**
* Singleton static method
* #return singleton instance
*/
+ (id)sharedHandler {
static DataHandler *sharedHandler = nil;
#synchronized (self) {
if (sharedHandler == nil)
sharedHandler = [[self alloc] init];
}
return sharedHandler;
}
-(void) logout {
// ...
}
#end
AppDelegate.m
#import "AppDelegate.h"
#import "DataHandler.h"
#implementation AppDelegate {
- (void)applicationWillResignActive:(UIApplication *)application {
[[DataHandler sharedHandler] logout];
}
#end
I keep getting:
Error: no known class method for selector 'sharedHandler`
Error: no known instance method for selector 'logout'
What is the cause of this behavior?
You have two files named DataHandler.h and the import in AppDelegate.m is picking up the wrong file. Note that it may be picking up a file that's not actually in your project, as long as it's in the folder on disk.
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'm trying to create a method that I can call from different viewControllers.
I have a class called Info.h/Info.m and in this I have a method: -
-(void) testFunc {
... Do something here
}
I then want to call this function in my ViewController. I tried the following but I can't get the testFunc to run.
#import "ViewController.h"
#import "Info.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
Info *targetsInstance = [[Info alloc] init];
[targetInstance testFunc];
}
#end
When I type [targetInstance testFunc] I get the error "No visible #interface for 'Info' declares the selector 'testFunc'"
In your Info.h file, you must declare -(void) testFunc as a method in the #interface section
#interface Info: UIViewController {
}
-(void) testFunc;
#end
assuming you declared the info class (I recommend using a capital letter for class names) correctly replace this:
[info testFunc];
with:
[targetsInstance testFunc];
Since the method is an instance method (due to the '-' character) you need an instance for invoking it.
I am trying to call a method in my data controller object to load the data for my application, but for some reason it is not being called. Below is what I have done to initialize it. Any help would be greatly appreciated.
ViewController:
header file:
#import <UIKit/UIKit.h>
#class DetailViewController;
#class DataController;
#import <CoreData/CoreData.h>
#import "JointCAD.h"
#interface TableViewController : UITableViewController {
}
#property (nonatomic, assign) DataController *dataController;
#end
implementation file:
#import "TableViewController.h"
#import "DataController.h"
#implementation TableViewController
#synthesize dataController;
- (void)viewDidLoad {
[dataController refreshData];
}
#end
Data Controller:
header file:
#import <Foundation/Foundation.h>
#import "JointCAD.h"
#import "JointCADXMLParser.h"
#import "TFHpple.h"
#interface DataController : NSObject {
TFHpple *xpathParser;
}
- (void)refreshData;
- (void)initXMLParser;
- (void)noCallsMessage;
- (void)noInternetMessage;
#end
implementation file:
#import "DataController.h"
#implementation DataController
XMLParser *xmlParser;
- (void)refreshData {
NSLog("Some Method");
}
Is 'dataController' Object being set by some other class? - I believe that's why you have set it as a property? Right?
If No, then Remove the property,#synthesize of 'dataController' and try simple allocation of your 'dataController' object and then try calling your method.
Hope it helps.
You either need to initialize "DataController" prior to actually calling one of it's methods, or you need to make the method, "refreshData" a class by changing it's "-" to a "+".
If you need an instance callback instead. You need to rewrite "viewDidLoad" like this:
- (void)viewDidLoad {
DataController *dataController = [[DataController alloc] init];
[dataController refreshData];
}
And get rid of the property declaration of dataController because you haven't initialized it. If you would prefer a property declaration instead, simply allocate the viewcontroller prior to calling a function from it.
- (void)viewDidLoad {
dataController = [[DataController alloc] init];
[dataController refreshData];
}
One last thing to note is that I (and probably Ray) assume that you're using a storyboard configuration. If you are using a xib configuration, you need to add initWithNibName: to each initialization of the view controller.
I hope that's helpful!
I have a test case and a helper class. In the helper class I want to use asserts too like here:
MainTests.h
#import <SenTestingKit/SenTestingKit.h>
#interface MainTests : SenTestCase
#end
MainTests.m
#import "MainTests.h"
#import "HelperClass.h"
#implementation MainTests
- (void)testExample {
HelperClass *helperClass = [[HelperClass alloc] init];
[helperClass fail];
}
#end
HelperClass.h
#import <SenTestingKit/SenTestingKit.h>
#interface HelperClass : SenTestCase
- (void)fail;
#end
HelperClass.m
#import "HelperClass.h"
#implementation HelperClass
- (void)fail {
STFail(#"This should fail");
}
#end
Sidenote: I had to make the helper class a subclass from SenTestCase to being able to access the assertion macros.
The assertion from the helper class is ignored. Any ideas why? How can I use assertions in helper classes?
I had this same problem today and came up with a hack that worked for my purposes. Poking into the SenTestCase macros, I noticed that they call [self ...] on the helper but didn't trigger the asserts. So, wiring up the source class to the helper got it working for me. Changes to your question classes would look like:
MainTests.h
#import <SenTestingKit/SenTestingKit.h>
#interface MainTests : SenTestCase
#end
MainTests.m
#import "MainTests.h"
#import "HelperClass.h"
#implementation MainTests
- (void)testExample {
// Changed init call to pass self to helper
HelperClass *helperClass = [[HelperClass alloc] initFrom:self];
[helperClass fail];
}
#end
HelperClass.h
#import <SenTestingKit/SenTestingKit.h>
#interface HelperClass : SenTestCase
- (id)initFrom:(SenTestCase *)elsewhere;
- (void)fail;
#property (nonatomic, strong) SenTestCase* from;
#end
HelperClass.m
#import "HelperClass.h"
#implementation HelperClass
#synthesize from;
- (id)initFrom:(SenTestCase *)elsewhere
{
self = [super init];
if (self) {
self.from = elsewhere;
}
return self;
}
- (void)fail {
STFail(#"This should fail");
}
// Override failWithException: to use the source test and not self
- (void) failWithException:(NSException *) anException {
[self.from failWithException:anException];
}
#end
It is entirely possible that additional overrides are needed for more advanced functionality, but this did the trick for me.