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.
Related
I'm testing out some MVVM pattern stuff and seem to have gotten myself confused. Hoping someone here can clarify things for me.
So, what I did was set up a project and added a class that is a subclass of NSObject and called it RootViewModel.
Gave it one method:
- (void) rootTest {
NSLog(#"Booyeah!");
}
In ViewController I imported RootViewModel and made an IBOutlet for it.
#import "ViewController.h"
#import "RootViewModel.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *btnRunModel;
#property IBOutlet RootViewModel* myModel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.myModel rootTest];
}
#end
Then in Storyboard I dragged an Object into the ViewController scene, named it RootModel and connected it to the myModel property in ViewController.
Run the app and it works as expected, Booyeah gets logged.
So now here's where I got messed up. I wanted to set up a unit test. So working in the default unit test file I imported ViewController and made it a property and instantiated it in the set up.
#import <XCTest/XCTest.h>
#import "ViewController.h"
#interface ObjectiveVMMVTests : XCTestCase
#property (nonatomic, strong) ViewController* myViewController;
#end
#implementation ObjectiveVMMVTests
- (void)setUp {
[super setUp];
self.myViewController = [[ViewController alloc] init];
}
Then I tried to create a test where I call the rootTest method.
- (void) testRootModel {
[self.myViewController.myModel rootTest];
}
But I get a compiler error saying myViewController has no property myModel. I assumed it would be there, not sure where I messed this up.
In your unit test, you are saying:
#import "ViewController.h"
That's great. So now the unit test knows that this is a class. But that is not where the myModel property is declared. It is declared in ViewController.m, making this a private property.
Move the property declaration into ViewController.h to make it public so the unit test can see it.
Like #matt said, the IBOutlet is not part of the public interface of ViewController. It's private, hidden in the implementation (.m) file.
You have at least two viable options:
Add #property IBOutlet RootViewModel* myModel; to the ViewController.h file to make it part of the public interface;
Add an interface definition to the ObjectiveVMMVTests unit test file that'll satisfy the compiler:
#interface ViewController ()
#property IBOutlet RootViewModel* myModel;
#end
The implementation of the -(RootViewModel*)myModel getter is there anyway, the compiler just needs to know that ViewController does respond to the message. (You could use performSelector if you weren't interested in the returned object.)
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.
Running into a simple problem and not quite sure what is causing it. Linked a NSButton up to a ViewController xib. The property is referenced and then I linked up the IBAction to the view controllers view. I'm getting a crash whenever I press the button with an unrecognized selector message. I know I'm doing something wrong but on iOS this is pretty standard.
Here is the code:
#import "AppDelegate.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
IPVLocationViewController *mainViewController = [[IPVLocationViewController alloc]initWithNibName:#"IPVLocationViewController" bundle:nil];
self.window.contentView = mainViewController.view;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#end
#import "MainViewController.h"
#interface MainViewController ()
#property (weak) IBOutlet NSButton *mainButton;
#end
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
- (IBAction)mainClick:(id)sender {
NSLog(#"THE BUTTON WAS CLICKED");
}
#end
In your Nib , it looks like your view controller instance is of type NSViewController instead of MainViewController.
So select the view controller in your Nib (or storyboard), and change its type to MainViewController.
Of course, if this view controller isn't being loaded from a nib or storyboard, then just check where you create it and make sure you created an instance of the correct class.
Solved it:
The accepted answer in this post helped me:
Needed to hold a reference to the view controller in the AppDelegate.
#interface AppDelegate ()
#property (nonatomic, strong) MainViewController *mainViewController;
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
self.mainViewController = [[MainViewController alloc]initWithNibName:#"MainViewController" bundle:nil];
self.window.contentView = self.mainViewController.view;
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#end
I am making my first OSX app. My appDelegate has a window which has a contentView of NSViewController. This NSViewController has a custom view which displays on startup. I added an NSScrollView as a property of my NSViewController, and in the xib I put it in the correct position and referenced it to the files owner (the NSViewController). The scrollView never displays when the view is displayed. The code that includes the scrollView is as follows:
in the .h for the viewController:
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#import "StockData.h"
#interface MasterViewController : NSViewController {
IBOutlet NSScrollView * scrollView1;
}
#property (retain) IBOutlet NSScrollView * scrollView1;
#property (retain) NSView * contents;
#end
in the .m for the viewController:
#import "MasterViewController.h"
#import <math.h>
#import <Foundation/Foundation.h>
#implementation MasterViewController
#synthesize scrollView1, contents;
- (void) awakeFromNib
{
self.scrollView1 = [[NSScrollView alloc] init];
self.contents = [[NSView alloc] initWithFrame:NSMakeRect(0,0,430,1000)];
[self.view addSubview:scrollView1];
[self.scrollView1 setDocumentView:self.contents];
}
#end
If anyone could help that would be awesome! Thanks!
If I understand your issue, you don't need to alloc/init the scrollView1 if it is well-connected to the xib file. The xib allocates it for your since the scrollView1 is an object of that xib. If you NSLog(#"%#",[scrollView1 description]) before and after your allocation, It should give you two different objects. I would try :
self.contents = [[NSView alloc] initWithFrame:NSMakeRect(0,0,430,1000)];
[self.view addSubview:scrollView1];
[self.scrollView1 setDocumentView:self.contents];
Now you're adding the xib scrollView1 object to the self.view.
Hope it helps!
New to iOS/Objective-C here. I've spent a lot of time trying to figure this out, but just can't manage it. Here's what's happening:
Click a 'Graph' button on my RootViewController's view
GraphViewController takes over, has a graphView property
I set the graphView's dataSource property to self
Checking self.graphView.dataSource with NSLog confirms that it does indeed point to self
When GraphView's drawRect: is called, self.dataSource is set to (null), where I expected it to point to the GraphViewController object
To summarise: I'm instantiating the graphView property in the view controller, then setting its dataSource, but by the time the view's drawRect: is called the dataSource is no longer set.
GraphViewController.m:
#import "GraphViewController.h"
#import "GraphView.h"
#implementation GraphViewController
#synthesize graphView = _graphView;
#synthesize program = _program;
- (GraphView *)graphView {
if(!_graphView) {
_graphView = [[GraphView alloc] init];
[_graphView setDataSource:(id)self];
}
return _graphView;
}
#end
GraphViewController.h:
#import <UIKit/UIKit.h>
#import "GraphView.h"
#interface GraphViewController : UIViewController
#property (strong, nonatomic) IBOutlet GraphView *graphView;
#end
GraphView.m:
#import "GraphView.h"
#implementation GraphView
#synthesize dataSource = _dataSource;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSLog(#"initWithFrame called, self.dataSource=%#", self.dataSource);
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"drawRect:");
NSLog(#"\tself=%#", self);
NSLog(#"\tself.dataSource=%#", self.dataSource); // is (null), shouldn't be
[self.dataSource programToGraph];
}
#end
GraphView.h:
#import <UIKit/UIKit.h>
#class GraphView;
#protocol GraphViewDataSource
- (id)programToGraph;
#end
#interface GraphView : UIView
#property (nonatomic, weak) IBOutlet id <GraphViewDataSource> dataSource;
#end
So it looks like the GraphViewController instance is being deallocated, which will nil out the dataSource property.
So you should go back and look at how you are creating and managing that GraphViewController. A common mistake is to create a view controller like that, then borrow its view and throw it into some other view controller's view hierarchy, and then let the original view controller just go away.
I would look at that, and if you don't see it there, post the code where you create and present the GraphViewController.
Oh, and where are you calling initWithFrame: from?? It almost looks like you could also have two different instances of GraphView floating around. Try logging 'self' along with self.datasource to check that also.