Forward class properties Objective C - objective-c

i am making an Mac OS X application and i'm trying to let classes know of each other
Controller creates View1 and View2
BaseView has a property of Controller
View1 and View2 extends from BaseView
here is my example
Controller Class
#import <Cocoa/Cocoa.h>
#import "View1.h"
#class View1;
#interface Controller : NSViewController
{
View1 *_view1;
}
#end
//////
#import "Controller.h"
#implementation Controller
- (id) init
{
self = [super init];
if( self )
{
_view1 = [[View1 alloc] initWithFrame:CGRectZero];
_view1.controller = self;
}
return self;
}
#end
BaseView Class
#import <Cocoa/Cocoa.h>
#import "Controller.h"
#class Controller;
#interface BaseView : NSView
{
Controller *_controller;
}
#property (nonatomic,assign) Controller *controller;
#end
//////
#import "BaseView.h"
#implementation BaseView
#synthesize controller = _controller;
#end
View Example Class
#import "BaseView.h"
#interface View1 : BaseView
#end
//////
#import "View1.h"
#implementation View1
#end
But it gives me this error:
Controller.m:23:16: Property 'controller' cannot be found in forward class object 'View1'
what do i do wrong?

When you use a forward declaration in your header file(e.g. #class View1;), you do not need to #import the header.
In your View1.h you don't declare a #class, that's where you get the error. Nevertheless I suggest you to use forward declaration in your header file and import the needed headers in your implementation file when you need the method declarations etc. - this will prevent you from a header loop, too.
your code should look like
#class BaseView;
#interface View1 : BaseView
#end
//////
#import "View1.h"
#import "BaseView.h"
#implementation View1
#end

I think the problem might not be in your code.
Are they in the same relative folder? Is BaseView in a different location? You might have to go to your project settings and adjust your User Header Search Paths if this is the case
Also, make sure that all of your files are set up for the target you are currently running, by clicking on them on the project navigator, and in the right-hand side menu check which targets it's marked

Related

Objective-c - control outlet from other class

I just like to play with coding for a hobby, so probably a noob question;
I have a simple storyboard for MacOS with 2 views. Both have there own classes (main class and subclass). How can I control a outlet in the subclass from the main class?
for example
I have a button (IBAction) in the mainclass and a textfield (IBOutlet) in the subclass. I want to set the stringvalue for the textfield with a click on the button in main.
I have searched a lot last days but just don't get it. (or just need a push in the right direction)
EDIT after JingJingTao's answer:
I used the control-drag function to open the second window.
I tried the code JingJingTao gives, but the textfield doesn't respond to the action.
My classes look like this now:
ViewController.h
#import <Cocoa/Cocoa.h>
#interface ViewController : NSViewController
- (IBAction)newText:(id)sender;
#end
ViewController.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
#property (nonatomic) ViewController2 *subclass;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)setRepresentedObject:(id)representedObject {
[super setRepresentedObject:representedObject];
}
- (void)newText:(id)sender {
self.subclass.textField.stringValue = #"button pressed";
}
#end
ViewController2.h
#import "ViewController.h"
#interface ViewController2 : ViewController
#property (nonatomic) IBOutlet NSTextField *textField;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
}
#end
Update:
I've attached two screenshots of what it looks like in the storyboard for the first suggestion,
1) Add a view to your ViewController, set the class at the top right to 'YourView', 'YourView' is a just an NSView, add a textfield to it and hook it up.
2) Add YourView as a property to your ViewController, i.e. #property (nonatomic) IBOutlet NSView *yourView; and hook it up.
Let me know if there are any issues.
You just need to put the textfield in the public interface of your subclass, so you can access it in your main class, although it does sound like you're using inheritance and I don't think you need to but that's another topic :D.
Example:
In MainClassViewController.m
#interface MainClassViewController ()
#propert (nonatomic) Subclass *subclass;
#end
#implementation MainClassViewController
// I guess you already add your subclass to the main viewcontroller because they display on the same screen.
- (void)yourButtonTapMethod {
self.subclass.textfield.text = #"Your value";
}
In Subclass.h
#interface Subclass : NSObject
#property (nonatomic) IBOutlet UITextfield *textfield;
I use Cocoa Touch instead of Cocoa, so maybe it's NSTextfield for you. Please let me know if this does not answer your question, good luck.

