Classical MVC in Cocoa - ios

I'm trying to structure some view-code out of the controller (obviously without using a nib). Therefore, I tried a simple example, but for some reason, I can't add the target to the button in the controller, rest is fine. Here's what I'm trying:
Controller.h:
#import <UIKit/UIKit.h>
#import "IndexView.h"
#interface IndexController : UIViewController
{
}
#property (nonatomic) IndexView *contentView;
#end
Controller.m
#import "IndexController.h"
#import "IndexView.h"
#interface IndexController ()
#end
#implementation IndexController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.contentView = [[IndexView alloc]init];
[self.view addSubview:self.contentView];
[self connectUIElements];
}
return self;
}
- (void) connectUIElements
{
[self.contentView.testButton addTarget:self action:#selector(testButtonClicked) forControlEvents:UIControlEventTouchUpInside];
}
#pragma mark --
#pragma mark UIHandler
- (void) testButtonClicked
{
NSLog(#"testbutton clicked");
}
#end
View.h
#import <UIKit/UIKit.h>
#interface IndexView : UIView
#property (nonatomic, strong) UIButton *testButton;
#end
View.m
#import "IndexView.h"
#implementation IndexView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUpView];
}
return self;
}
- (id) init
{
self = [super init];
if (self) {
[self setUpView];
}
return self;
}
- (void) setUpView
{
[self setBackgroundColor:[UIColor whiteColor]];
self.testButton = [[UIButton alloc]initWithFrame:CGRectMake(10, 50, 100, 50)];
self.testButton.backgroundColor = [UIColor greenColor];
[self.testButton setTitle:#"hello, world" forState:UIControlStateNormal];
[self addSubview:self.testButton];
}
#end
I'm just exploring possibilities to get closer to a classical MVC pattern and a little farther away from Apples mediator-interpretation. Any idea what's wrong?

You have to create your view using initWithFrame:, which is the default initializer for UIView. (The reason that is does not work with a simple init - but I am guessing here! - might be that the views size is zero and therefore the touch events do not work.)

Related

Calling UIView from UIController

I am trying to call a UIView FirstScreen from my ViewController.
But I don't know how to do it.
ViewController:
#import "ViewController.h"
#import "FirstScreen.h"
#interface ViewController ()
{
FirstScreen *f;
}
FirstScreen.m:
#import "FirstScreen.h"
#implementation FirstScreen
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self didLoad];
}
return self;
}
-(void) didLoad{
[self addLabel];
[self addImageView];
}
#implementation FirstScreen
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self didLoad];
}
return self;
}
-(void) didLoad
{
f = [[FirstScreen alloc] initWithFrame:CGRectMake(0, 0, self.view.size.width, self.view.size.height)];
[self.view addSubview:f];
}
#import "FirstScreen.h"
#implementation FirstScreen
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
// calling another methods
[self anotherMethod];
return self;
}
-(void) anotherMethod
{
// write some code here
}
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FirstScreenObj = [[FirstScreen alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
FirstScreenObj.backgroundColor = [UIColor grayColor];
[self.view addSubview:FirstScreenObj];
}
I hope it will help you!

Adding a Navigation Controller but navigation item not displaying

Originally I had a custom NavigationBar, without a navigation controller. I have a sliding menu.
On the home screen there is a tableview, with a list. I would like to be able to add items to this list. So, I had to add in a navigation controller after the fact. I added the navigation controller to the storyboard and linked it to my main view controller [the one with the list]. Then I dragged in a view controller. I dropped in a bar button item into the navigation item, and pushed it to the recently added view controller.
I ran my app and the app shows no navigation bar or navigation item whatsoever now. Originally I had a custom navigation bar.
I'm not too sure what's going on here. Thanks for any help.
- (void)customizeAppearance {
UIImage *NavBG = [UIImage imageNamed:#"nav bar.png"];
[[UINavigationBar appearance] setBackgroundImage:NavBG forBarMetrics:UIBarMetricsDefault];
init View Controller code from .m
#import "initViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#interface initViewController ()
#end
#implementation initViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.topViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Main"];
}
from .h
#import "ECSlidingViewController.h"
#interface initViewController : ECSlidingViewController
#end
from main.m
#import "MainViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
{
NSArray *toDoList;
NSIndexPath *selectedIndexPath;
}
#synthesize menuBtn;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
from main.h
#import <UIKit/UIKit.h>
#interface MainViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
{
}
#property (strong, nonatomic) UIButton *menuBtn; // go to MenuViewController.m and synthesize
#end
Second view controller.m file
#import "SecondViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#interface SecondViewController ()
#end
#implementation SecondViewController
#synthesize menuBtn;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Below is the same stuff pasted from MainViewController.m
// Do any additional setup after loading the view.
self.view.layer.shadowOpacity = 0.75f;
self.view.layer.shadowOpacity = 10.0f;
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
self.menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
menuBtn.frame = CGRectMake(8, 10, 34, 24);
[menuBtn setBackgroundImage:[UIImage imageNamed:#"menuButton.png"] forState:UIControlStateNormal];
[menuBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.menuBtn];
}
Here are all the arrays I use
From the image you are showing, it doesn't look like any of the VCs have the starting arrow to its left. If that is the case, go to SB, click on the Nav controller, go to Attributes inspector on the right,scroll down and check the "Is initial View Controller".
Hope this answers it.
Update: Guessing at your code, you are trying to modify an immutable NSArray. Change your declaration to NSMutableArray *toDoList.

Passing data From uiview to uiviewcontroller

after try 2 days and i'm losing my mind now... the main problem is simple.. i've button in uiview,, and i want to call method on uiviewcontroller ... here's the code
Uiview call headerView.h
#class HeaderView;
#protocol headerViewDelegate
- (void)tes:(HeaderView *)tes ratingDidChange:(float)rating;
#end
#interface HeaderView : UIView {
UIButton *test;
}
#property (nonatomic,strong) UIButton *test;
#property (assign) id <headerViewDelegate> delegate;
#end
and the Headerview.M
#import "HeaderView.h"
#import <QuartzCore/QuartzCore.h>
#implementation HeaderView
#synthesize test;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame]; // not needed - thanks ddickison
if (self) {
test=[UIButton buttonWithType:UIButtonTypeRoundedRect];
test.frame=CGRectMake(30, 10, 100,40);
[test setTitle:#"Kampret" forState:UIControlStateNormal];
[test addTarget:self action:#selector(testdata:) forControlEvents:UIControlEventTouchUpInside];
}
[self addSubview:test];
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
}
return self;
}
- (void)dealloc {
[super dealloc];
}
-(void)layoutSubviews{
self.backgroundColor=[UIColor whiteColor];
[self release]; // release object before reassignment to avoid leak - thanks ddickison
//self = [nib objectAtIndex:0];
self.layer.shadowColor = [[UIColor blackColor] CGColor];
self.layer.shadowOffset = CGSizeMake(1.0, 1.0);
self.layer.shadowOpacity = 0.40;
}
-(void)testdata:(id)sender{
[self.delegate tes:self ratingDidChange:1.1f];
}
#end
viewcontroller.h
#import <UIKit/UIKit.h>
#import "HeaderView.h"
#interface ReusableTableHeadersViewController : UITableViewController <headerViewDelegate> {
HeaderView *header;
}
#property(nonatomic,strong) HeaderView *header;
#end
viewcontroller.m
#import "viewcontroller.h"
#implementation ReusableTableHeadersViewController
#synthesize header;
#synthesize tblData, data;
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
header = [[HeaderView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)];
[self.view addSubview:header];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
}
- (void)dealloc {
[super dealloc];
}
-(void)tes:(HeaderView *)tes ratingDidChange:(float)rating{
NSLog(#"passing data==========%f",rating);
}
#end
i want to log the rating :
NSLog(#"passing data==========%f",rating);
from method:
-(void)testdata:(id)sender{
[self.delegate tes:self ratingDidChange:1.1f];
}
but it show nothing... why? because i use initwithframe?
dont blame me... i'm totally newbie here :)
You have not set delegate of headerview as view controller.
- (void)viewDidLoad {
[super viewDidLoad];
header = [[HeaderView alloc] initWithFrame:CGRectMake(0, 0, 320, 120)];
header.delegate = self;
[self.view addSubview:header];
}

iOS Custom Delegate Returns Nil after setDelegate called from viewController

I have been having a strange problem using a custom delegate class in ARC. In the viewcontroller after viewDidLoad I call the toolbars setDelegate method and assign the viewcontroller as the delegate.
Whenever I try to reference delegate, it is nil, even after being set in the
viewcontroller.
//MPToolbar.h
#import <UIKit/UIKit.h>
//Define the protocol for the delegate
#class MPToolBar;
#protocol MPToolBarDelegate <NSObject>
#required
- (void)writeButtonSelected;
- (void)writeButtonDeSelected;
#end
#interface MPToolBar : UIView{
id <MPToolBarDelegate> delegate;
}
#property(strong) UIButton *lastButton;
#property(strong) id <MPToolBarDelegate> delegate;
-(IBAction)buttonSelected:(id)sender;
-(void)resizeForOrientation:(UIInterfaceOrientation)orientation;
#end
//MPToolbar.m
#import "MPToolBar.h"
#implementation MPToolBar
#synthesize lastButton, delegate;
- (id)initWithFrame:(CGRect)frame
{
if ((self = [super initWithFrame:frame])) {
// Initialization code
}
NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:#"MPToolBar" owner:self options:nil];
[self addSubview:[nibViews objectAtIndex:0]];
return self;
}
#pragma button actions
-(IBAction)buttonSelected:(id)sender{
UIButton *btn = (UIButton *)sender;
if(lastButton && lastButton != btn)[self deselect:lastButton];
if (btn.selected){
[self deselect:btn];
return;
}
[btn setSelected:YES];
lastButton = btn;
switch (btn.tag) {
case 0:
[self.delegate writeButtonSelected];
break;
}
}
-(void)deselect:(UIButton *)btn{
[btn setSelected:NO];
switch (btn.tag) {
case 0:
[self.delegate writeButtonDeSelected];
break;
}
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
-(void)resizeForOrientation:(UIInterfaceOrientation)orientation{
if (UIInterfaceOrientationIsLandscape(orientation)) {
self.frame = CGRectMake(0, 44, 1024, 60);
}
if (UIInterfaceOrientationIsPortrait(orientation)) {
self.frame = CGRectMake(0, 44, 768, 60);
}
}
#end
//ViewTest.h
#import <UIKit/UIKit.h>
#import "MPToolBar.h"
#interface ViewTest : UIViewController <MPToolBarDelegate>
{
MPToolBar *toolBar;
}
#property(strong) MPToolBar *toolBar;
#end
//ViewTest.m
#import "ViewTest.h"
#interface ViewTest ()
#end
#implementation ViewTest
#synthesize toolBar;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.toolBar = [[MPToolBar alloc] initWithFrame:CGRectMake(0, 44, 1024, 60)];
[self.view addSubview:self.toolBar];
[self.toolBar setAlpha:1.0];
[self.toolBar setDelegate:self];
// Do any additional setup after loading the view from its nib.
}
#pragma mark - MPToolBar Delegate Methods
-(void)writeButtonSelected{
//set new annotation for write mode and size to screen bounds.
NSLog(#"writeButtonSelected");
}
- (void)writeButtonDeSelected{
NSLog(#"writeButtonDeSelected");
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#end
Ok so I finally found the problem. In my xib file I had set the UIView class to my custom controls class name instead of setting files owner.
once I changed the first UIView in the xib back to a standard UIView and then set the files owner to my custom class all was right with the world again!
-Thanks for everyone who tried to help!
Several things that could be causing problems:
Do you actually declare your view controller as a MPToolBarDelegate in its header? (that code is not present).
These are the delegate functions in your code:
-(void)ButtonSelected;
-(void)ButtonDeSelected;
However, you're actually invoking this one:
[_delegate writeButtonSelected];
which is not part of your protocol.
Try changing your delegate declarations like this:
#interface MPToolBar : UIView{
id delegate;
}
#property (nonatomic, assign) id <MPToolBarDelegate> delegate;
then when you call your delegate method use this:
[self.delegate ButtonSelected];
Also, the original iPad is upgradeable to iOS 5.0. If you are using ARC you can't be compatible with 4.3 anyway, ARC only started at 5.0 as I understand it.
With a similar symptom for me, my problem was that the segue's destinationViewController was NOT the object I was expecting it to be, because it was embedded in a UINavigationController.
Easy fix. See here. Lose pointer to Delegate while going through Navigation Controller

Nesting GLKView into UIViewController

I'm trying to use GLKView in UIViewController, my code looks like this
CustomViewController.h
#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>
#interface CustomViewController : UIViewController
{
NSString * name;
}
#property NSString * name;
CustomViewController.m
#import "CustomViewController.h"
#interface CustomViewController ()
#end
#implementation CustomViewController
#synthesize name;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
EAGLContext * context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
CGRect mainScreen = [[UIScreen mainScreen] bounds];
GLKView * viewGL = [[GLKView alloc] initWithFrame:CGRectMake(mainScreen.size.width / 2, mainScreen.size.height / 2, 50, 50)];
viewGL.context = context;
[self.view addSubview:viewGL];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
How can I define the draw/render method of GLKView? and where can I init OpenGL? Any suggestions?
Initialize OpenGL in your viewDidLoad, just as you're currently doing.
Take a look at registering your view controller as the GLKView's delegate. The delegate's glkView:(GLKView *)view drawInRect: method will be invoked whenever a redraw is required.
This tutorial may help.

Resources