How to call a simple method declared in same ViewController? - iphone

I have declared a method in a view controller as:
-(void)rqst_run{
// method login here
}
When I wrote the code below (in the same file) in ViewDidLoad method after [super viewDidLoad];
[self rqst_run];
I get this error:
Method '-rqst_run' not found (return type defaults to 'id')
Any idea how to fix this?
Thx in advance
Stephane

Methods need to be declared before they're used.
You can solve your issue in one of two ways:
Move the declaration of rqst_run to before the declaration of viewDidLoad
Declare rqst_run in the #interface section for your class (either in the .h, or a class continuation in your .m)
The second is the best of those, so you would, for example, add something akin to the below at the top of your .m
#interface MyClass()
- (void) rqst_run;
#end
If you're not familiar with the concept of class continuations, this page offers a reasonable summary; in essence, an #interface section in the .m for declarations that you want kept out of the "public interface" (i.e. the .h)

Related

In interface file: when to use forward declaration for custom class as opposed to just including its header?

I have subclass of UIViewController called FullScreenViewController which has a property of type ImageScrollView which is subclassed UIScrollView object. The implementation and interface look as follows:
FullScreenViewController.h
#import <UIKit/UIKit.h>
#class ImageScrollView;
#interface FullScreenViewController : UIViewController
{
ImageScrollView *_scrollView;
}
#property(nonatomic, retain) ImageScrollView *scrollView;
#end
FullScreenViewController.m
#import "FullScreenViewController.h"
#import "ImageScrollView.h"
#implementation FullScreenViewController
#synthesize scrollView = _scrollView;
...
#end
now I subclass FullScreenViewController, and I try to access any properties from the ImageScrollView property and I keep getting the error message: "Property cannot be found". When I add ImageScrollView.h to the subclass, it works, but I'm not understanding this. I've already added ImageScrollView.h in FullScreenViewController, why should I have to add it again?
UPDATE: Rather than using a forward class declaration, I've included ImageScrollView.h in FullScreenViewController.h. I'm a little confused as to why I've ever use a forward declaration versus just including the .h file?
The reason you need to add it is you only have a #class declaration in your FullScreenViewController.h file. That only declares variable of type ImageScrollView* as pointers to object of class ImageScrollView. It does not give you access to the properties of ImageScrollView. To get access to methods and properties specific to ImageScrollView, you need to include the #interface declaration of ImageScrollView, which I assume is in your ImageScrollView.h file.
Given the header:
#interface FullScreenViewController : UIViewController
{
ImageScrollView *_scrollView;
}
#property(nonatomic, retain) ImageScrollView *scrollView;
#end
a forward declaration #class ImageScrollView is all that's needed. This tells the compiler that there is an objc class named ImageScrollView.
Of course, with a forward declaration, the interface is not visible where you need to use it unless you also #import ImageScrollView where you use it.
now I subclass FullScreenViewController, and I try to access any properties from the ImageScrollView property and I keep getting the error message: "Property cannot be found". When I add ImageScrollView.h to the subclass, it works, but I'm not understanding this. I've already added ImageScrollView.h in FullScreenViewController, why should I have to add it again?
ImageScrollView's declaration is not visible to the subclass FullScreenViewControllerSubclass. ImageScrollView.h is visible only where #imported. FullScreenViewController.m is not visible to FullScreenViewControllerSubclass.m. Therefore, you must write another #import in FullScreenViewControllerSubclass.m to use ImageScrollView there.
UPDATE: Rather than using a forward class declaration, I've included ImageScrollView.h in FullScreenViewController.h. I'm a little confused as to why I've ever use a forward declaration versus just including the .h file?
Use forwards for fast build times and sane, controlled dependency structures. This is a very time consuming problem to undo. And this problem gets much worse as the size of your programs and libraries increase:
Would you prefer a change to a header in a medium sized project to require recompilation of 50 sources with an average preprocessed input of 150,000 lines per translation, or would you favor that change to affect 6 sources with an average preprocessed input of 40,000 lines per translation? The difference here is that small change takes the incremental rebuild from seconds to minutes to complete, depending on how you have structured your dependencies and imports.
Have you tried accessing it using the alias _scrollView or scrollView.you should access it using _scrollView and see if u have imported the file in .m or .h as #class won't suffice.

receiver type *** for instance message is a forward declaration

