glkView drawInRect not called - iphone

I am learning OpenGLES and I am trying to put a GLKViewer inside an UIViewController.
I know I can come around the main issues by using GLViewController, but I am trying to learn how to do it this way.
I found this question, Nesting GLKView into UIViewController and Nested GLKView and GLKViewController but I must be missing something even though I think I am doing all the right steps because when I run my project, I am not getting to the drawInRect print line.
In the storyboard I am pointing the ViewController as the delegate of the glkview component.
I tried to keep the code as simple as possible and any help will be apreciated:
MyController.h
#import <Foundation/Foundation.h>
#import <GLKit/GLKit.h>
#interface MyGLController : UIViewController <GLKViewDelegate>
{
GLuint vertexBufferID;
}
#property (weak, nonatomic) IBOutlet GLKView *glview;
#property (strong, nonatomic) GLKBaseEffect *baseEffect;
#end
MyGLController.m
#import "MyGLController.h"
#implementation MyGLController
//#synthesize baseEffect;
-(void) viewDidLoad{
[super viewDidLoad];
self.glview.context = [[EAGLContext alloc] initWithAPI:
kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.glview.context];
printf("View Loaded");
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
printf("DrawInRect");
}
#end
* Update *
As far as I can tell the glkview is hooked up properly as suggested per and added the josh-knapp and called setNeedsDisplay.
In case there's something I am missing, I have uploaded a copy of the project here: https://github.com/jcrogel/OpenGLDebug.git
I am a total noob in this so I apologize for any silly oversight :)

You didn't say you hooked up the glview property of MyGLController in the storyboard, so verify that.
Next, you're setting up the glview context after it loads. Without a GLKViewController, there is nothing telling the glview it needs to be drawn. Make sure you call [self.glview setNeedsDisplay] somewhere after the context is set up.

I had a similar problem.
By default, xcode sets the enable setNeedsDisplay checkbox to NO in GLKView property list.
Once I changed it, it worked.

I see this question was already answered. But I had the same problem, with a different solution. I figured I'd post the info here on the off chance others might be able to benefit from it.
Problem Description
While using GLKView and GLKViewController, the render loop function (drawInRect) is called once, but not called again.
Possible Cause
Some methods to CViewController have been implemented incorrectly, without calling their supers. The following code illustrates three such functions. The examples below have the three functions implemented correctly, calling their supers.
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:NO];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:NO];
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:NO];
}

Related

Objective-C initialization in awakeFromNib seems not working

