Error when compiling: No visible #interface declares the selector - objective-c

In one class I have the following
AlertEditorContainerViewController.m
#import "AlertEditorContainerViewController.h"
#interface AlertEditorContainerViewController ()
-(void)swapViewControllers;
#end
#implementation AlertEditorContainerViewController
#synthesize currentSegueIdentifier;
#synthesize segIndex;
- (void)swapViewControllers
{
self.currentSegueIdentifier = ([self.currentSegueIdentifier isEqual: SegueIdentifierFirst]) ? SegueIdentifierSecond : SegueIdentifierFirst;
[self performSegueWithIdentifier:self.currentSegueIdentifier sender:nil];
}
#end
The in another class I try to call it
AlertEditorViewController.h
#interface AlertEditorViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
AlertEditorContainerViewController *containerViewController;
}
AlertEditorViewController.h
#import "AlertEditorViewController.h"
#implementation AlertEditorViewController
- (IBAction)segmentSwitchValueChanged:(id)sender
{
[containerViewController swapViewControllers];
}
#end
This gives the error "No visible #interface for AlertEditorContainerViewController declares the selector swapViewControllers'
I have looked up all of the other similar queries and they all seem to point at typos etc which I can't find in my code.

Declare -(void)swapViewControllers in your AlertEditorContainerViewController.h file, not your .m file.
For information on this problem, you'll want to check out this Stack Overflow question, but in short, by declaring the method within the #interface block located in your .m file, you're effectively making it a private method (inaccessible by other implementation files). From the link:
The interface section in the implementation file allows you to declare variables, properties, and methods that are private, meaning that they won't be seen by other classes.
The compiler knows it's there within the scope of that particular file, but other files can't access or even see that method as being defined.

Related

Add ivar and property to class using class extension

I'm trying to add an instance variable and a property to an existing class. I want to do this to extend the base class of an open source library, without modifying the source code (for easier code management).
The documentation says
Unlike regular categories, a class extension can add its own
properties and instance variables to a class. If you declare a
property in a class extension [...] the compiler will automatically
synthesize the relevant accessor methods, as well as an instance
variable, inside the primary class implementation.
I tried to do this in a test app. I have an empty class ClassA:
ClassA.h
#import <Foundation/Foundation.h>
#interface ClassA : NSObject
#end
ClassA.m
#import "ClassA.h"
#implementation ClassA
#end
Then I added an extension:
ClassA+Ext.h
#import "ClassA.h"
#interface ClassA ()
#property (nonatomic) NSString *name; // <-- this is my new property
#end
Finally in my AppDelegate I simply init a ClassA and try to set and then log the name.
#import "AppDelegate.h"
#import "ClassA.h"
#import "ClassA+Ext.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
ClassA *a = [[ClassA alloc] init];
a.name = #"test";
NSLog(#"Name: %#", a.name);
}
#end
This compiles and runs, but I get this error on the console:
2013-05-10 00:58:08.598 Test[53161:303] -[ClassA setName:]: unrecognized selector
sent to instance 0x108a1a630
2013-05-10 00:58:08.600 Test[53161:303] -[ClassA setName:]: unrecognized selector
sent to instance 0x108a1a630
The name is not logged. And if I set a breakpoint and inspect the ClassA instance, it doesn't have a name ivar. What am I doing wrong? Isn't this actually possible to do?
Your understanding is incorrect. You added a property through a class extension. This property should only be able to be used inside your class. It should not be used as a true "property" for your class in which you can change it through external instantiation. Think of it as a pseudo private instance variable.
I believe what you want to do is simply subclass your Class A.
Another viable solution proposed was:
"You can write a category to wrap it into -[setAssociatedObject:forKey:]" when using objc_setAssociatedObject --> by #Artur
I think class extensions are meant to be put in the class.m files, usually above the #implementation of the class.

inherit methods declared in .m file

I now know there is no protected method in Objective-C and here is my problem.
I have two viewControllers with many functions and properties that are shared. My vision was to have a BaseViewController holding the shared methods and properties, and from it two classes will inherit and override the needed functionality while using the same variables,
I don't wish to convert the shared functions to public by placing them in the .h file
To help clarify my question I'm adding code :)
#interface BaseViewController ()
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *uiButtons;
- (void)setBtns:(NSArray *)p_btns; //tried with & without this line
#end
#implementation BaseViewController
- (void)setBtns:(NSArray *)p_btns {
uiButtons = p_btns;
//do something generic with the buttons (set font, image etc.)
}
#end
#interface DerivedViewController ()
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *buttonsConnectedToTheActualView;
#end
#implementation DerivedViewController
- (void) setBtns:(NSArray *)p_btns {
[super setBtns:p_btns];
//do something specific with the buttons (decide if they face up or down according to this class logic)
}
#end
The call to [super setBtns:p_btns]; raises an error:
DerivedGameViewController.m:No visible #interface for 'BaseViewController' declares the selector 'setBtns:'
How can I achieve this? Can someone post a snippet or point to my mistake (in code or concept).
Just create a second header with the protected methods declared in a category. Name and document the header appropriately.
UIGestureRecognizer.h and UIGestureRecognizerSubclass.h may server you as an example.

