Dynamically typed class generates compiler warnings on method selection - objective-c

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.

Related

Error when compiling: No visible #interface declares the selector

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.

Why I am getting "Apple Mach -O Linker error"?

I have two UIViewControllers. They have two variables with the same names but in different files.
HomeViewController.h
#import <UIKit/UIKit.h>
#interface HomeViewController : UIViewController
#end
HomeViewController.m
#import "HomeViewController.h"
#import "DetailViewController.h"
#interface HomeViewController ()
#end
#implementation HomeViewController
bool search=true;
bool dbOpen=false;
....
#end
DetailViewController.h
#import <UIKit/UIKit.h>
#interface DetailViewController : UIViewController
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
bool search=true;
bool dbOpen=false;
....
#end
When I remove "search" and "dbOpen" variables from HomeViewController.m or DetailViewController.m files, it compiles successfully. Why this is happening? Variables are not in header files and m files don't know about each other?
Global variables (what you have) are global, it doesn't matter if they are in different files (also what makes them dangerous).
bool search;
A global can only be defined once or you will get a linker error. Also people will avoid you at social events.
Static variables are per file - this might have been what you meant..
static bool search;
Instance variables are per instance. This is probably what you meant. You should start by using Properties - the compiler will handle adding the instance variable that backs it.
Something along the lines of:
#property bool search;
I'm trusting that you mean to use bool and not the Objective-c type BOOL. Visibility is up to you. Define the property in the Interface if you want it to be public.
If you really don't want a property you should define your instance variables in the interface section.
#interface HomeViewController : UIViewController {
bool search;
}
#end
Just to make it more confusing.. If you really must define the Instance variables in the Implementation there is a way, but I can't bring myself to type it.
The variable declarations have to be in the #interface like:
#interface HomeViewController ()
BOOL search;
BOOL dbOpen;
#end
and
#interface DetailViewController ()
BOOL search;
BOOL dbOpen;
#end
To set their initial values add the assignment in for exam,e viewDidLoad
- (void)viewDidLoad
{
search = YES;
dbOpen = NO;
}
Note the other changes like BOOL and YES/NO.
Since you have declared these variables
bool search=true;
bool dbOpen=false;
as global, only one occurance of these variables can exist. Change the name of the global variables in "HomeViewController.m" or "DetailViewController.m"
This is classical error of using global variables. Try to avoid to use it. In general use the extern keyword.
You use extern with global variables to create unambiguous
declarations. In addition to helping the compiler, it also clues in
anyone reading the code that the global variable is defined (and
possibly initialized) elsewhere, but you're simply using it here
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
extern bool search=true;
extern bool dbOpen=false;
....
#end

Objective C - Can't set superclass property in subclass

Take this simple class hierarchy:
Tree.h:
#interface Tree : NSObject
#property (nonatomic, assign) id<TreeDelegate> delegate;
#end
Tree.m:
#implementation Tree
#synthesize delegate;
#end
Aspen.h:
#interface Aspen : Tree
- (void)grow:(id<TreeDelegate>)delegate;
#end
Aspen.m:
#implementation Aspen
- (void) grow:(id<TreeDelegate>)d {
self.delegate = d;
}
#end
When I try to do self.delegate = d;, I'm getting the following error:
-[Aspen setDelegate:]: unrecognized selector sent to instance 0x586da00
I was expecting the Tree parent class's delegate property to be visible to the subclass as-is, but it doesn't seem to be since the error indicates the parent class's synthesized setter isn't visible.
What am I missing? Do I have to redeclare the property at the subclass level? I tried adding #dynamic at the top of the implementation of Aspen but that didn't work either. Such a simple concept here, but I've lost an hour searching around trying to find a solution. Out of ideas at this point.
--EDIT--
The above code is just a very stripped-down example to demonstrate the issue I'm seeing.
I just tried your code, supplemented by the protocol, an object implementing it, the necessary import and a main function and on my system it works like a charm:
#import <Foundation/Foundation.h>
#protocol TreeDelegate <NSObject>
#end
#interface MyDelegate : NSObject <TreeDelegate>
#end
#implementation MyDelegate
#end
#interface Tree : NSObject
#property (nonatomic, assign) id<TreeDelegate> delegate;
#end
#interface Aspen : Tree
- (void)grow:(id<TreeDelegate>)delegate;
#end
#implementation Tree
#synthesize delegate;
#end
#implementation Aspen
- (void) grow:(id<TreeDelegate>)d {
self.delegate = d;
}
#end
int main(int argc, char ** argv) {
MyDelegate * d = [[MyDelegate alloc] init];
Aspen * a = [[Aspen alloc] init];
[a grow:d];
return 0;
}
I was finally able to figure this out. My actual code leverages a 3rd party static library that defines the classes Tree and Aspen in my example. I had built a new version of the static library that exposed the Tree delegate given in my example, however I did not properly re-link the library after adding it to my project and as a result the old version was still being accessed at runtime.
Lessons learned: be diligent with steps to import a 3rd party library, and when simple fundamental programming concepts (such as in my example text) aren't working, take a step back and make sure you've dotted i's and crossed t's.

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 !!!