delegate don't work between 2 viewcontrollers

I get stuck on using the delegate method.
I have 2 views. In view A, I use a delegate to say I pressed a button to view B.
View B receives the message well.
I would like to sent a message to say that the view B has received the message.
So the view from A to B for my delegate works but the B to A is not working.
.h:
#import <UIKit/UIKit.h>
#protocol ButtonProtocolName <NSObject>
- (void)toucheEnter:(id)sender;
#end
#interface ClavierKsViewController : UIViewController
#property (nonatomic, assign) id <ButtonProtocolName> delegate;
#end
.m
#import "ClavierKsViewController.h"
#interface ClavierKsViewController ()
#end
#implementation ClavierKsViewController
-(IBAction)toucheEntreeClavier:(id)sender{
[self.delegate toucheEnter:sender];
}
#end
Now on view B.h:
#import "ClavierKsViewController.h"
#interface CaisseViewController : UIViewController<ButtonProtocolName>
#property (nonatomic,retain) ClavierKsViewController *clavierKsView;
b.m
- (void)viewDidLoad
{
[super viewDidLoad];
clavierKsView = [self.storyboard instantiateViewControllerWithIdentifier:#"clavierKsView"];
clavierKsView.delegate=self;
}
-(void)toucheEnter:(id)sender{
NSLog(#"valider");
}
in that sense it works
When I created a delegate from view B to view A in based on the same way, I still get the same message: can not find protocol declaration for delegate
The protocol cannot work is likely caused by circular dependency. The solution is to extract your protocol to another .h like "ButtonProtocolName.h" and import the protocol in both a.h and b.h

Objective-C message being sent to superclass

I have derived a class SignalView from UIView however when I send a message to my object of type SignalView it gets sent to a UIView and I get error :
-[UIView Initialise]: unrecognized selector sent to instance 0x1b3900
my object also appears as a UIView object in the debug watch window:
m_signalview UIView * 0x001b3900
the relevant code is:
// signalview.h
#import <UIKit/UIKit.h>
#interface SignalView : UIView
{
}
-(void)Initialise;
#end
//signalview.m
#import "SignalView.h"
#interface SignalView ()
#end
#implementation SignalView
-(void)Initialise
{
}
// viewcontroller.h
#import <UIKit/UIKit.h>
#import "SignalView.h"
#interface ViewController : UIViewController
#property (weak, nonatomic) IBOutlet SignalView *m_signalview;
#end
// viewcontroller.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize m_signalview;
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"%#", m_signalview);
[m_signalview Initialise];
}
H2C03 is right. its likely not a SignalView. I would check your outlet in your view's nib file in the interface builder inspector make sure it doesn't still say UIView. If it does change it to SignalView:
Should look like this:
Then it's simply an instance of UIView and not a SignalView. You're allocating and initializing UIView when you would need a SignalView instance. When you have something like this in your code:
m_signalView = [[UIView alloc] init];
change it to
m_signalView = [[SignalView alloc] init];
I see that m_signalview is an IBOutlet.
Are you connecting that to a UIView you added in Interface Builder?
If so you might need to set the right class in its properties so that the loader can create an object of the right class.

Objective-C delegate function not working correctly

