Basic MVC: set variable to NSTextField input in different classes - objective-c

The main idea:
Model: Set the value from the textfield to a variable which I can call/log.
View: Just a NSTextField hooked up to the Model class.
Controller: NSButton hooked up to the ViewController.
As you will notice, it logs the basic string from NSLog, also the predefined beginvalue. but when I ask for the txtBegin value it returns NULL
I know the TextField and the Button are hooked up in the connections inspector.
Screenshot:
Downloadable project:
ViewController.h
#import <Cocoa/Cocoa.h>
#import "Model.h"
#interface ViewController : NSView
- (IBAction)logTheVariable:(id)sender;
#end
ViewController.m
- (IBAction)logTheVariable:(id)sender
{
Model *myModel = [[Model alloc]init];
[myModel doSomething];
}
Model.h
#import <Foundation/Foundation.h>
#interface Model : NSObject{
//iVars
int begin;
}
//properties
#property (weak) IBOutlet NSTextField *txtBegin;
//methods
-(void)doSomething;
#end
Model.m
#import "Model.h"
#implementation Model
-(void)doSomething{
NSLog(#"I'm in the Model Class"); //logs like a charm!
begin = 5; //just a test to see if it logs anything (which works)
NSLog(#"%d",begin);// logs like a charm!
//->Problem is here <-
NSLog(#"%#",_txtBegin.stringValue); //returns a "NULL" value.
//->Problem is here <-
}
#end

Simple solution just declare the outlet of textfield in your viewcontroller and then modify below method in your model class and implement it:-
Model.h
-(void)doSomething: (NSString*)yourstringvalue;
Model.m
-(void)doSomething: (NSString*)yourstringvalue
{
NSLog(#"%#",yourstringvalue);
}
Viecontroller.m
- (IBAction)logTheVariable:(id)sender
{
Model *myModel = [[Model alloc]init];
NSString * str=self.begintext.stringValue;
[myModel doSomething:str];
}

The Model class instance you use in logTheVariable: is logging a null value because it is a new instance you created in the action of the ViewController, not an instance of Model interface builder is aware of.
- (IBAction)logTheVariable:(id)sender
{
Model *myModel = [[Model alloc]init];
//This is a new instance. The IBOutlet for txtBegin is null.
[myModel doSomething];
}
What you have implemented is not how MVC is intended. Apple provides a thorough roadmap of the user interface, framework and programming concepts you need to know to develop for OSX that will help you understand how Apple expects you to use their frameworks. https://developer.apple.com/library/mac/referencelibrary/GettingStarted/RoadMapOSX/chapters/01_Introduction.html
Models generally don't know anything about the user interface. They just store data and communicate when data is changed.
Your Model class should expose a property for any data it wants to expose.
Your Model class should not have any reference to the NSTextField.
So now in your model, you can log when your property is changed
-(void)doSomething:(NSString *)value //method name should be setBegin assuming you name your property 'begin'
{
NSLog(#"I'm in the Model Class"); //logs like a charm!
begin = 5; //just a test to see if it logs anything (which works)
NSLog(#"%d",begin);// logs like a charm!
//->Problem is here <-
NSLog(#"%#",value); //will log like a charm
}
Views generally doesn't know anything about the model. It just displays data in a way the user can interact with and possibly edit.
Controllers tie the Model and View together. It receives notification from the model when data changes and updates the View. Conversely, it also receives notification from the View when the data is edited to update the Model.
Your ViewController class should have a reference to the NSTextField (using an outlet)
Your ViewController class should have an instance of Model which it creates internally.
Now your logTheVariable can be implemented to tie the Model and View together:
- (IBAction)logTheVariable:(id)sender
{
//Use ViewController's model instance
Model *myModel = [self myModel];
NSString * value = [[self txtBegin] stringValue];
[myModel doSomething:value];
}

Related

How to create and use same objects in view controller methods?

Hi am a experienced Java programmer.I've just stepped into learning Objective-C and XCode.I am unable to understand
a very basic but important thing which is not letting me progress any further.
I want to create objects of classes defined by me and then access and use those objects in the View Controller methods of different
Views in the Storyboard.
I don't know where and how to create the objects so they could be accessed in any View.In Java I can do everything in main but the
structure of Objective C is confusing me.
For example I have a class
#interface list : NSObject
{
NSMutableArray* ary;
}
#end
I want to create objects of this class and use them those objects in the methods of different View Controllers.
How can I do so?
Please can somebody just give me a to the point answer about where to create the objects so they could become accessible in View Controller methods.
I have seen far to complex answers but not basic ones
PS: I'm using XCode 4.4
I think you should read some books or tutorials.
Some books:
http://www.amazon.com/Programming-Objective-C-5th-Developers-Library/dp/032188728X/ref=sr_1_3?s=books&ie=UTF8&qid=1351547991&sr=1-3&keywords=stephen+kochan
http://www.amazon.com/Learn-Objective-C-Java-Developers-Series/dp/1430223693
http://www.amazon.com/Objective-C-Absolute-Beginners-iPhone-Programming/dp/1430228326
For tutorial - just google it - one of them:
http://mobile.tutsplus.com/tutorials/iphone/learn-objective-c-day-1/
Say, you have mainViewController class where you want to use your list class then you can do something as follows:
// mainViewController.h
#import "list.h"
#interface mainViewController
#property (nonatomic, strong) list *objList;
#end
// mainViewController.m
#implementation mainViewController
#synthesize objList = _objList;
- (void) viewDidLoad {
self.objList = [[list alloc] init];
}
- (void) someMethod {
self.objList.ary = ...;
}
#end

Objective-c: Singleton - passing variables

I have a singleton that I'd like to use to manage the onscreen animation of my views. Here's my.
#import <Foundation/Foundation.h>
#interface OAI_AnimationManager : NSObject {
NSMutableDictionary* sectionData;
}
#property (nonatomic, retain) NSMutableDictionary* sectionData;
+(OAI_AnimationManager* )sharedAnimationManager;
- (void) checkToggleStatus : (UIView* ) thisSection;
#end
.m file
#import "OAI_AnimationManager.h"
#implementation OAI_AnimationManager
#synthesize sectionData;
+(OAI_AnimationManager *)sharedAnimationManager {
static OAI_AnimationManager* sharedAnimationManager;
#synchronized(self) {
if (!sharedAnimationManager)
sharedAnimationManager = [[OAI_AnimationManager alloc] init];
return sharedAnimationManager;
}
}
- (void) checkToggleStatus : (UIView* ) thisSection {
//get the section data dictionary
NSLog(#"%#", sectionData);
}
#end
You'll see in the .h file I added a NSMutableDictionary and am using #property/#synthesize for it's getter and setter.
In my ViewController I instantiate the animation manager as well as a series of subclasses of UIView called Section. With each one I store the data (x/y w/h, title, etc.) in a dictionary and pass that to the dictionary delcared in animation manager. In the Section class I also instantiate animation manager and add a UITapGestureRecognizer which calls a method, which passes along which section was tapped to a method (checkToggleStatus) in animation manager.
As you can I see in the method I am just logging sectionData. Problem is I am getting null for the value.
Maybe my understanding of singletons is wrong. My assumption was the class would only be instantiated once, if it was already instantiated then that existing object would be returned.
I do need all the other Section classes data as if one animates others animate in response and I can get around it by passing the tapped Section to the animation manager and doing [[Section superview] subviews] and then looping and getting the data from each that way but it seems redundant since that data is available in the ViewController when they are created.
Am I doing something wrong in trying to transfer that data? Is there a better solution? I am open to suggestions and criticisms.
Thanks
h file
#interface OAI_AnimationManager : NSObject
#property (nonatomic, retain) NSMutableDictionary* sectionData;
+(OAI_AnimationManager* )sharedAnimationManager;
- (void) checkToggleStatus : (UIView* ) thisSection;
#end
m file
static OAI_AnimationManager* _sharedAnimationManager;
#implementation OAI_AnimationManager
#synthesize sectionData = _sectionData;
+(OAI_AnimationManager *)sharedAnimationManager {
#synchronized(self) {
if (!_sharedAnimationManager) {
_sharedAnimationManager = [[OAI_AnimationManager alloc] init];
}
}
return _sharedAnimationManager;
}
- (void) checkToggleStatus : (UIView* ) thisSection {
//get the section data dictionary
NSLog(#"%#", _sectionData);
}
#end
Notice I moved your sectionData variable from the header and moved it to the implementation file. A while back, they changed it to where you can synthesize properties and specify their instance variable names along side it... hence:
sectionData = _sectionData;
I also added and underscore to the instance variable... this is a universal convention for private variables and it also will throw a compile error now if you try to type just sectionData as you did in the return statement of checkToggleStatus:. Now you either have to type self.sectionData or _sectionData.
You didn't include the code that creates an instance of your dictionary but I bet you didn't set it as self.sectionData = [[NSDictionary alloc] init] which means it would not retain the value and you would get null the next time you called it. Classic memory management mistake... I know it well because I learned the hard way hehehe

How to generate a generic table view controller?

I've created a custom TablePickerViewController which is a subclass of UITableViewController. I'm using this class to display a list of object of a custom type TablePickerItem.
I'm using TablePickerViewController multiple times in my iOS application to show different kinds of lists where the user has to pick an item -- and then another view controller MainViewController should react on this selection and do something.
I've created this protocol and created a delegate property in the TablePickerViewController:
#protocol TablePickerViewControllerDelegate <NSObject>
- (void)tablePickerViewController:(TablePickerViewController *)controller
didSelectItem:(TablePickerItem*)item;
#end
When I setup a new TablePickerViewController in MainViewController it is also set as delegate -- than it will be notified when the user taps an cell in the table view.
The problem is that my MainViewController will setup multiple TablePickerViewController with different data (TablePickerItem). How should I setup my MainViewController to handle these multiple TablePickerViewController? Events from each of them will results in calling to the same protocol-method in my MainViewController.
Further I need to get the element which the TablePickerItem represents, as I need to know for instance the elements ID when acting in the tablePickerViewController:didSelectItem method. Should I just handle this by adding something like #property (nonatomic) id element to the TablePickerItem and set the original object into this property then creating it?
Maybe someone can give me an example on how to create an generic table view controller, if my solutions seems being done in the wrong way.
I'm not entirely sure of your set up, but if you have multiple pickers that feedback to the main controller then you could just have a reference to the picker e.g.
// MainViewController.m
#interface MainViewController ()
#property (nonatomic, strong) TablePickerViewController *picker1;
#property (nonatomic, strong) TablePickerViewController *picker2;
// ... and so on. Obviously you know your problem domain so you can change
// the terrible naming above to something appropriate
#end
#implementation MainViewController
// ...
- (void)theMethodWhereYouSetUpYourPickers;
{
TablePickerViewController *picker1 = [[TablePickerViewController alloc] init];
picker1.delegate = self;
self.picker1 = picker1;
// ...
}
- (void)tablePickerViewController:(TablePickerViewController *)controller
didSelectItem:(TablePickerItem*)item;
{
if (controller == self.picker1) {
NSLog(#"Something was picked in picker 1 %#", item);
} else if (controller == self.picker2) {
NSLog(#"Something was picked in picker 2 %#", item);
}
}
// ...
#end

Objective-C, using protocol to access datasource

I'm using the MVC model but I cannot get the data needed for the View, I am trying to use a data source since a View should never own its data. Typically, a protocol is used to create a data source.
I have a MVC: CalculatorBrain.[hm] - CalculatorViewController.[hm] - (view is .xib)
I also have MVC: GraphingView - GraphingViewController - (model is the data I can't get)
The goal is: when I press a button on the calculator, it draws the function (e.g.: x+5=) that is currently in it's display. The calculator part takes care of the expression/function, the display, etc while the graphing part should draw. CalculatorViewController should be the GraphingView's source, but the data always stays null.
This is GraphingView.h with the declaration of the protocol :
#class GraphingView;
#protocol GraphingViewSource
- (float)getDataPoints:(GraphingView *)requestor;
#end
#interface GraphingView : UIView {
id <GraphingViewSource> source;
}
#property (assign) id <GraphingViewSource> source;
#end
CalculatorViewController.m implements the protocol by implementing the getDataPoints: method. Header of CalculationViewController.h :
#interface CalculatorViewController : UIViewController <GraphingViewSource>
Pressing the button which should set up the data source :
- (IBAction)graphPressed:(UIButton *)sender
{
GraphingViewController *graphingVC = [[GraphingViewController alloc] init];
graphingVC.graphingView.source = self;
[self.navigationController pushViewController:graphingVC animated:YES];
[graphingVC release];
}
Pressing the button brings up the new view nicely etc, but following line of code only returns null (inside GraphingView.m) :
float result = [self.source getDataPoints:self];
It seems, I cannot access my data source...
From your comments it seems that graphingView is nil at the time you are trying to set its source.
If there is a xib for the view controller, you should be doing this:
GraphingViewController *graphingVC = [[GraphingViewController alloc] initWithNibName:#"GraphingViewController" bundle:nil];
Instead of a plain init.
This will create and instantiate all of your view objects so they are available to have properties set before you present the view controller.

Accessing cocoa interface builder controller methods

So I have an objective-c project that uses a controller class. This interfaces with interface builder via IBOutlets.
My understanding is that the controller gets initialized by loading the user interface (as it is added to interface builder as an object). I would then like to use the controller's getter methods to return values that are in the IBOutlet fields.
So, to clarify what I mean with some code, here's my controller interface/implementation:
#interface controller : NSObject {
#private
IBOutlet NSTextField *name;
}
-(NSString*) name;
#end
Then, in my implementation, I have:
-(NSString*) name
{
return [name stringValue];
}
in a third class, I'd like to be able to write:
NSString blahblah = [controller name] and have the value of blahblah assume the value of whatever is in the controller's IBOutlet "name" field.
Hopefully this makes sense. When I try and do it this way I get "Semantic Issue: Method '+name' not found (return type defaults to 'id')"
Why? Where is the controller object actually substantiated and where, and how do I access it's fields?
You have to instantiate the controller by using [[controller alloc] initWithNibName:nibName bundle:nil];
By just using [controller name] you are calling a class method. Also it should be NSString *blahblah
You should read this document:
http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html#//apple_ref/doc/uid/TP40007594