Reference properteries declared in a protocol and implemented in the anonymous category?

I have the following protocol:
#protocol MyProtocol
#property (nonatomic, retain) NSObject *myProtocolProperty;
-(void) myProtocolMethod;
#end
and I have the following class:
#interface MyClass : NSObject {
}
#end
I have a class extension declared, I have to redeclare my protocol properties here or else I can't implement them with the rest of my class.
#interface()<MyProtocol>
#property (nonatomic, retain) NSObject *myExtensionProperty;
/*
* This redeclaration is required or my #synthesize myProtocolProperty fails
*/
#property (nonatomic, retain) NSObject *myProtocolProperty;
- (void) myExtensionMethod;
#end
#implementation MyClass
#synthesize myProtocolProperty = _myProtocolProperty;
#synthesize myExtensionProperty = _myExtensionProperty;
- (void) myProtocolMethod {
}
- (void) myExtensionMethod {
}
- (void) useMyConsumer {
[[[MyConsumer new] autorelease] consumeMyClassWithMyProtocol:self];
}
#end
MyConsumer will only be called from MyClass, so I don't want any other classes to see that MyClass implements methods on MyProtocol because they aren't public API. Similarly, I don't want MyConsumer to see the class extension within MyClass.
#interface MyConsumer : NSObject {
}
#end
#implementation MyConsumer
- (void) consumeMyClassWithMyProtocol: (MyClass<MyProtocol> *) myClassWithMyProtocol {
myClassWithMyProtocol.myProtocolProperty; // works, yay!
[myClassWithMyProtocol myProtocolMethod]; // works, yay!
myClassWithMyProtocol.myExtensionProperty; // compiler error, yay!
[myClassWithMyProtocol myExtensionMethod]; // compiler warning, yay!
}
#end
Is there any way I can avoid redeclaring the properties in MyProtocol within my class extension in order to implement MyProtocol privately?
What you've been referring to as an "anonymous category" is actually known as a class extension, and is used to declare private functionality in an implementation file. That last part is important, because it means that other classes will not be able to see the declarations that you put into a class extension (and they won't be able to see that your class implements the methods of MyProtocol). This is also probably what is responsible for #synthesize failing without redeclaring the properties.
Instead, declare your conformance to the protocol in the interface of your class, and add whatever methods you want to be public:
#interface MyClass : NSObject <MyProtocol> {
}
// public methods and properties go here
#end
If you add the protocol declaration to your interface, then it also removes the need for your consumer to specify it explicitly. Your consumer method can have the following signature instead:
- (void) consumeMyClassWithMyProtocol: (MyClass *) myClassWithMyProtocol;
EDIT: It sounds like you're looking for a way to selectively expose private functionality. First, I would try to consider a different architecture for what you're trying to accomplish, because what's about to follow is a rather unpleasant solution, and it's generally better OOP if everything is public or private.
With that said, Apple typically solves this problem by having a separate header file for the class in question, which declares the methods that should be visible. So you would have your class interface, in which you expose everything that should be completely public:
// MyClass.h
#interface MyClass : NSObject {
}
#end
And a separate header, in which you declare a category for pseudo-private stuff:
// MyClass+Private.h
#import "MyClass.h"
#interface MyClass (Private) <MyProtocol>
- (void)mySortaPrivateMethod;
#end
MyClass.m would implement everything from those two files, and could still have a class extension:
// MyClass.m
#import "MyClass.h"
#import "MyClass+Private.h"
#interface MyClass ()
- (void)myClassExtensionMethod;
#end
#implementation MyClass
// everything can go here
#end
Then your consumer would include MyClass+Private.h so that it can see the declarations there, and everyone else would simply use MyClass.h.