Initializing in awakeFromNib seems not working.
I have PBManager.m and In ViewController.m I made property for PBManager like
#interface ViewController : UIViewController
#property (strong, nonatomic) PBManager * pbMgr;
#end
And tried to initialize it in awakeFromNib like
- (void) awakeFromNib {
self.pbMgr = [PBManager sharedInstance]; // singleton. would be no problem...
}
and I used it in button action
- (IBAction)btnSendAction:(UIButton *)sender {
[self.pbMgr sendMessage:#"sendMessage" key:#"testKey" val:#"val"];
}
but this self.pnMgr in btnSendAction is null!
But it works when I initialize it in viewDidLoad.
Please tell me what's going on.
Thanks.
You need [super awakeFromNib];
From the documentation:
You must call the super implementation of awakeFromNib to give parent classes the opportunity to perform any additional initialization they require. Although the default implementation of this method does nothing, many UIKit classes provide non-empty implementations. You may call the super implementation at any point during your own awakeFromNib method.

iOS iPhone is it possible to clone UIView and have it draw itself to two UIViews?

I'm thinking of a way to have a UIView render itself onto another UIView as well as the first one. So I have my main UIView with it's bounds, and the UIView also renders itself in some other UIView.
Is this possible ? Does it require extensive layer operations?
Don't know whats your real intention is, but this will draw the view twice, userinteraction etc. will not work on the second view. Also this solution does not take care of different frame sizes.
Header of the View you want to clone
#interface SrcView : UIView
#property(nonatomic, readonly, strong) UIView *cloneView;
#end
#interface CloneView : UIView
#property(nonatomic, weak) UIView *srcView;
- (id)initWithView:(UIView *)src;
#end
implementation of the View you want to clone
#import "SrcView.h"
#import "CloneView.h"
#implementation SrcView
#synthesize cloneView;
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx{
[cloneView setNeedsDisplay];
}
- (UIView *)cloneView {
if (!cloneView) {
cloneView = [[CloneView alloc] initWithView:self];
}
return cloneView;
}
#end
#implementation CloneView
#synthesize srcView;
- (id)initWithView:(UIView *)src {
self = [super initWithFrame:src.frame];
if (self) {
srcView = src;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[srcView.layer renderInContext:UIGraphicsGetCurrentContext()];
}
#end
now you can just call cloneView and add it somewhere you want.
This seems to be an oft asked question here on StackOverflow. For example:
iphone, ipad Duplicate UIView - Cloned View
Copying the drawn contents of one UIView to another
UIView duplicate
Duplicate, clone or copy UIView
But if it were me doing this, my first approach would be to get a handle to the UIView I want to copy, then recursively iterate all the subviews of it and then copy & add them as subviews to the UIView I want to copy the main UIView into.
I can't imagine there's too much layer operations going on with this, but you would likely need to figure out how to programmatically re-establish outlets and/or actions.
There is no easy way to clone a view and then to update two views by one line of code. Because their underlying CALayers are different. But for duplicating a UIView, here is a new method you can use: Use UIView's method:
- (UIView *)snapshotViewAfterScreenUpdates:(BOOL)afterUpdates
This is the fastest way to draw a view. Available in iOS 7.
Create another instance of the UIView you wish to "clone" and add it as a subview to another view. You don't really clone a UIView object, you simply create another instance of it.

iOS - Scrolling two UITextViews simultaneously

I've done some looking around but I haven't been able to find anything that clearly explains how I could simultaneously scroll two un-editable UITextViews. I think I may need to use either scrollRangeToVisible, or setContentOffset, though I could not get either of them to work.
Does anyone have any examples/samples, or documentation regarding this that they could point me towards?
EDIT: To clarify, I would like to be able to scroll one UITextView, and have the changes as a result of the scrolling reflected on a second UITextView as well.
Thanks!
Use the UIScrollViewDelegate methods to get information about scroll actions of the first scroll view and then scroll the second programmatically like that:
- (void) scrollViewDidScroll:(UIScrollView *)view1 {
scrollView2.contentOffset = view1.contentOffset;
}
React in
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
and set the other's scrollView setContentVisible according to scrollView.contentOffset.
Just be aware that some methods of UIScrollView will invoke scrollViewDidScroll even if called programmatically. This applies to scrollRangeToVisible and will end up in a loop unless you take action to prevent this loop. I don't think that setContentOffset or setting scrollView2.contentOffset = CGPointMake(..,..) does call scrollViewDidScroll. However, I would not sign this in blood. Be prepared to see a loop and take actions to avoid it. (such as boolean instance variable set before calling setContentOffset and re-set in scrollViewDidScroll followed by return;)
Just continuing with previous answers, to give some more information, I generated this code:
In the interface (.h):
#import <UIKit/UIKit.h>
#interface DoubleTextViewController : UIViewController <UITextViewDelegate>
#property (strong, nonatomic) IBOutlet UITextView *textView1;
#property (strong, nonatomic) IBOutlet UITextView *textView1;
#end
In your implementation (.m):
Use this viewDidLoad function after defining the corresponding properties and global variables.
#import "DoubleTextViewController.h"
#define TEXT_VIEW_1_TAG 1001
#define TEXT_VIEW_2_TAG 1002
#interface DoubleTextViewController () {
BOOL isScrolling;
}
#end
#implementation DoubleTextViewController
#synthesize textView1, textView2;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view..
isScrolling = NO;
[self.textView1 setTag:TEXT_VIEW_1_TAG];
[self.textView2 setTag:TEXT_VIEW_2_TAG];
[self.textView1 setDelegate:self];
[self.textView2 setDelegate:self];
}
And add this function for simultaneous scroll.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (isScrolling) {
return;
}
isScrolling = YES;
if (scrollView.tag == TEXT_VIEW_1_TAG) {
[self.textView2 setContentOffset:scrollView.contentOffset animated:NO];
} else if (scrollView.tag == TEXT_VIEW_2_TAG) {
[self.textView1 setContentOffset:scrollView.contentOffset animated:NO];
}
isScrolling = NO;
}
As proposed by Hermann Klecker, the isScrolling variable stops scrolling loops and makes the user experience nicer. Using the code proposed by Fabian Kreiser makes the scroll stops as soon as the user leaves the finger, making it strange.

