Cocoa - calling a VIEW method from the CONTROLLER - cocoa

Got a little problem i asked about it before but maybe i didnt ask properly.
I have a cocoa application, which amongst other things, must do the following task:
- load some images from the disk, store them in an array and display them in a custom view.
In the Interface Builder i have a CustomView and an OBJECT that points to TexturesController.h
The custom view is a custom class, TextureBrowser.
Below is the code for the controller and view:
TexturesController
#import <Cocoa/Cocoa.h>
#class TextureBrowser;
#interface TexturesController : NSObject {
IBOutlet NSTextField *logWindow;
IBOutlet TextureBrowser *textureView;
NSMutableArray *textureList;
}
#property textureView;
-(IBAction)loadTextures:(id)sender;
-(IBAction)showTexturesInfo:(id)sender;
#end
TextureBrowser
#interface TextureBrowser : NSView {
NSMutableArray *textures;
}
#property NSMutableArray *textures;
-(void)loadTextureList:(NSMutableArray *)source;
#end
These are just the headers. Now , what i need to do is:
when loadTextures from the TexturesController is called, after i load the images i want to send this data to the view (TextureBrowser), for example, store it in the NSMutableArray *textures.
I tried using the -(void)loadTextureList:(NSMutableArray*)source method from the view, but in the TextureController.m i get a warning : No -loadTextureList method found
This is how i call the method :
[textureView loadTextureList: textureList];
And even if i run it with the warning left there, the array in the view class doesnt get initialised.
Maybe im missing something...maybe someone can give a simple example of what i need to do and how to do it (code).
Thanks in advance.

In TexturesController.m, you have to import TextureBrowser.h so that the controller knows what methods the property textureView has. Right now, you've just got a blank placeholder symbol instead of an actual class.
Since textureView is defined by an outlet, you need to make sure that its class is properly set in Interface Builder. If you provide a generic NSView instead, it won't have the loadTextureList: method.

If you imported TextureBrowser.h in TexturesController.m, I don't see why it wouldn't find your method.
But why don't you simply call self.textureView.textures = textureList; from the TexturesController ?

Related

C4 passing image between subclasses

