inserting an image in view or delegate - drawrect

Right now my code was an app delegate, a view controller, and a main view
right now i'm just trying to insert a large image as the background, but i can't figure out where to put it and i'm getting an error when i run a simulation
<Error>: CGContextRestoreGState: invalid context 0x0. This is a serious error. This application, or a library it uses, is using an invalid context and is thereby contributing to an overall degradation of system stability and reliability. This notice is a courtesy: please fix this problem. It will become a fatal error in an upcoming update.
- (void) applicationDidBecomeActive: (UIApplication *) application {
NSLog(#"AAAAAAAAAA");
[self startGameLoop];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(#"AAAAA");
mainView = [[MainView alloc] initWithFrame: [UIScreen mainScreen].applicationFrame];
mainView.backgroundColor = [UIColor grayColor];
[self.window addSubview: mainView];
[self.window makeKeyAndVisible];
[self startGameLoop];
return YES;
}
- (void) startGameLoop {
quack = [NSTimer scheduledTimerWithTimeInterval:.0303 target:self selector:#selector(loop) userInfo:nil repeats:YES];
NSLog(#"Game Loop timer instance: %#", quack);
mainView.backgroundColor = [UIColor grayColor];
}
- (void) loop {
NSLog(#"BBBBBB");
pic = [UIImage imageNamed:#"f1.png"];
[pic drawAtPoint:CGPointMake(160, 0)];
[mainView setNeedsDisplay];
}
- (void) drawRect: (CGRect) rect {
maps = [UIImage imageNamed:#"map.png"];
[maps drawAtPoint:CGPointMake(W/2, 0)];
}

You're calling a method ( [pic drawAtPoint:] ) that requires a "current" graphics context, outside of a graphics context. UIKit automatically creates one behind the scenes before any call to drawRect:.
Also, your drawRect must be in the MainView class, not within the UIApplicationDelegate.
Try removing [pic drawAtPoint:CGPointMake(160,0)] from within loop.
If you want to draw it every loop, it must be done within the drawRect method, within the MainView class.
Also, you mentioned you're using a view controller but I see none referenced in your code.
But if you only want to move an image around, you may want to consider NOT calling setNeedsDisplay. Rather, create a UIImageView, add it to your view, and setting its center property within the loop method.

Related

UIView Doesn't Appear and drawRect Method Never Called

I've made a UIView subclass called MiniView.
I try adding it to my viewController as follows:
#interface SomeViewController ()
#property (strong, nonatomic) MiniView *miniView;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
self.miniView = [[MiniView alloc] initWithFrame:CGRectMake(20.f, 20.f, 200.f, 200.f)];
_miniView.backgroundColor = [UIColor blackColor];
[self.view addSubview:_miniView];
}
The MiniView class looks like this:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"DRAW RECT");
CGContextRef context = UIGraphicsGetCurrentContext();
UIColor * redColor = [UIColor colorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0];
CGContextSetFillColorWithColor(context, redColor.CGColor);
CGContextFillRect(context, self.bounds);
}
But drawRect never gets called, unless I explicity call it, from within the setNeedsLayout method. It also doesn't draw anything. I've tried just adding a UIImageView in the drawRect method, and this appears fine. But the above code produces nothing.
I also get the error:
: CGContextSetFillColorWithColor: invalid context 0x0. This is
a serious error. This application, or a library it uses, is using an
invalid context and is thereby contributing to an overall degradation
of system stability and reliability. This notice is a courtesy: please
fix this problem. It will become a fatal error in an upcoming update.
If I print a log statement in the drawRect method and output the 'rect' values, it's correct at 200 x 200, so I don't know why the context is 0x0.
So one problem is that drawRect is never called, and the other problem is that if I call it explicitly, nothing is displayed...
You probably need to call setNeedsDisplay on your custom UIView subclass:
- (void)viewDidLoad {
[super viewDidLoad];
self.miniView = [[MiniView alloc] initWithFrame:CGRectMake(20.f, 20.f, 200.f, 200.f)];
_miniView.backgroundColor = [UIColor blackColor];
[_miniView setNeedsDisplay]; // Added this
[self.view addSubview:_miniView];
}
This is basically a prod to tell the system your UIView needs to be redrawn. See the docs for more info.
Posting as a separate answer as requested:
The actual problem was that I had redefined the setNeedsDisplay method in the MiniView class, like so:
- (void)setNeedsDisplay
{
NSLog(#"Redrawing info: %#", [_info description]);
}
Because I had neglected to make a call to [super setNeedsDisplay], drawRect was never being called and nothing was drawing. So this fixed it:
- (void)setNeedsDisplay
{
[super setNeedsDisplay];
NSLog(#"Redrawing info: %#", [_info description]);
}
Never call drawRect explicity, try this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.miniView = [[MiniView alloc] initWithFrame:CGRectMake(20.f, 20.f, 200.f, 200.f)];
_miniView.backgroundColor = [UIColor blackColor];
[self.view addSubview:_miniView];
[_miniView setNeedsDisplay];
}
Well in your drawrect method include this line:-
[super drawRect:rect];

Unbalanced calls to begin/end appearance transitions for <xxViewController: 0xaa82610>

I tried to add TapforTap Ads to my iPhone app, the ad appear but I show this message in console "Unbalanced calls to begin/end appearance transitions for ." after any navigation of pages and then the app crash, the below code for calling TapForTap Ads. How I can solve this problem?
- (void)viewDidLoad
{
[super viewDidLoad];
CGFloat y = self.view.frame.size.height - 50.0;
TapForTapAdView *adView = [[TapForTapAdView alloc] initWithFrame: CGRectMake(0, y, 320, 50) delegate: self];
[self.view addSubview: adView];
[TapForTapAppWall prepare];
[TapForTapAppWall showWithRootViewController: self]; // or possibly self.navigationController
}
Thanks A lot
I don't know it for sure. But try this:
- (void) ShowTapAd {
CGFloat y = self.view.frame.size.height - 50.0;
TapForTapAdView *adView = [[TapForTapAdView alloc] initWithFrame: CGRectMake(0, y, 320, 50) delegate: self];
[self.view addSubview: adView];
[TapForTapAppWall prepare];
[TapForTapAppWall showWithRootViewController: self]; // or possibly self.navigationController
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSelectorOnMainThread:#selector(showTapAd) withObject:nil waitUntilDone:NO];
}
The run time warning that you got appears when you hussle with two (or more) segue, Navigation Controller push or present modally types of processes. Meaning when you initiate one before the former was totally finished.
I am surprised that those things can happen when you call something within viewDidLoad. So you may find out that the root cause is not located within the code sniplet that you have shown. But if it is then this could do the trick.
What it does:
It just makes sure that your setup of the ad view is performed after viewDidLoad is properly finished. As viewDidLoad runs on the main tread as all UI related stuff does (or should do), the current appearance transistion should be finised by then.
Hope, this helps. Again, it is just a guess.

Can't programmatically move label in viewDidLoad

I'm trying to move a uiLabel down a drop if it's an iPhone 5 (4" display). But it's not working when the code is in viewDidLoad. If I call the code from clicking a uiButton, it works. Here's the code:
-(void) viewDidLoad {
if(CGSizeEqualToSize([[UIScreen mainScreen] preferredMode].size,CGSizeMake(640, 1136))) {
CGRect frame = [self.timeOnCurrentQuestion frame];
frame.origin.y += 40; // change the location
[self.timeOnCurrentQuestion setFrame:frame];
nslog(#"This DOES get logged");
}
}
Jonah, have you tried your code in viewWillAppear method? Possibly, it'll sort-out your issue.
Maybe that are something you need to beware of.
- (void)viewDidLoad
It is a method that when the controller juz created its view.
for example:
maybe in your init method, you call something like:
[self.view setBackground:[UIColor redColor]];
self.timeOnCurrentQuestion = [[UIView alloc] initWithFrame:kFrame];
In this case the work flow will be like this:
[self.view setBackground:[UIColor redColor]];
[self viewDidload];
self.timeOnCurrentQuestion = [[UIView alloc] initWithFrame:kFrame];
Th reason for this work flow is because the self.view is called, then its view is needed before the normal view cycle, so , in this case, self.timeOnCurrentQuestion is still nil in the viewDidload method.
I don't know if my practice is the best or not.
I always init the subView in the controller's init method.
and do the [self.view addSubview:_subview] (//or everything method call that require the self.view) in [self viewDidload];
viewDidAppear worked for me. The life cycle seems to be
LoadView()
viewDidLoad()
viewWillAppear()
viewDidAppear()

calling addSubview in initWithNibName: causes viewDidLoad (and other UI Object inits)to fire before the addSubview Call executes

I'm adding a button in the middle of my initWithNibName:bundle:, when i add the button view to self.view, the view goes to start to initialize before it add's the button. So the Code in viewDidLoad gets fires before the initWithNibName:bundle: is finished. There is code below the addSubview that is relied on in the viewDidLoad and causes it to crash/not work since the init code has not run.
I've had the same experience when I added the button code to the viewDidLoad method. There is a UITableView in the .xib and the table gets inited before the rest of the viewDidLoad gets run and caused the tableView to get bad Data.
What is the best practice for adding a view to a view when you are initing and loading the view? just put all the addSubViews before the Return?
Thanks!
Here is my initWithNibName:bundle:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
self = [super initWithNibName:nibNameOrNil bundle:nil];
[self setIoUIDebug:(IoUIDebugSelectorNames)];
if (IoUIDebug & IoUIDebugSelectorNames) {
NSLog(#"%# - %#", [self description], NSStringFromSelector(_cmd) );
}
CGRect frame = CGRectMake(20, 521, 500, 37);
saveButton = [UIButton newButtonWithTitle:NSLocalizedStringFromTable(#"Save Animation Label",#"ScreenEditor",#"Save Animation Label")
target:self
selector:#selector(saveButtonPressedAction:)
frame:frame
image:[UIImage imageNamed:#"BlueButtonSmall.png"]
imagePressed:[UIImage imageNamed:#"BlueButtonSmallPressed.png"]
darkTextColor:NO];
[self.view addSubview:saveButton]; // <- Right here I'll hit breakpoints in other parts of viewDidLoad and cellForRowAtIndexPath, before the lined below get executed.
[saveButton setEnabled: NO];
[saveButton setUserInteractionEnabled: NO];
newAnimation = nil;
selectedSysCDAnimation = nil;
selectedIoCDTag = nil;
animationSaved = NO;
return self;
}
You should add the subviews inside viewDidLoad this will mean that the views are added when the main view is loaded into memory. I would reserve your initWithNibName:bundle: call for custom initialization and not interacting with the UI as this what viewDidLoad is designed for.
In regards to your tableView, you should put a call to load the tables datasource inside of viewDidLoad. Once the datasource is loaded, you can simply call reloadData on the tableview to load the data into the tableview.
For Example:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:saveButton];
[self loadDataSource];
}
- (void)loadDataSource {
// load datasource here
[self.tableView reloadData];
}
Any access to the view property of the view controller will lazily initialize the view. This will trigger a call to viewDidLoad which will execute before the access to the view property returns in initWithNibName:. You should add the sub view in viewDidLoad or using interface builder.

Subviews not showing up in UIView class

I'm trying to lay out some images in code using addSubview, and they are not showing up.
I created a class (myUIView) that subclasses UIView, and then changed the class of the nib file in IB to be myUIView.
Then I put in the following code, but am still getting a blank grey screen.
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
[self setupSubviews];
}
return self;
}
- (void)setupSubviews
{
self.backgroundColor = [UIColor blackColor];
UIImageView *black = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"black.png"]];
black.center = self.center;
black.opaque = YES;
[self addSubview:black];
[black release];
}
yes, just implement initWithCoder.
initWithFrame is called when a UIView is created dynamically, from code.
a view that is loaded from a .nib file is always instantiated using initWithCoder, the coder takes care of reading the settings from the .nib file
i took the habit to do the initialization in a separate method, implementing both initWithCode and initWithFrame (and my own initialization methods when required)
try implementing initWithCoder: sometimes I've had trouble with IB and initWithFrame:
or at least add a logging call to see if your init method is executed