In my iOS5 app, I have NSObject States class, and trying to init it:
states = [states init];
here is init method in States:
- (id) init
{
if ((self = [super init]))
{
pickedGlasses = 0;
}
return self;
}
But there is error in the line states = [states init];
receiver type "States" for instance message is a forward declaration
What does it mean? What am I doing wrong?
That basically means that you need to import the .h file containing the declaration of States.
However, there is a lot of other stuff wrong with your code.
You're -init'ing an object without +alloc'ing it. That won't work
You're declaring an object as a non-pointer type, that won't work either
You're not calling [super init] in -init.
You've declared the class using #class in the header, but never imported the class.
FWIW, I got this error when I was implementing core data in to an existing project. It turned out I forgot to link CoreData.h to my project. I had already added the CoreData framework to my project but solved the issue by linking to the framework in my pre-compiled header just like Apple's templates do:
#import <Availability.h>
#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#endif
I got this sort of message when I had two files that depended on each other. The tricky thing here is that you'll get a circular reference if you just try to import each other (class A imports class B, class B imports class A) from their header files. So what you would do is instead place a forward (#class A) declaration in one of the classes' (class B's) header file. However, when attempting to use an ivar of class A within the implementation of class B, this very error comes up, merely adding an #import "A.h" in the .m file of class B fixed the problem for me.
I was trying to use #class "Myclass.h".
When I changed it to #import "Myclass.h", it worked fine.
If you are getting this error while trying to use Swift class or method in Objective C: you forgot one of 2 steps Apple defined on this diagram:
Example:
Error shows up in your Test.m file:
Receiver 'MyClass' for class message is a forward declaration
In Obj-C files:
Step 1: check that Test.h has
#class MyClass;
Step 2: find *-Swift.h file name in Build Settings (look for Objective-C Generated Interface Header Name). Name will be something like MyModule-Swift.h
Step 3: check that Test.m imports the above header
#import <MyModule/MyModule-Swift.h>
In Swift file:
Ensure MyClass (or it's base class) inherits NSObject class.
Ensure #objc is before each method you want call from Obj-C.
Also, check Target Membership section (in File Inspector).
You are using
States states;
where as you should use
States *states;
Your init method should be like this
-(id)init {
if( (self = [super init]) ) {
pickedGlasses = 0;
}
return self;
}
Now finally when you are going to create an object for States class you should do it like this.
State *states = [[States alloc] init];
I am not saying this is the best way of doing this. But it may help you understand the very basic use of initializing objects.
Check if you imported the header files of classes that are throwing this error.
Make sure the prototype for your unit method is in the .h file.
Because you're calling the method higher in the file than you're defining it, you get this message. Alternatively, you could rearrange your methods, so that callers are lower in the file than the methods they call.
There are two related error messages that may tell you something is wrong with declarations and/or imports.
The first is the one you are referring to, which can be generated by NOT putting an #import in your .m (or .pch file) while declaring an #class in your .h.
The second you might see, if you had a method in your States class like:
- (void)logout:(NSTimer *)timer
after adding the #import is this:
No visible #interface for "States" declares the selector 'logout:'
If you see this, you need to check and see if you declared your "logout" method (in this instance) in the .h file of the class you're importing or forwarding.
So in your case, you would need a:
- (void)logout:(NSTimer *)timer;
in your States class's .h to make one or both of these related errors disappear.

Objective-C when to declare what methods in #interface

When and what methods should be declared in the #interface section of a class? As I understand, methods that describe what your class does should be declared in the #interface section, but other "helper" methods should not be declared. Is this a correct understanding from my side?
One way is to declare the instance methods in .h file. And, declare the private methods inside the .m, using a Category.
For example, in MyOwnClass.h file.
#interface MyOwnClass
- (void)aInstanceMethod;
#end
And, inside your MyOwnClass.m file, before the #implementation block,
#interface MyOwnClass (MyPrivateMethods)
- (void)aPrivateMethod;
#end
You usually should add your methods to the .h file when you want an external class to have access to it (public methods).
When they're private (only used internally by the class) just put them in your .m file.
Anyway, it's just a pattern. As Objective-C works with messages, even if you don't set a method in your .h file an external file can access it, but at least your auto-complete won't show it.
You should declare all your methods in your .h
The tip from EmptyStack is nice but it's just a tip.
If you don't intend to ship your binary as an SDK, you don't really need it.
Objective-C doesn't have (yet) private methods.

Why does this code example on Apple's dev site declare three interfaces for the same class?

I'm diving into iOS development while trying to grasp Objective-C and I'm still in that phase where, ever where I look, I see things that don't make any sense to a veteran C programmer like myself. In this Game Kit example on Apple's dev site, one of the header files declares a class interface, three different times...
#interface SessionManager : NSObject <GKSessionDelegate> {
NSString *sessionID;
GKSession *myGKSession;
NSString *currentConfPeerID;
NSMutableArray *peerList;
id lobbyDelegate;
id gameDelegate;
ConnectionState sessionState;
}
#property (nonatomic, readonly) NSString *currentConfPeerID;
#property (nonatomic, readonly) NSMutableArray *peerList;
#property (nonatomic, assign) id lobbyDelegate;
#property (nonatomic, assign) id gameDelegate;
- (void) setupSession;
- (void) connect:(NSString *)peerID;
- (BOOL) didAcceptInvitation;
- (void) didDeclineInvitation;
- (void) sendPacket:(NSData*)data ofType:(PacketType)type;
- (void) disconnectCurrentCall;
- (NSString *) displayNameForPeer:(NSString *)peerID;
#end
// Class extension for private methods.
#interface SessionManager ()
- (BOOL) comparePeerID:(NSString*)peerID;
- (BOOL) isReadyToStart;
- (void) voiceChatDidStart;
- (void) destroySession;
- (void) willTerminate:(NSNotification *)notification;
- (void) willResume:(NSNotification *)notification;
#end
#interface SessionManager (VoiceManager) <GKVoiceChatClient>
- (void) setupVoice;
#end
I see that each interface is different, but specify the same class name.
What's the reason for this?
I've also noticed this same behavior in other code examples, only instead of declaring multiple interfaces in the header file, you'll see an additional #interface block declared towards the top of the .m implementation file, typically above the #implementation block. Why?
Thanks so much in advance for your wisdom!
These are called Categories, and you can see them by the parentheses after the class name.
They're used to group methods into chunks instead of having them all in one big bunch. They can also be placed separate from the main class declaration. This is particularly useful inside .m files, where you may need to create utility methods for your class, but you don't want them visible to other objects for any reason (so you don't put them in the .h, which is imported by the other classes). Another common use is to group methods which correspond to a certain logical category, informal protocol, or what have you. Categories can be named (#interface MyClass (MyCategory)) or anonymous (#interface MyClass ()). The latter is usually used for generic private methods in your header.
(The reason you need categories to declare private methods in your .m is so the compiler knows about the methods — otherwise, you'll get a warning when you try to call such a method.)
Also, you can use categories to add methods to existing classes. For example, UIKit contains a category on NSString called NSString(UIStringDrawing). Or if you wanted to make your own:
#interface NSString (MyFoo)
+ (NSString *)fooString;
#end
//... somewhere else...
#implementation NSString (MyFoo)
+ (NSString *)fooString { return #"foo!"; }
#end
Note that you can't add instance variables with a category.
It is not defining the interface 3 times - there is only one interface.
what you are seeing are categories that add methods to the class
There is a base interface that defines the attributes and some methods - there is only one of these ant it defines how the object is stored in memory and is the only one that is needed.
Objective C looks up methods at run time. These methods do not need to be found at compile time and thus do not need to be declared in headers/interfaces etc. If they are not declared and you code calls them then you will get compile time warnings.
In this case one category with an empty name is used for private functions. I usually only put this interface in the .m file of the class so is not visible to other code as not in a header.
The second category is to add the methods to make SessionManager meet the GKVoiceChatClient protocol. The usual reason for doing this is to group code covering a specific behaviour together.
Another reason for using categories is to add methods to an existing class like NSString -you can create your own category adding methods without subclassing the class as you have to do in many other OO languages including Java and C++
This is for code upkeep purposes i belive...its easier to looks through the different labeled interfaces, for example (VoiceManager) which is for voice manager setup and methods related to that, and you have the one interface dealing with the GK delegate methods and whatever interaction with gamekit there will be...as opposed to looking at one huge interface file and having to pick out what you are looking for...They can also divide the implementations in this way too so its easier to look through and navigate.
In order:
The first interface declaration is the actual interface declaration that declares the class as a subclass of NSObject and implementing the GKSessionDelegate protocol. It also declares the instance variables and a selection of methods.
The second interface declaration is a class extension. It can be thought of as a kind of anonymous category. So we'll skip it for now and come back to it.
The third interface is a category declaration. Categories allow you to do two things. They allow you to split the class implementation across multiple source files. In the above, you'll have
#implementation SessionManager
// methods declared in the first #interface
#end
#implementation SessionManager(VoiceManager)
// methods declared in the third #interface
#end
The two #implementations need not be in the same source file.
The other thing a category can do is allow you to extend already existing classes.e.g. #interface NSString(MyStringMethods)...
Coming back to the class extension, this is a bit like an anonymous category. The implementations of the methods declared in it must be in the main #implementation block. The purpose of the class extension is to allow you to declare private API separately from the class's header file. I normally put one in the.m file at the top if I have methods that should only be used from the class. Although, note that this is only a compile time restriction. There is nothing to stop a class extension message from being sent by anybody at run time.

How can you share ivars between classes.?

In one classes .h i have
NSMutableArray *rountines;
and in another classes .m i want to do something like this
[routines addOject:#"Hello];
the other class is an ModalViewController type set up.
So, in essence i'd like the .m file of the MVC to be able to read, and edit and do other things to the ivars i declare in the header.
Cheers,
Sam
edit
Another example, which is similar to what im trying to achieve is like an edit screen.
You can't share ivars between classes really. ivar stands for instance variable, and that is a variable that belongs to some particular instance of an object. The way to solve this problem is to allow other objects to access this object's state. This is most commonly done through setter and getter methods. Objective-C 2.0 makes this easier by providing the #property and #synthesize keywords.
If you had access to the object that had the routines array, you could access it through its property (getter method) like this:
[[someObject routines] addObject:#"hello"];
you can either do this by making the ivars you want to share globals (in which case they would be ivars of the singleton class or app delegate class) or by passing a reference to the class you want to modify the ivars of as an argument to a method of the ModalViewController class:
#implementation ModalViewController
......
-(void)addObjectToRoutinesFromClass: (MyClass *)myclass {
[myclass.routines addObject:#"Hello"];
}
#implementation MyClass
......
ModalViewController *myModalViewController = [[ModalViewController alloc] init];
[myModalViewController addObjectToRoutinesFromClass:self];
#end