How to simulate protected properties and methods in objective-c [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Protected methods in objective-c
The way to declare private properties is simple.
You declare that in extension that's declared in .m files.
Say I want to declare protected properties and access it from the class and subclass.
This is what I tried:
//
// BGGoogleMap+protected.h
//
//
#import "BGGoogleMap.h"
#interface BGGoogleMap ()
#property (strong,nonatomic) NSString * protectedHello;
#end
That one is compile. Then I added:
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap ()
-(NSString *) protectedHello
{
return _
}
#end
Problem starts. I can't implement class extension outside the original .m files it seems. Xcode will demand something inside that bracket.
If I do
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap (protected)
-(NSString *) protectedHello
{
return _
}
#end
I cannot access the ivar of _protectedHello declared in BGGoogleMap+protected.h
Of course I can use regular category rather than extension, but that means I can't have protected properties.
So what should I do?
The Objective-C Programming Language says this:
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class.
So you could just implement your class extension's methods in the class's main #implementation. That is the simplest solution.
A more complicated solution is to declare your “protected” messages and properties in a category, and declare any instance variables for that category in a class extension. Here's the category:
BGGoogleMap+protected.h
#import "BGGoogleMap.h"
#interface BGGoogleMap (protected)
#property (nonatomic) NSString * protectedHello;
#end
Since a category cannot add an instance variable to hold protectedHello, we need a class extension also:
`BGGoogleMap_protectedInstanceVariables.h'
#import "BGGoogleMap.h"
#interface BGGoogleMap () {
NSString *_protectedHello;
}
#end
We need to include the class extension in the main #implementation file so that the compiler will emit the instance variable in the .o file:
BGGoogleMap.m
#import "BGGoogleMap.h"
#import "BGGoogleMap_protectedInstanceVariables.h"
#implementation BGGoogleMap
...
And we need to include the class extension in the category #implementation file so that the category methods can access the instance variables. Since we declared the protectedHello property in a category, the compiler will not synthesize the setter and getter method. We have to write them by hand:
BGGoogleMap+protected.m
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap (protected)
- (void)setProtectedHello:(NSString *)newValue {
_protectedHello = newValue; // assuming ARC
}
- (NSString *)protectedHello {
return _protectedHello;
}
#end
Subclasses should import BGGoogleMap+protected.h to be able to use the protectedHello property. They should not import BGGoogleMap_protectedInstanceVariables.h because the instance variables should be treated as private to the base class. If you ship a static library without source code, and you want users of the library to be able to subclass BGGoogleMap, ship the BGGoogleMap.h and BGGoogleMap+protected.h headers, but don't ship the BGGoogleMap_protectedInstanceVariables.h header.
I wish I could tell you otherwise but you just can't. See this question for more information: Protected methods in Objective-C.
I am not sure, what you want to do? Something Hacking or Cracking of Data Abstraction out of OOPS concept?
Extensions are used to add properties. You have successfully added private property as in
#import "BGGoogleMap.h"
#interface BGGoogleMap ()
#property (strong,nonatomic) NSString * protectedHello;
#end
What are you doing in this ?
#import "BGGoogleMap+protected.h"
#implementation BGGoogleMap ()
-(NSString *) protectedHello
{
return _
}
#end
You have extended a class, now you are again implementing same class !!! Twice!!! And category only comes with .h file. I guess you are creating yourself a .m file, that not acceptable.
Private properties cant be accessed outside the class, it can be accessed only from the base class or subclass. That is what the error is.
I can't implement class extension outside the original .m files it seems.
Yes this is abstraction and data hiding of Objective-c !!!

Varieties of #interface declarations, some with parentheses

I've noticed a variety of #interface declarations for Objective-c classes. I'd like to understand why developers declare #interface in the following ways:
// in the .h file
#interface MyClass : NSObject
// ...
#end
// in the .m file (what's the purpose of the parens?)
#interface MyClass ()
// more property declarations which seem like they can go in the .h file
#end
// again in the .m file (what's the purpose of private?)
#interface MyClass (Private)
// some method declarations
#end
This is just a normal class interface, inheriting from NSObject, where you declare ivars, properties and methods
// in the .h file
#interface MyClass : NSObject
// ...
#end
The following two are categories, which allow you to add methods to a class. It is not a subclass however (do not declare a method with the same name, as you won't be able to access the original one). If you have a named category of the interface (like #interface MyClass (Private)), then the implementation should be provided in #implementation MyClass (Private), in the case of unnamed categories (also called extensions), the implementation can be provided as usual. Note that extensions also allow you to add ivars to the class while (named) categories do not.
// in the .m file (what's the purpose of the parens?)
#interface MyClass ()
// more property declarations which seem like they can go in the .h file
#end
// again in the .m file (what's the purpose of private?)
#interface MyClass (Private)
// some method declarations
#end
It is used to declared private methods.
This response explain this in details: What are best practices that you use when writing Objective-C and Cocoa?
What ever goes in the .m file is private. the parens are for categories so you can segment your code into categories to make it more readable. because the code is in .m and private, they called the category Private.

Dynamically typed class generates compiler warnings on method selection

Perhaps this is the wrong way to go about this, but it seems like such a clean and workable approach that I wonder how I can make the compiler warning go away?
#interface SomeView : UIView {
NSString *stringOfsomeImportance;
RelatedClass *niftyService;
}
#property (nonatomic, copy) NSString * stringOfnoImportance;
#property (nonatomic, retain) RelatedClass *niftyService;
#implementation
-(void)someMethod;
-(void)otherMethods;
#implementation RelatedClass *pvSomeObj = [[RelatedClass alloc] initWithSender:self];
[self setNiftyService:pvSomeObj];
Now, looking at the RelatedClass implementations...
#interface RelatedClass : NSObject {
id thesender;
#property (nonatomic, retain) id thesender;
#implementation
[thesender otherMethods]; // this generates a compiler warning
// that otherMethods cannot be found
// in SomeView, though it *is* found
// and seems to execute just fine
This seems like a valid approach, so I'm left wondering why the warning?
Is there a way to better "explain" this to the compiler?
Could someone kindly share if this type of linkage is encouraged or if there is a better way to link two related, interdependent classes that need to communicate with one another?
I can't statically declare the sender object (SomeView) in RelatedClass because that seems to cause a recursion problem, as SomeView is defined with RelatedClass as a member...
Any suggestions?
You can define a protocol and say that your thesender object must conform to it:
#protocol MyProtocol
-(void)otherMethods;
#end
#interface RelatedClass : NSObject {
id<MyProtocol> thesender; // Now compiler knows that thesender must respond
// to otherMethods and won't generate warnings
}
You can send otherMethods message another way (you may need to define theSender as NSObject here):
if ([theSender respondsToSelector:#selector(otherMethods)])
[theSender performSelector:#selector(otherMethods)];
Edit: Actually you can also define thesender as SomeView* in your RelatedClass using forward class declaration:
//SomeView.h
#class RelatedClass;
#interface SomeView : UIView {
RelatedClass *niftyService;
}
// then include RelatedClass.h in SomeView.m
//RelatedView.h
#class SomeView;
#interface RelatedClass : NSObject {
SomeView* thesender;
}
// then include SomeView.h in RelatedClass.m
In your headers, you can forward declare classes that you want to use. In your implementation files, you can include the full header of those classes that you forward-declared.
For example:
SomeView.h
#import <FrameworkHeader.h>
// Here, you are saying that there is a class called RelatedClass, but it will be
// defined later.
#class RelatedClass;
#interface SomeView : UIView
{
RelatedClass *niftyService;
}
#end
SomeView.m
#import "SomeView.h"
#import "RelatedClass.h"
// By including "RelatedClass.h" you have fulfilled the forward declaration.
#implementation SomeView
// Can use "RelatedClass" methods from within here without warnings.
#end
RelatedClass.h
#import <FrameworkHeader.h>
#class SomeView;
#interface RelatedClass
{
SomeView *someView;
}
// methods
#end
RelatedClass.m
#import "RelatedClass.h"
#import "SomeView.h"
#implementation RelatedClass
// Can use "SomeView" methods from within here without warnings.
#end
id thesender = ....;
[thesender otherMethods]; // this generates a compiler warning
// that otherMethods cannot be found
// in SomeView, though it *is* found
// and seems to execute just fine
For the above to generate the warning as you describe, it is entirely because the method -otherMethods has not been declared someplace where the compiler sees the declaration before attempting to compile the call site.
That is, the declaration of the method:
- (void) otherMethods;
Must appear in a header file that is imported -- directly or indirectly -- by the implementation file compiling that particular call site or the method declaration must appear in the #implementation before the call site.