Objective C - Call method from another class - ios

I have 2 classes geoViewController and geoMainViewController
I have a method in the geoMainViewController called getFoo
It looks like this:
- (NSString *)getFoo
{
NSString* foo = #"This is foo";
return foo;
}
I am trying to call getFoo from the geoViewController class.
I have #import "geoMainViewController.h" in my geoViewController m file.
I am trying instantiate the geoMainViewController class and call the getFoo method from the viewDidLoad in my geoViewController class like this:
- (void)viewDidLoad
{
[super viewDidLoad];
geoMainViewController* mainVC = [[geoMainViewController alloc] init];
NSString* myFoo = [mainVC getFoo];
}
It seems to be instantiating the geoMainViewController class fine but I am getting an error on NSString* myFoo = [mainVC getFoo];
The error is - no visible #interface for 'geoMainViewController' declares the selector 'getFoo'
I am sure I am missing a step because I am very new to Objective C. I am just not sure what I am doing wrong.
Any help on this would be great.
Thanks!

In your geoMainViewController.h you should declare the selector to be visible:
-(NSString *)getFoo;

Did you put - (NSString *)getFoo in your geoMainViewController.h ?
You have to make those methods visible to the outside of your object through the .h file, so other objects know which selectors they respond to. Did the autoComplete fill in the message per chance?
#import <Foundation/Foundation.h>
#interface
{
}
#property (nonatomic,strong) ;
#property (nonatomic,strong) ;
#property (nonatomic, strong) ;
- (NSString *)getFoo
#end
EDIT: (You could also just make Foo a property by the way)

Did you declare it in your header file?
Header file contains all the function declarations in the .h file and you only include the .h file in your class. So it depends on .h file. .h file will have all the functions as the .m file.
Hope it helps you.

You are misunderstanding how to use a view controller. While you can technically create an instance of a view controller in order to call one of its methods, you shouldn't do so. The normal approach is that the view controller is part of the view hierarchy and you can call methods on it when you have access to that instance. You are missing something fundamental here.
Your actual error is a missinh method declaration, I would suspect, but you have bigger problems to solve first.

Related

How to call a method in another class?