I have an app that has three views. All three views have an Ad Banner at the bottom of the screen. The first view creates an audio streamer which is paused when the Ad Banner on this view is clicked. I'm trying to use the AdBanner delegate methods on the second view to stop/start the audio. When the Ad Banner is selected the AdBanner delegate methods should call my custom delegate functions. The code compiles and runs but doesn't function correctly.
Using NSLog I've determined that the Ad Banner is calling its delegate function correctly but this isn't calling the custom delegate.
Hope this makes sense. Any help would be appreciated. Here is my code.
SecondViewControler H-file
#import "SecondViewController.h"
#protocol demoViewControllerDelegate <NSObject>
#required
-(void)stopSent;
-(void)startSent;
#end
#interface SecondViewController ()
{
id<demoViewControllerDelegate> delegate;
}
#property (nonatomic, assign) id<demoViewControllerDelegate> delegate;
#end
SecondViewController M-file
#implementation SecondViewController
#synthesize delegate;
Protocols
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave {
[delegate stopSent];
return YES;
}
- (void)bannerViewActionDidFinish:(ADBannerView *)banner{
[delegate startSent];
}
FirstViewController H-file
#import <QuartzCore/QuartzCore.h>
#import "iAd/iAd.h"
#import <MessageUI/MessageUI.h>
#import "AudioStreamer.h"
#import "Reachability.h"
#import "SecondViewController.h"
#import "MFAppDelegate.h"
#import "MFSideMenu.h"
Class secondViewConroller;
#interface DemoViewController : UIViewController <ADBannerViewDelegate,demoViewControllerDelegate> {
}
#end
FirstViewController M-file
-(void)stopSent{
if (isPlaying) {
[streamer stop];
wasPlaying=true;
}
}
-(void)startSent{
if (wasPlaying) {
[streamer start];
isPlaying=true;
}
}
Your protocol methods need to be implemented in the class that you've designated as your delegate target.
It looks like your DemoViewController (or FirstViewController) is the object you've designated as the delegate, since you've given the interface the "<ADBannerViewDelegate,demoViewControllerDelegate>" designations.
Then, from your Second View Controller, you can call the object you designated and set as a delegate by doing:
[delegate startSent];
and
[delegate stopSent];
in the appropriate locations, which appear to be "bannerViewActionShouldBegin" and "bannerViewActionDidFinish", respectively.
You should also make sure that the delegate is properly set, therefore instead of:
[delegate startSent];
you should actually do this:
if(delegate)
[delegate startSent];
else
NSLog( #"delegate is null; we should figure out why" );

Errors when making circular reference imports

My program was running fine, but I changed something and now it has over 48 errors.
I think I know the problem, but I don't know how to fix it. I created a class called mViewBase for all my UIViewControllers to derive from.
I decided to have a navigtion bar at the bottom of all my views, to go to other view controllers called cakes2. So cakes2.h imports mViewBase, and mViewBase import cakes2.h
You must be able to do this in Objective-C. Does anybody have any idea of what I can do?
My mViewBase.h file:
#import <UIKit/UIKit.h>
#import "Cakes2.h"
#interface mViewBase : UIViewController {
UIView *mBackground;
UIView *mBackArrow;
UITextView *mTitle;
// Cakes2 *mCakes;
}
-(void) aSetTitle: (NSString *) NewTitle;
-(IBAction) aBack: (id) tender;
-(IBAction) aHome: (id) sender;
-(IBAction) aCakes: (id) sender;
-(IBAction) aCall: (id) sender;
-(IBAction) aDirections: (id) sender;
#end
My Cakes2.h file:
#import <UIKit/UIKit.h>
#import "Gallery.h"
#import "WebView.h"
#import "mViewBase.h" // Circular reference! But I need it
#interface Cakes2 : mViewBase <UITableViewDelegate, UITableViewDataSource> {
// Gallery *mGallery;
IBOutlet UITableView *mMenu;
// WebView *mWebView;
}
-(IBAction) aOpenWeb;
#end
You can use a forward declaration in one of your header files to avoid the need to import the other header. For example, in mViewBase.h, you can say:
#class Cakes2;
Now the compiler knows that "Cakes2" refers to a class, and you don't need to import the entire Cakes2.h file.
I think you should perhaps consider using a UITabBarController. It is made specifically for managing several view controllers from a bar at the bottom of the screen.