Nesting GLKView into UIViewController - ios

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.

Related

How to pass value from subclass to super class during initialization

Suppose, I've two view controller. ViewController1 is the sub class of ViewController2. From subclass (ViewController1), I called superclass init method & passed a value by parameter & assigned that value to the superclass variable. But In superclass (ViewController2)'s viewDidLoad method, that value is always null. Why ? How can I pass that value from sub to super so that I can get that value in super class's viewDidLoad method ?
ViewController1.h
#interface ViewController : ViewController2
#end
ViewController1.m
#implementation ViewController
- (instancetype)init
{
self = [super initWithName:#"Hello"];
if (self) {
NSLog(#"1 :");
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
ViewController2.h
#interface ViewController2 : UIViewController
#property (nonatomic, strong) NSString *name;
-(instancetype)initWithName:(NSString *)name;
#end
ViewController2.m
- (instancetype)initWithName:(NSString *)name
{
self = [super init];
if (self) {
self.name = name;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"2 : %#", self.name);
}
#end
I tired your code and it worked just fine. I suspect, that you don't instantiate your ViewController directly. Do you use storyboard in your project? If yes - you should override initWithCoder: in ViewController.
However, it is bad idea to set any properties of view controllers during init-family methods. According to Apple recommendations, all customisation should be done in -viewDidLoad or -viewWill/DidAppear methods.
If you absolutely in need to set name property from outside, it is better you assign it directly, not trough passing argument to init method.
One more thing - initWithNibName:bundle: is Designated initializer. It means, that your subclasses absolutely must in the end call it during initialisation chain.
Updated - 16-Mar-2016
Example :
ViewController1.h
#import <UIKit/UIKit.h>
#import "ViewController2.h"
#interface ViewController1 : ViewController2
#end
ViewController1.m
#import "ViewController1.h"
#interface ViewController1 ()
#end
#implementation ViewController1
-(instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
//self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil andUserName:#"Ramesh Annadurai"];
// we can use above init method or below method, both will work
self = [super initWithName:#"Test Name"];
if (self) {
[self.view setBackgroundColor:[UIColor brownColor]];
}
return self;
}
-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
//self = [super initWithCoder:aDecoder];
// If you are using storyboard use this initWithCoder method.
self = [super initWithName:#"Test Name"];
if (self) {
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
ViewController2.h
#import <UIKit/UIKit.h>
#interface ViewController2 : UIViewController
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andUserName:(NSString *) userName;
- (instancetype)initWithName:(NSString *) userName;
#end
ViewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#property (strong, nonatomic) NSString *userName;
#end
#implementation ViewController2
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil andUserName:(NSString *) userName
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.userName = userName;
}
return self;
}
- (instancetype)initWithName:(NSString *) userName
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
self.userName = userName;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"User Name : %#", self.userName);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end

Request for member 'subview' in something not a structure or union?

I've created a gradient using Quartz, only one issue. I can't get it to rotate with the screen. I've tried everything listed on this tutorial. Here's the view controller header:
#import <UIKit/UIKit.h>
#interface RadialGradientBackgroundViewController : UIViewController {
}
#end
And here's the view controller:
#import "RadialGradientBackgroundViewController.h"
#import "BackgroundLayer.h"
#implementation RadialGradientBackgroundViewController
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
CAGradientLayer *bgLayer = [BackgroundLayer gradient];
bgLayer.frame = self.view.bounds;
[self.view.layer insertSublayer:bgLayer atIndex:0];
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[[[self.subview.layer sublayers] objectAtIndex:0] setFrame:self.view.bounds]; // Error is here!
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
}
- (void)dealloc {
[super dealloc];
}
#end
Your view controller does not have a subview property or method. As rmaddy said, change subview to view.

Classical MVC in Cocoa

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.)

how to resume timer when poping to view2

my application has 3 views
in view1 only one button (play level 1) that pushes to veiw2 and updates titlelabel in view2
when view2 loads and appears a timer starts to count down and update another label in view2 itself, also view2 has button that pauses the timer and pushes to view3
in view3 only one button that pop back to view2 and resumes thee timer
my problem is that when i pop from view3 to view2 the timer is still paused
any help please?
Thanks & kind regards.
view1.h
#import <UIKit/UIKit.h>
#interface view1 : UIViewController
-(IBAction)nextpage;
#end
view1.m
#import "view1.h"
#import "view2.h"
#interface view1 ()
#end
#implementation view1
-(IBAction)nextpage{
view2 *obj = [[view2 alloc] init];
[self.navigationController pushViewController:obj animated:YES];
[obj.leveltitle setText:#"Level"];
obj.time=10;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[self.navigationController setNavigationBarHidden:YES];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
view2.h
#import <UIKit/UIKit.h>
#interface view2 : UIViewController
{
int time;
NSTimer *timer;
BOOL paused;
}
#property (nonatomic, retain) NSTimer *timer;
#property (readwrite, nonatomic) int time;
#property (nonatomic) BOOL paused;
#property (readwrite, retain) IBOutlet UILabel *leveltitle;
#property (nonatomic, readwrite) IBOutlet UILabel *label;
-(IBAction)back;
-(IBAction)pause;
#end
view2.m
#import "view2.h"
#import "view3.h"
#interface view2 ()
#end
#implementation view2
#synthesize leveltitle, label;
#synthesize time, timer;
#synthesize paused;
-(void)countDown2
{
if (paused == NO && time>0)
{
time = time -1 ;
view3 *obj = [[view3 alloc] init];
obj.sss = time;
if (time == 0)
{
[timer invalidate];
}
[label setText:[NSString stringWithFormat:#"%i",time]];
}
}
-(IBAction)back{
[self.navigationController popViewControllerAnimated:YES];
}
-(IBAction)pause{
view3 *obj = [[view3 alloc] init];
[self.navigationController pushViewController:obj animated:YES];
paused = YES;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
paused = NO;
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(countDown2) userInfo:nil repeats:YES];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
view3.h
#import <UIKit/UIKit.h>
#interface view3 : UIViewController
{
int sss;
}
#property (nonatomic) int sss;
-(IBAction)back;
#end
view3.m
#import "view3.h"
#import "view2.h"
#interface view3 ()
#end
#implementation view3
#synthesize sss;
-(IBAction)back{
view2 *obj = [[view2 alloc] init];
obj.paused=NO;
obj.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(cont) userInfo:nil repeats:YES];
//[obj.timer fire];
[self.navigationController popViewControllerAnimated:YES];
}
-(void)cont{
view2 *obj = [[view2 alloc] init];
obj.time = sss;
if (obj.paused == NO && time>0)
{
obj.time = obj.time -1 ;
if (obj.time == 0)
{
[obj.timer invalidate];
}
[obj.label setText:[NSString stringWithFormat:#"%i",obj.time]];
}
}
- (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 from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
It is because in view3's back method, you created a new instant of view2 name obj and set paused=NO. But that obj was not the same instant of view2 when you pop back. What you need to do is to use a delegate method pattern, so that view3 will have a callback method in view2 to set the paused to NO.
For an example of delegate method pattern, check out an example from this SO.
Edit: sample callback code:
Make these addition/changes to your code:
In view2.h:
#import "view3.h"
#interface view2 : UIViewController <view3Delegate>
In view2.m:
-(IBAction)pause{
view3 *obj = [[view3 alloc] init];
obj.delegate = self; //adding this line
[self.navigationController pushViewController:obj animated:YES];
paused = YES;
}
-(void)setPausedValue:(BOOL)value //this is the new method callback from view3 to set paused value
{
paused = value;
}
In view3.h:
#import <UIKit/UIKit.h>
#protocol view3Delegate <NSObject>
-(void) setPausedValue:(BOOL)value;
#end
#interface view3 : UIViewController
{
int sss;
}
#property (assign) id <view3Delegate> delegate;
#property (nonatomic) int sss;
-(IBAction)back;
#end
In view3.m:
#implementation view3
#synthesize delegate;
-(IBAction)back{
// view2 *obj = [[view2 alloc] init];
// obj.paused=NO;
[self.delegate setPausedValue:NO]; //make callback and set value
obj.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(cont) userInfo:nil repeats:YES];
//[obj.timer fire];
[self.navigationController popViewControllerAnimated:YES];
}

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

Resources