I would like to have only one class for control my menu.
I try used this:
In the .h
#define Generic ((AppDelegate*)[[UIApplication sharedApplication] delegate])
#import <UIKit/UIKit.h>
#interface Generic : UIViewController
- (IBAction)photo:(id)sender;
#property (nonatomic, strong) NSString *apareceMenu;
#end
in the .m
- (IBAction)photo:(id)sender{
NSLog(#"Ok");
}
Now i need read the - (IBAction)photo in other class, But i don't know how.
I believe to be something
[Generic photo];
Could someone help me please?
Follow the instructions in this post:
How to call method from one class in another (iOS) https://stackoverflow.com/a/9731162/2274694
[Generic photo:] is correct method to call the function. Before the you must do this steps in another class.
Generic *genericObj = [[Generic alloc]initWithNibName:#"Generic" bundle:nil];
then you call your class like,
[genericObj photo];
create object for Generic class and call photo via that object
[genericObj photo];

iOS error: No visible #interface for 'xxxx' declares the selector 'alloc'

Here is my TextValidator class:
//TextValidator.h
#import <Foundation/Foundation.h>
#interface TextValidator : NSObject
- (BOOL) isValidPassword:(NSString *)checkPassword;
- (BOOL) isValidEmail:(NSString *)checkString;
- (BOOL) isEmpty:(NSString *)checkString;
#end
// TextValidator.m
#import "TextValidator.h"
#implementation TextValidator
- (BOOL) isEmpty:(NSString *)checkString
{
return YES;
}
- (BOOL) isValidPassword:(NSString *)checkPassword
{
return YES;
}
- (BOOL) isValidEmail:(NSString *)checkString
{
return YES;
}
#end
This is the way I try to initialise the TextValidator class in ViewController.m:
//ViewController.h
#import <Foundation/Foundation.h>
#interface SignUpViewController : UIViewController <UITextFieldDelegate>
#end
//ViewController.m
#import "SignUpViewController.h"
#import "TextValidator.h"
#interface SignUpViewController ()
#property TextValidator *myValidator;
#end
#implementation SignUpViewController
- (void)viewDidLoad
{
[[self.myValidator alloc] init]; //iOS error: No visible #interface for 'TextValidator' declares the selector 'alloc'*
[super viewDidLoad];
}
#end
When I try to compile the code I get the following error:
No visible #interface for 'TextValidator' declares the selector 'alloc'.
TextValidator class inherits from NSObject and as far as I know init and alloc functions are already defined at the base class. So why does the program gives such an error?
Note that, I already checked this topic and it doesn't work for me.
My psychic debugger, without reading your code, tells me you're calling alloc on an object instance, rather than a class. The alloc method is a static method defined by classes (typically inherited from NSObject) that returns a new instance of the underlying object. You can't ask an instance to allocate itself!
Now looking at the code, I see that you want:
self.myValidator = [[TextValidator alloc] init];
to construct a new instance, and assign it to the myValidator property.
Replace
[[self.myValidator alloc] init];
with
self.myValidator = [[TextValidator alloc] init];
The error signals that you have not implemented the alloc instance method for self.myValidator, which is true. But that's a class method that applies for all NSObject objects.
Your syntax of creating object is incorrect. Correct code:
self.myValidator = [[TextValidator alloc] init];
If you experience this randomly (like when you are changing branches), not because you forgot to declare selector.
Go to file inspector > Target Membership
uncheck the targets
then check it again
This will refresh your project.pbxproj
Then if you build, you'll see your real problem
For Others :
Check the varible name is not like the class name.
Well it happend to me.
XXXViewController * XXXViewController = [[XXXViewController alloc] init];
Don't tell anyone like I did right now.
For those who get the error of "no visible #interface for declares the selector ..."
such an error usually happens when you have mistyped the name of the method, or that method doesn't belong to that class at all and doesn't exist in your class
I had this problem today and solved it on my own. Basically you could also not be satisfying all the requirements of the function / procedure.
Go into the class itself and make sure your declaring all the requirements.
I took the class out of the header library and compared it word for word to verify it matches the function using it.

Creating properties only visible to subclass in Objective-C

I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
#interface AbstractClass : UIView
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
…
#protocol ButtonDelegate
#required
- (void) buttonWasPressed;
#end
…
#interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
#implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Do like UIGestureRecognizer does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h.
Only import this in the *.m-files. Never include it in any public header.
All private properties and methods goes into *.m-files. Use the #interface ClassName ()
Example https://gist.github.com/hfossli/8041396
how to my subclass can inherit some properties from its superclass
without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
#interface Animal : NSObject
{
#protected
NSString *name; // default access. Only visible to subclasses.
}
#end
#implementation Animal
-(NSString*)description {
return name;
}
#end
#interface Cow : Animal
#end
#implementation Cow
-(id)init {
self=[super init];
if (self){
name = #"cow";
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
NSLog(#"%#", cow); // prints the name through internal access
// error accessing from the outside: NSLog(#"%#", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(#"%#", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those
properties
Which one is it?
Create an empty category on top of your implementation file (.m):
#interface AbstractClass()
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
#interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
#end
I am not sure about this, but give a try.
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's #synthesize, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
#interface Abstract ()
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
#implementation Abstract
#synthsize buttonDelegate;
#end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without #synthsize into all subclasses:
#interface MySubclass : Abstract
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of #synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.

How to use an internal method in a Objective-C category?

Trying to extend the capabilities from a open source project, I wrote a category for add a new method. In this new method, the category needs to access to an internal method from the original class, but the compiler says that it can't find the method (of course, is internal). Is there any way to expose this method for the category?
EDIT
I don't want to modify the original code, so I don't want to declare the internal method in the original class header file.
The code
In the original class implementation file (.m), I have this method implementation:
+(NSDictionary*) storeKitItems
{
return [NSDictionary dictionaryWithContentsOfFile:
[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:
#"MKStoreKitConfigs.plist"]];
}
In the category, I want to add this method:
- (void)requestProductData:(NSArray *(^)())loadIdentifierBlock
{
NSMutableArray *productsArray = [NSMutableArray array];
NSArray *consumables = [[[MKStoreManager storeKitItems] objectForKey:#"Consumables"] allKeys];
NSArray *nonConsumables = [[MKStoreManager storeKitItems] objectForKey:#"Non-Consumables"];
NSArray *subscriptions = [[[MKStoreManager storeKitItems] objectForKey:#"Subscriptions"] allKeys];
if(loadIdentifierBlock != nil) [productsArray addObjectsFromArray:loadIdentifierBlock()];
[productsArray addObjectsFromArray:consumables];
[productsArray addObjectsFromArray:nonConsumables];
[productsArray addObjectsFromArray:subscriptions];
self.productsRequest.delegate = self;
[self.productsRequest start];
}
In every line in which I call storeKitItemscompiler says: Class method "+storeKitItems" not found ...
This is trivial, make a forward declaration of the method.
Unfortunately, in obj-c, every method declaration must be inside #interface, so you can make it work in your category .m file with another internal category, e.g.
#interface MKStoreManager (CategoryInternal)
+ (NSDictionary*)storeKitItems;
#end
No implementation is needed, this only tells the compiler the method is somewhere else, similarly to #dynamic with properties.
If you are only interested in removing the warning, you can also just cast the class to id, the following should work, too:
NSDictionary* dictionary = [(id) [MKStoreManager class] storeKitItems];
However, my favorite solution is to do it a bit differently, let's assume the following example:
#interface MyClass
#end
#implementation MyClass
-(void)internalMethod {
}
#end
#interface MyClass (SomeFunctionality)
#end
#implementation MyClass (SomeFunctionality)
-(void)someMethod {
//WARNING HERE!
[self internalMethod];
}
#end
My solution is to split the class into two parts:
#interface MyClass
#end
#implementation MyClass
#end
#interface MyClass (Internal)
-(void)internalMethod;
#end
#implementation MyClass (Internal)
-(void)internalMethod {
}
#end
And include MyClass+Internal.h from both MyClass.m and MyClass+SomeFunctionality.m
A category has no access to the private methods of a class. It's no different than trying to call those methods from any other class. At least if you call the private method directly. Since Objective-C is so dynamic, you can call private methods (which is a bad idea) using other means such as using performSelector or with NSInvocation.
Again, this is a bad idea. An update to the implementation of the class could break your category.
Edit: Now that there is code posted -
Since the +storeKitItems method is not declared in the .h file, no category or other class can access the private method.
In you category implementation file you can define and informal protocol for the method
#interface YourClasses (ExternalMethods)
+(NSDictionary*) storeKitItems;
#end
This will stop the compiler from complaining about not knowing of the method storeKitItems in you category.

linking a static library in ios

I have created a math based application in Xcode 4.4. I am using tabbar based app with the help of storyboard.
I have written all my math functions in a separate class called CalculationMethods which is the subclass of NSObject.
My ViewController:
// FirstViewController.h
#import <UIKit/UIKit.h>
#import "CalculationMethods.h"
#interface FirstViewController : UIViewController
#end
// FirstViewController.m
#import "FirstViewController.h"
#import "CalculationMethods.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%f",[self julianDateFinder: [self currentDayMonthAndYearFinder]]);
}
#end
As you can see I have included my CalculationMethod.h file in both FirstViewController.h and the FirstViewController.m file, but when I use the methods of that class such as julianDateFinder and currentDayMonthAndYearFinder, Xcode errors, saying:
"No Visible #interface for 'FirstViewController' declares the selector 'CurrentDayMonthAndYearFinder'"
I am new to iOS and XCode. Can anyone help me solve the error?
In the FirstViewController, to use any of the methods in the CalculationMethods class, you need to create an instance of CalculationMethods. And then access a method using this syntax: [instanceOfCalculationMethods aMethodInCalculationMethods];
For example in your case, try this:
In the FirstViewController.h file, before the #end:
CalculationMethods *_calculationMethods;
And in the viewDidLoad method:
_calculationMethods = [CalculationMethods alloc] init];
NSLog(#"%f",[_calculationMethods julianDateFinder: [_calculationMethods currentDayMonthAndYearFinder]]);
I think you're misunderstanding how Objective C works slightly.
Without adding details of the CalculationMethods.h header file I can't help you much, but that compiler warning is telling you that FirstViewController doesn't have the method currentDayMonthAndYearFinder.
The reason that this is the case is because you're calling performing the selector CurrentDayMonthAndYearFinder on self which in the context of your FirstViewController instance is in fact the instance of FirstViewController
You said it yourself that your method CurrentDayMonthAndYearFinder is on your CalculatorMethods class so I suggest you either create an instance of your CalculatorMethods class or call the class method named CurrentDayMonthAndYearFinder on your CalculatorMethods class.
The problem here is weather or not you've defined instance methods or class methods.
Do yourself a favour and update your question with the contents of CalculationMethods.h

Resources