"Variable Undeclared" error when compiling to iOS Device, but not for Simulator

I have an custom UIVIewController that is the base class for other controllers and has an instance of a custom UIView variable that is accessed by inherited the classes.
BaseViewController.h
#interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
#end
BaseViewController.m
#import "BaseViewController.h"
#implementation BaseViewController
-(void)loadView {
[super loadView];
_vwHeader = [[UIView alloc] init];
}
#end
CustomViewController.h
#import "BaseViewController.h"
#interface CustomViewController : BaseViewController
#end
CustomViewController.m
#import "CustomViewController.h"
#implementation CustomViewController
- (void)loadView
{
[super loadView];
[_vwHeader setHidden:NO];
}
#end
The problem is that when I am running it on the simulator everything works perfectly fine, but when I change to the device I have an error on the [_vwHeader setHidden:NO]; line which says: '_vwHeader' undeclared (first use in this function)
I already tried to do:
Comment this line of code, but then it gives me an error in another class using a variable from the base class the same way (It only returns one error at a time), so it seems that it is not an specific error in the view or the controller class as the error occurs in other clases with different types, such as UIView and NSObject types
Change target compiler configuration, such as: architectures (all of them), base sdk (all above 4.0) didn't change anything
What seem to solve the problem, but not completely
Creating a property for _vwHeader and accessing it by self._vwHeader or super._vwHeader seems to work, but having to create a property just to access a variable does not make me confortable, specially because I would have to do it for all variables in the same situation inside my project.
changed C/C++ compiler version: using Apple LLVM Compiler 2.1 makes the compilation error goes away, but gives a bunch of other problems with other libraries being used in the project. So, it is not a definitive solution, but might be a clue of what the problem is.
EDIT:
I tried to create another variable that is not a pointer, a BOOL instead of the UIView * and then used it in the inherited class: the problem also occurs
EDIT (2):
I have no properties whatsoever in any of my classes and I still get the error.
I just added the properties for test porpouses, to see if a property in a parent class caused the same behaviour, and apparently it doesn't.
Something that is also weird is that when I get the error in the variable, I checked with my intellisense and it finds it...
In order to refer to an instance variable within any object other than self, including super, you must use the structure pointer operator (->). The default scope of an instance variable is protected, which means it can only be accessed within the class it is defined in or a subclass of that class. Since CustomViewController is a subclass of BaseViewController, this scope is sufficient to access the variable using self->_vwHeader, but if the second class you were trying to do this from is not a subclass you will also need to change the scope to either #public or #package.
In summary, change your method call to:
[self->_vwHeader setHidden:NO];
and it should work for any subclasses of the base view controller.
Do a clean and build, and also make sure you are not specifying a specific framework search path in the build settings. If you leave it empty you should get the correct libraries.
well I don't know, should work.
BaseViewController.h
#interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
#property(nonatomic,retain)UIView *_vwHeader;
#end
BaseViewController.m
#synthesize _vwHeader;
CustomViewController.m
#import "CustomViewController.h"
#implementation CustomViewController
- (void)loadView
{
[super loadView];
[self._vwHeader setHidden:NO];
}
#end
I faced similar problem as you. In my case the reason was (strangely!) wrong synthesization of properties in subclass.
Example:
In .h file of subclass you have following declaration
BOOL _flag;
...
#property (nonatomic, assign) BOOL flag;
while in you synthesize the property in the wrong way:
#synthesize flag;
instead of
#synthesize flag = _flag;
Strangely, the compiler does not complain about the wrong synthesization (the properties even work fine!), but raises an error, when I try to access protected fields declared in base class.
Detailed explanation
Here is what my code look like
I have base class (excerpt):
#interface BaseEditionModalController : NSObject
{
DataContext *_dataContext;
}
And I have subclass of it (excerpt):
#interface LocationModalController : BaseEditionModalController
{
MCLocation *_readLocation;
LocationCommModel *_oldLocationCommModel;
}
//This is MCLocation for reading only - from the main application context
#property (nonatomic, retain) MCLocation *readLocation;
#property (nonatomic, retain) LocationCommModel *oldLocationCommModel;
#end
And in the LocationModalController.m I have following wrong declarations:
#implementation LocationModalController
#synthesize readLocation;
#synthesize oldLocationCommModel;
Trying to access _dataContext in LocationModalController produced the error that _dataContext is undeclared.
Changing the synthesization of properties to:
#implementation LocationModalController
#synthesize readLocation = _readLocation;
#synthesize oldLocationCommModel = _oldLocationCommModel;
MAGICALLY SOLVES THE PROBLEM!
Regards
I just stumble upon your method declaration
-(void)loadView { ... }
In a view the first point you can rely that everything is fully initialized is after -(void)viewDidLoad was called. Maybe your code works on the simulator because your Mac is fast enough to cope this speed issue - but your mobile device isn't.
Maybe try this coding:
Your BaseViewController.h file:
#interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
#end
Your BaseViewController.m file:
#import "BaseViewController.h"
#implementation BaseViewController
-(void)viewDidLoad {
[super viewDidLoad];
_vwHeader = [[UIView alloc] init];
}
Your CustomViewController.h file:
#interface CustomViewController : BaseViewController {
}
#end
Your CustomViewController.m file:
#import "CustomViewController.h"
-(void)viewDidLoad {
[super viewDidLoad];
[_vwHeader setHidden:NO];
}
Now your CustomViewController can rely on every instance variable in BaseViewController is correctly instantiated.
The error says that _vwHeader undeclared.
So try by modifying the code in:
CustomViewController.m
#import "CustomViewController.h"
#implementation CustomViewController
- (void)loadView
{
[super loadView];
if(!_vwHeader)
{
_vwHeader = [[UIView alloc]init];
}
[_vwHeader setHidden:NO];
}
#end
It is possible that when you compile for target and for simulation the data members are either protected or private. Probably for target are private by default and this seems to cause the problem. Try out playing with the #private and #protected keywords.
However, I strongly suggest that you use properties even between your super/sub-classes. Having a complex structure is a bit hard to debug. Setting up a property will transfer the access to the data through the getter/setter methods (a breakpoint on #synthesize also works) and you will be able to see in the call stack who is accessing what.
Especially, the syntax #synthesize propertyName = prefixDataNameSufix; allows you to easily adjust your class interface style without having to modify your coding habits.
I had the exact same problem and it turns out that I did not remove an unused iVar/property in the SUBCLASS. Let's call it session. I removed _session from the iVar but I forgot to remove it from the properties, then in the .m file I had this synthesize session = _session. Once I removed them all, I can compile for iOS device without problems.
If you think your superclass is fine, look into your subclass, check your iVars and properties and synthesize section in the .m file
I had this exact problem.
In my case, I was relying on ivar synthesis of a property. That is, I did NOT declare UITextView *textView_, but I did #synthesize textView = textView_;
This builds fine on my iOS Simulator. However, my iOS device build fails, regardless of whether I use llvm or gcc.
When I add the declaration back to my interface:
#interface MyTableViewController : BaseTableViewController {
#private
UITextView *textView_; // this line is important!
}
Everything works fine!
See the answer from tc above. This is a bug in the compiler shipped with sdk 4.2.
Specifically I have seen the same error and if on the same machine I have sdk 4.2 and sdk 4.3 installed the error disappears (even if I compile for 4.2).
If anyone is having this issue after upgrading their tools and devices to iOS10, I had it and found that declaring them as weak, nonatomic in the .h file was the issue. I had never encountered this when doing so before but after removing (weak, nonatomic) from the property declaration, everything worked fine again.