I'm trying to pass an image between 2 different views that are added as subclasses to the MainCanvasController.
the image seems to get passed (it is shown, when printed to the Console) but it doesn't display anything...
this is how I try to receive and display the image
-(void)receiveNumber:(C4Image*)number{
C4Log(#"number:%#", number);
number.center=self.canvas.center;
[self.canvas addImage:number];
receivedImage=number;
C4Log(#"received number: %#", receivedImage);
}
and here is how I post the image
[secondView receiveNumber:originalImage];
I don't really know what's going wrong. (well, honestly, I don't know at all...) So any hints are very much appreciated!
I had a look at your project and found the answer.
Your FirstView object has a variable called secondView, which is exactly the same name as the object in your main workspace. However, despite having the same name both of these are different objects.
I've done a couple things:
1) instead of using variables in the interface file for your objects, use properties.
2) create a SecondView property in your FirstView class
3) set the property of firstView to the same object in your workspace, secondView
My FirstView.h looks like:
#interface FirstView : C4CanvasController{
C4Label *goToSecondView;
}
#property (readwrite, strong) C4Window *mainCanvas;
#property (readwrite, strong) C4Image *postedImage;
#property (readwrite, strong) SecondView *secondView;
#end
My postNoti: looks like:
-(void)postNoti{
C4Log(#"tapped");
[self postNotification:#"changeToSecond"];
[self.secondView receiveNumber:self.postedImage];
}
NOTE I got rid of the [SecondView new]; line.
The following is the part that you were missing
My workspace has the following line:
firstView.secondView = secondView;
Which sets the variable of the first view to have a reference to the secondView object.
You hadn't done this, and so you were passing the image to an object that had the same name as the view that's visible from your main workspace's canvas.

Send controller object over delegate

I am trying to make a cocoa app with an NSplitView that keeps track of "active subviews" (like how the Terminal app knows which pane you are editing).
I have a SessionWindowController that keeps track of the "currentPaneContainerViewController" based on which PaneView the user last clicked on.
some classes and files:
SessionWindowController.h/.m
PaneContainerViewController.h/.m
PaneView.h/.m
PaneContainerView.xib
PaneContainerView.xib has the PaneContainerViewController as its file owner.
My current implementation is as follows:
To access the PaneContainerViewController from the NSView, I use IBOutlets that reference to the file owner, and to access the SessionWindowController I also maintain an IBOutlet of the object conforming to a delegate method I made (namely, the object happens to be the SessionWindowController).
#import <Cocoa/Cocoa.h>
#import "PaneViewDelegate.h"
#class PaneContainerViewController;
#class SessionWindowController;
#interface PaneView : NSView
{
//outlet connection to own controller
IBOutlet PaneContainerViewController *myPaneContainerViewController;
//we'll use delegation to get access to the SessionWindowController
IBOutlet id<PaneViewDelegate> sessionDelegate;
}
#implementation PaneView
-(void)mouseUp:(NSEvent *)event
{
if (sessionDelegate && [sessionDelegate respondsToSelector:#selector(setCurrentPaneContainerViewController:)]) {
[sessionDelegate setCurrentPaneContainerViewController:myPaneContainerViewController];
}
}
Here is the class that sessionDelegate belongs to, which conforms to the PaneViewDelegate protocol:
#interface SessionWindowController : NSWindowController <PaneViewDelegate>
{
PaneContainerViewController *currentPaneContainerController;
}
- (void)setCurrentPaneContainerViewController:(PaneContainerViewController*)controller;
My trouble is accessing the SessionWindowController object using the IBOutlet. In Interface Builder, what do I connect the sessionDelegate outlet to to be able to access the SessionWindowController instance? Furthermore, is it okay to pass the controller to the delegate instead of an NSEvent?
I am new to Cocoa, so if there is a better design pattern do please let me know. This does seem like a lot of boilerplate for a pretty common functionality.

allocating view controller the right way

i am trying to archiv something really simple.
I add a property for a NSScrollView in my ViewController header file called PanelController:
#property (strong) IBOutlet NSScrollView *listurls_fld;
I add the ViewController.h file to my NSObject Interface called "qhandler.h"
#import "handler.h"
#import "PanelController.h"
i have a +(void) function inside the qhandler.m ->
+ (void)do_handle:(NSDictionary *)response
{
PanelController *MyView=[[PanelController alloc] init];
NSLog(#"add moo");
[MyView.listurls_fld setStringValue:#"moo"];
}
which doesn't work...
It does neither work with setAlphaValue or whatever, i guess it's because i am allocating a new instance of PanelController, but as a matter of fact, I tried to change the main instance.
I know it's basic but i have enormous problems using IBOutlets from a viewcontroller, inside an external obj-c file.
Thanks,
john
ViewController.h
id mainDelegate;
ViewController.m
in viewDidLoad oder what function ever triggers after load:
mainDelegate=self;
so i can use [mainDelegate ...:..]; in every file..

Change IBOutlet text to property of object returned from custom class

I'm using xCode 4.2.1 - I have an app that uses a web service and fetches some data using a custom class and NSURLConnection. The user taps a "refresh" button which starts a series of events that happen in some custom classes in my project, and I can get the object, along with the properties I want to return in a method in the MainViewController, I'm just not able to change the text of an IBOutlet to a property (NSString) of the returned object.
In my "MainViewController.h, I have an IBOutlet (and it's wired to a button in the MainViewController.xib):
IBOutlet UILabel *textLabel;
and:
#property (nonatomic, retain) IBOutlet UILabel *textLabel;
And I've synthesized the label in MainViewController.m
#synthesize textLabel;
The process looks like this: Refresh Button Tapped --> Fires a mthod in MainViewController --> Fires another method in a custom class (retrieves data from web, creates object) --> Sends Object to MainViewController via: (in my custom class implementation)
// parsing, etc.. and define a string for priceString property of mp object
MainViewController *mvc = [[MainViewController alloc] init];
[mvc log:mp];
And in my MainViewController.m I can access a property of that object and print it in NSLog just fine from this method.
- (void) log:(Price *)mp {
self.textLabel.text = mp.priceString;
NSLog(#"%#", mp.priceString);
}
At this point, I can see the data in the log, but the textLabel text won't change.
I've been trying to read examples for a week, and I've heard everything from delegation, to NSNotication answers, but nothing seems to work.
All I need to do is populate an IBOutlet from a -(void) method.
Any help would be greatly appreciated, and I'm down for implementing delegation, but I'm very new to it, and seeking an example.
EDIT - more details.
After further research, I think I should note that my NSURLConnection that is returning my objects is in a separate class, and I've been reading a lot of threads where people are starting the connection in viewDidLoad.
The problem is that you are calling [mvc log:mp]; just after initializing the view controller. At that stage, the view is still not loaded from the xib file.
you can change log to see that:
- (void) log:(Price *)mp {
if (self.textLabel) {
self.textLabel.text = mp.priceString;
} else {
NSLog(#"textLabel is nil.");
}
}
You can call [mvc log:mp]; in the view controller viewDidLoad method, or after viewDidLoad has been executed.
To understand this better, add NSLog(#"viewDidLoad."); in viewDidLoad method, and add NSLog(#"viewController initialized."); just after the code where you initialized the view controller.
You will see the following
viewController initialized.
textLabel is nil. // if you call log as usual after initializing the view controller.
viewDidLoad.

Unable to write to NSTextField from Model Controller object

After always running monolithic blocks of code from within my AppController object, I've just learned how to modularize my code using separate model controller objects (so much neater and less confusing to work with :-))
My simple test app has a main AppController and two model objects (Model1 and Model2). I can successfully pass data from the AppController to the models, and the models themselves can run methods and process the passed data 'internally' as they were intended to do -- but I can't get them to communicate with a darned NSTextField in the UI. Here's the relevant parts of my code:
In AppController.m #import "AppController.h"
#implementation AppController
- (IBAction)passObjectsToModelController:(id)sender
{
NSString *stringToPass = #"Hello from Model2 :-)";
int numToPass=12345;
Model2 *ObjController2 = [[Model2 alloc]initWithStuff:stringToPass:numToPass];
[ObjController2 release];
}
#end
...in Model2.h
#import
#interface Model2 : NSObject
{
IBOutlet NSTextField *passedStringField;
}
- (id)initWithStuff:(NSString*)passedString :(int)passedNum;
#end
...and finally in Model2.m
#import "Model2.h"
#implementation Model2
- (id)initWithStuff:(NSString*)passedString :(int)passedNum
{
if(self = [super init])
{
NSLog(#"now inside 'Model2' controller...");
NSLog(#"the passed string reads: %#",passedString); //••• this works •••
NSLog(#"the passed number is:%d",passedNum); //••• this works •••
[passedStringField setStringValue:passedString]; //••• WTF!!... this DOESN'T work! •••
// do something internally with passedNum here...
}
return self;
}
#end
Both model objects have outlets to the common NSTextField and I've control-dragged from both objects to the field and connected them. My AppController doesn't know about the NSTextField (and I assume, doesn't even want to know). No IB connections have been made between the controller object and model objects.
NSLog tells me that the model objects are being created, and that the passed values are making it that far... but not from there into the text field in the GUI window. I'm not getting any compiler errors or warnings. Am I missing some kind of 'setTarget:' call perhaps?
Any help/ideas would be much appreciated. Thanks :-)
Aside from the lack of MVC that mihirsm mentions, the actual problem is that you're trying to access an outlet in an -init method.
When a object is initialized, outlets are not guaranteed to be connected.
If you want to set the value of an NSTextField declared as an outlet, you should implement -awakeFromNib, which is called when the nib has been loaded and all outlets are guaranteed to be live.
in Model1.h:
#interface Model1 : NSObject
{
IBOutlet NSTextField* passedStringField;
NSString* modelString;
}
- (id)initWithString:(NSString*)passedString number:(int)passedNum;
#end
in Model1.m:
#implementation Model1
- (id)initWithString:(NSString*)passedString number:(int)passedNum
{
if(self = [super init])
{
//copy the string to our ivar
modelString = [passedString copy];
}
return self;
}
//awakeFromNib is called when our outlet is live
- (void)awakeFromNib
{
[passedStringField setStringValue:modelString];
}
//don't forget to release the string, because we created it using -copy
- (void)dealloc
{
[modelString release];
}
#end
The Controller sits between the Model and the View. The Model should not communicate with the View.
It should be the job of the Controller to pass any incoming values from the View to the Model. The Model then processes the data and sends back to the Controller which then updates the View with the new data.
So, in your code you should only have one IBOutlet for the TexField declared in the AppController.
Given all this, I am not exactly sure why the TextField is not being updated. From the given code looks like it should. Maybe multople IBOutlets are causing some issue? Can you try with only one Model having the IBOutlet?

Resources