Objects in nib file not associating with IBOutlet objects in code

OK I'm pulling my hair on on this, it makes no sense so it must either be a bug, or some extremely stupid mistake I'm making.
Here's the situation: I have a UIViewController with a xib file. It has a UIView hooked up to the view property, a UIImageView hooked up to a property called imageView, and a UISegmentedControl hooked up to segmentControl.
Yet in my code, I'm unable to assign an image to the image view. When I NSLog the object, I'm getting the address of 0x0, so it's not associating at all. I have the bindings set up in Interface builder, I've restarted XCode and clean and built the project. Nothing is working and I've wasted a stupid amount of time trying to figure this out at this point. I've also NSLoged the segmentControl object and am getting 0x0 as well. So nothing from the XIB is hooking up with the code, but the XIB itself is loading because the objects are displayed on the screen.
Does anyone have any ideas offhand of what I could be missing? This is such a simple thing, it's incredibly frustrating that it's refusing to work all of a sudden.
Here's the code below, in this case I'm accessing the objects in the setter for projectId, but I also tried accessing the imageView from another class and it didn't work either (and yes I had a #property declaration and synthesize for imageView when I tried).
DiagramViewController.h:
#import <UIKit/UIKit.h>
#interface DiagramViewController : UIViewController
{
NSUInteger projectId;
IBOutlet UIImageView *imageView;
IBOutlet UISegmentedControl *segmentControl;
}
#property NSUInteger projectId;
#end
DiagramViewController.m:
#import "DiagramViewController.h"
#implementation DiagramViewController
#synthesize projectId;
-(void)setProjectId:(NSUInteger)projId
{
NSLog(#"imageView: %#", imageView);
NSLog(#"segmentControl: %#", segmentControl);
projectId = projId;
NSString *filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"%i_schem", projectId] ofType:#"png" inDirectory:#"project-details/images/diagrams"];
NSData *imageData = [NSData dataWithContentsOfFile:filePath];
imageView.image = [UIImage imageWithData:imageData];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Overriden to allow any orientation.
return YES;
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
#end
And here's an image of the Interface Builder hookups:
You need to make sure you're doing this in the -viewDidLoad method, otherwise the nib file hasn't actually unarchived the objects and thus they will be set to nil. In particular, you can't access items from the nib within an -init method.
Without seeing your code however, it's hard to say if this is the case for you.
EDIT: Ok, thanks for posting code. When does -setProjectId: get invoked? Are you sure the nib has finished loading at this point? You have no viewDidLoad method in your view controller so it appears you never check for this at any time.
See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
viewDidLoad
Called after the controller’s view is loaded into memory.
(void)viewDidLoad
Discussion
This method is called after the view controller has loaded its associated views into memory. This method is called regardless of whether the views were stored in a nib file or created programmatically in the loadView method. This method is most commonly used to perform additional initialization steps on views that are loaded from nib files.
Sounds like something went wrong when you wired up the IBOutlets.
In IB right click on the UISegmentedControl and post a screenshot so that we can see what you have there. If you see anything 'yellow' then you may have found your problem.