So, I am following this Xcode tutorial book: Iphone and Ipad Game Development for Dummies. Its a good book, but there are some flaws here and there. Most of the time I can figure a way around these flaws, but now I stumbled upon something I cant fix. Even their website or contacts dont know the answer.
Im trying to make a game with cars and stuff. But the problem lies with the main menu. I already made buttons with custom button mode. And used IbActions to make them work(actually, "New Game" is the only button that works now cause it has its function already scripted). But now I have to make IBOutlets to give them an Animation. The book told me to use the QuartzCore.framework. Now the problem is that when I try to build it I get this error: No Declaration of property 'newGameButton' found in the Interface.
This is my script.
The header file:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface MainMenuViewController : UIViewController {
//This has changed
#property(nonatomic,retain) IBOutlet UIButton* newGameButton;
#property(nonatomic,retain) IBOutlet UIButton* statsButton;
#property(nonatomic,retain) IBOutlet UIButton* settingsButton;
CAKeyframeAnimation* popAnimation;
}
-(IBAction) newGame:(id)sender;
-(IBAction) showStats:(id)sender;
-(IBAction) showSettings:(id)sender;
#end
And the .m file (its called implantation right?):
#import "MainMenuViewController.h"
#import "TrafficAppDelegate.h"
#import "TrafficViewController.h"
#implementation MainMenuViewController
-(IBAction) newGame:(id)sender{
TrafficViewController* traffic = [[TrafficViewController alloc] initWithNibName:#"TrafficViewController" bundle:nil];
[self.navigationController pushViewController:traffic animated:NO];
}
-(IBAction) showStats:(id)sender{
}
-(IBAction) showSettings:(id)sender{
}
#synthesize newGameButton, statsButton, settingsButton;
-(void)viewDidLoad{
[super viewDidLoad];
popAnimation = [CAKeyframeAnimation animationWithKeyPath:#"transform.scale"];
popAnimation.keyTimes = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.7], [NSNumber numberWithFloat:1.0], nil];
popAnimation.values = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0.01], [NSNumber numberWithFloat:1.1], [NSNumber numberWithFloat:1.0], nil];
[popAnimation retain];
}
-(void)popView:(UIView*)view{
[view setHidden:NO];
[[view layer] addAnimation:popAnimation forKey:#"transform.scale"];
}
-(void)viewWillAppear:(BOOL)animated{
[popAnimation setDuration:0.3];
[newGameButton setHidden:YES];
[statsButton setHidden:YES];
[settingsButton setHidden:YES];
[self performSelector:#selector(popView:) withObject:newGameButton afterDelay:0.25];
[self performSelector:#selector(popView:) withObject:statsButton afterDelay:0.3];
[self performSelector:#selector(popView:) withObject:settingsButton afterDelay:0.35];
}
#end
Now I first tought that they werent connected to the buttons in the User Interface builder. But that didnt work either. I tried to remake the whole script. I tried to reload the script in Xcode. I even tried to make my own version. Im dont have any options left. Does anyone know what is wrong with my script?
set the property of the objects in header file as
#property(nonatomic, retain) IBOutlet UIButton* newGameButton;
.
.
.
and in .m file synthesis them using
#synthesis newGameButton;
do this for all the objects that you have declared
and then connect them in the IB
Are you loading the proper UIViewController?? i mean, if you are working with the interface builder check out that in your main window xib, the viewController object you are using corresponds with your MainMenuViewController class
You have said you were seeing:
"No Declaration of property 'newGameButton' found in the Interface"
Any property that is declared in either the .h (header) or .m (implementation) must be synthesised:
#property (nonatomic,retain) IBOutlet UIButton* newGameButton;
Like this for your properties in the .m (implementation)
#synthesize newGameButton;
Related
having a little issue in an ARC environment. Creating an NSObject that adds a view to a parent view - it's basically a 'popup class' that can handle some text and display it.
In a view controller it's instantiated..
CBHintPopup *popup = [[CBHintPopup alloc]init];
[popup showPopupWithText:#"test text" inView:self.view];
And the actual class files..
CBHintPopup.h
#interface CBHintPopup : NSObject {
}
-(void)showPopupWithText:(NSString *)text inView:(UIView *)view;
-(IBAction)closePopup;
#property (nonatomic, strong) UIView *popupView;
#property (nonatomic, strong) UIImageView *blackImageView;
#property (nonatomic, strong) UIButton *closeButton;
#end
CBHintPopup.m
#implementation CBHintPopup
#synthesize popupView,blackImageView, closeButton;
-(void)showPopupWithText:(NSString *)text inView:(UIView *)view {
//CREATE CONTAINER VIEW
self.popupView = [[UIView alloc]initWithFrame:CGRectMake((view.frame.size.width/2)-(225/2),-146,225,146)];
self.popupView.alpha = 0;
self.popupView.backgroundColor = [UIColor clearColor];
//CREATE AND ADD BACKGROUND
UIImageView *popupBackground = [[UIImageView alloc]initWithFrame:CGRectMake(0,0,225,146)];
popupBackground.image = [UIImage imageNamed:#"hintbackground.png"];
[self.popupView addSubview:popupBackground];
//CREATE AND ADD BUTTON
self.closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.closeButton addTarget:self action:#selector(closePopup) forControlEvents:UIControlEventTouchUpInside];
[self.popupView addSubview:self.closeButton];
//CREATE AND ADD LABEL
UILabel *popupTextLabel = [[UILabel alloc]initWithFrame:CGRectMake(22,25,176,93)];
popupTextLabel.text = text;
[self.popupView addSubview:popupTextLabel];
[view addSubview:self.popupView];
}
-(void)closePopup {
NSLog(#"HI");
}
Recieving the following once closePopup is called via pressing the button ('HI' is not printed)..
-[CBHintPopup performSelector:withObject:withObject:]: message sent to deallocated instance 0x246b2fe0
I've tried retaining the button in non-ARC and a load of other methods but simply having no luck. Probably something real simple but i can't nail it. I've removed all the setting up of the labels and images etc to save some space, so ignore alpha's etc.
Any help will be much appreciated, thanks for your time.
Have you implemented the constructor for CBHintPopup,since you have called the constructor
[[CBHintPopup alloc]init];
you have to implement the constructor method like this
in .m file of CBHintPopup
-(id)init{
if(self == [super init]){
// do some initialization here
}
return self;
}
I tried your code and found the crash you mentioned. I found a solution for fixing the crash.
I declared the CBHintPopup *popup; in the viewController's interface. And changed this line
CBHintPopup *popup = [[CBHintPopup alloc]init];
to
popup = [[CBHintPopup alloc]init];
Everything worked fine for me. But I couldn't find the reason behind this. Hope this will help you.
Found a fix for it - instead of CBHintPopup being an NSObject, i simply made it a sub-class of UIView and added self to the parent view (instead of self.popupView). I wouldn't really call this a 'fix' though - more of an alternative method. Surely an NSObject can add a UIView (with a UIBUtton) to a parent view with no problems? Is this a bug?
Make sure you are retaining the object for class CBHintPopup.
I think the crash is coming because object of CBHintPopup deallocates. And hence the action method is not found.
To begin, I would like to apologize for my English :)
I have FirstViewController, which contains scrollView. This is scrolView with enabled paging, and have 2 pages with 2 different view controllers. From one of the view controllers by touching the button the third view controller appears like a modal view. I call a method in FirstViewController that must disable scrolling and hide two labels which is not contained in the scrollView.
Method is executing, but UI not changes, scrolling still enabled and labels still visible.
Now a bit of code:
This is a piece of the FirstViewController.h (not the whole code):
#interface FirstViewController : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *scrollView;
IBOutlet UILabel *label1;
IBOutlet UILabel *label2;
}
#property (nonatomic, retain) UILabel *label1;
#property (nonatomic, retain) UILabel *label2;
#property (nonatomic, retain) UIScrollView *scrollView;
-(void)prepareToModal;
#end
Now it's -(void)prepareToModal; implementation:
-(void)prepareToModal {
[label1 setHidden:YES];
[label2 setHidden:YES];
scrollView.scrollEnabled = NO;
}
So, from the one of the view controllers, which contained in scrollView, I call prepareToModal
Previously:
#import "FirstViewController.h"
Next:
FirstViewController *vc = [[FirstViewController alloc] init];
[vc prepareToModal];
[vc release];
So, that's all. I put a breakpoint in prepareToModal, and it stopped executing. The method is called, but nothing changes on screen...
What am I doing wrong?
How to do this correctly?
Update:
I solved this problem.
When I present this modal view, I wrote this:
ThirdViewController *tvc = [[ThirdViewControler alloc] init];
tvc.delegate = self;
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:tvc];
[self presentModalViewController:nc animated:YES];
[tvc release];
[nc release];
Now, insted of [self presentModalViewController:nc animated:YES]; I write this:
[[[[UIApplication sharedApplication].windows objectAtIndex:0] rootViewController] presentModalViewController:nc animated:YES];
And It's working very well, I don't need a method -(void)prepareToModal;
Thanks a lot :)
Make sure you have hooked up your IBOutlets in Interface Builder.
I have one MainWindow.xib file. I have one label and one button on first MainWindow.xib file screen. I have secondview.xib file, i want to load secondview.xib file if user will click on main screen button. I have written a method to load Secondview by the following code..
self.second=[[[SecondWindow alloc]initWithNibName:#" HarbourFront" bundle:nil]autorelease];
from the MainWindow screen.
My interface declaration is,
#import "SecondWindow.h"
#interface TrainingProject_1AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
SecondWindow *second;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic,retain) SecondWindow *second;
-(IBAction) listTableView:(id) sender;
#end
// Definition in ".m" file
#synthesize second;
-(IBAction) listTableView:(id) sender {
NSLog(#"event called");
self.second=[[[SecondWindow alloc]initWithNibName:#" HarbourFront" bundle:nil]autorelease];
}
I checked that method is getting called but SecondWindow is not loading.
How can I load SecondWindow ?
Try this code:
self.second=[[[SecondWindow alloc]initWithNibName:#" HarbourFront" bundle:nil]autorelease];
[self .navigationController pushViewController:self.second animated:YES];
Hope it helps you....
just put this line [self.window addSubView:self.second.view]; below the line self.second=[[[SecondWindow alloc]initWithNibName:#" HarbourFront" bundle:nil]autorelease];
Im new to iphone development and after lots of reading on it im still trying to figure out how UIViews operate properly. I have been playing about with it and i this is where i am at so far:
I have created a new xcode project using the view-based application. I have my MMAppViewController classes and i created a new UIViewController subclass called "Level1View".
There is a button titled "Level 1" that takes me to the "Level1View" viewController. In this viewController there is there is a "next" button, a "main menu" button (that returns to MMAppViewController) and there is a label, currently titled "Level 1".
My problem is that the code i have used to change the title of label does not work! Does anyone know why this is? Here is my code:
#class MMAppViewController;
#interface MMAppAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MMAppViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MMAppViewController *viewController;
#end
and
#implementation MMAppViewController
-(IBAction)pushLevel1{
Level1View *level1View = [[Level1View alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:level1View animated:YES];
}
...
and
#import <UIKit/UIKit.h>
#interface Level1View : UIViewController {
IBOutlet UILabel *labelTitle;
}
-(IBAction)pushBack;
-(IBAction)pushNext;
#end
and
#import "Level1View.h"
#import "MMAppViewController.h"
#implementation Level1View
-(IBAction)pushBack{
MMAppViewController *MainView = [[MMAppViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:MainView animated:YES];
}
-(IBAction)pushNext{
[labelTitle setText:(#"Thanks for playing :)")];
}
- (void)didReceiveMemoryWarning {
...
Currently the app runs but the label wont change when i hit the "next" button. Can anyone help?
are you sure a UINavigationController isn't a better tool for the job you want to do? That will make it easy for you to manage a stack of UIView objects.
That said, have you tried adding logging to make sure your pushNext method is getting called? where is labelTitle declared? Did you use a XIB or not?
Did you bind the Label in Interface Builder to the labelTitle outlet in your Level1View?
If you forget that step, the outlets won't work. Even after several years, I still forget this step sometimes.
--Mike
are you sure you connected the label in IB?
and if you set a property "#property (nonatomic, retain) IBOutlet UILabel *labelTitle;" in Level1View.h you can access it from Main View:
Level1View *level1View = [[Level1View alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:level1View animated:YES];
level1View.labelTitle.text = #"something";
[level1View release];
The other thing you shouldn't present the Main View Controller again instead dismiss the Level1View with:
#implementation Level1View
-(IBAction)pushBack{
[self dismissModalViewControllerAnimated:YES];
}
//
and maybe the problem is [[Level1View alloc] initWithNibName:nil bundle:nil] you have to specify the nib you want to load e.g. [[Level1View alloc] initWithNibName:#"Level1View" bundle:nil]
Declare labelTitle as a property in your header file, and synthesize labelTitle in your .m - as long as labelTitle is hooked up through interface builder the rest of your code is fine.
.h
#property (nonatomic, retain) IBOutlet UILabel *labelTitle;
.m
#synthesize labelTitle;
Then your setter call will work. (also, dot-notation works for synthesized properties so you may as well use it)
change
[labelTitle setText:(#"Thanks for playing :)")];
to
labelTitle.text = #"Thanks for playing :)";
Synthesizing a property will create setter and getter methods at runtime. Read: The Objective-C Programming Language
A little background:
I'm a C# developer starting to mess with the iPhone (have an idea for a simple 2D game). The only MVC programming I've done was for the web (ASP.NET MVC) so although I do have an understanding in MVC, I can't wrap my mind around one thing. Here's an example to illustrate.
Say I have a simple app where all I want to do is display a big circle on the screen. I created a "View Based Application" and it gave me the basic classes to start with:
MVCConfusionAppDelegate
MVCConfusionViewController
Now since I'll be doing some custom drawing (I know I can add a subview and show the circle that way, but this is just a sample of a larger piece) I've added a class called MyCustomView and in Interface Builder set the View of the MVCConfusionViewController to be a MyCustomView.
Now here's the problem. I want to be able to set in code the size of how big the ball on the custom view should be. So I have a property on the MyCusomView like this:
#import <Foundation/Foundation.h>
#interface MyCustomView : UIView {
NSNumber *ballSize;
}
#property(nonatomic,retain)IBOutlet NSNumber *ballSize;
#end
#import "MyCustomView.h"
#implementation MyCustomView
#synthesize ballSize;
-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor redColor]set];
float floatValue = [self.ballSize floatValue];
CGRect ballRect = CGRectMake(50.0f, 50.0f,floatValue , floatValue);
CGContextFillEllipseInRect(context, ballRect);
}
#end
Then, here's my MVCConfusionViewController:
#import <UIKit/UIKit.h>
#import "MyCustomView.h"
#interface MVCConfusionViewController : UIViewController {
NSNumber *ballSize;
}
#property(nonatomic,retain)IBOutlet NSNumber *ballSize;
#end
#import "MVCConfusionViewController.h"
#import "MyCustomView.h"
#implementation MVCConfusionViewController
#synthesize ballSize;
- (void)viewDidLoad {
[super viewDidLoad];
MyCustomView *myView = (MyCustomView *)self.view;
myView.ballSize = self.ballSize;
}
And finally, the MVCConfusionAppDelegate:
#import <UIKit/UIKit.h>
#class MVCConfusionViewController;
#interface MVCConfusionAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MVCConfusionViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MVCConfusionViewController *viewController;
#end
#import "MVCConfusionAppDelegate.h"
#import "MVCConfusionViewController.h"
#import "MyCustomView.h"
#implementation MVCConfusionAppDelegate
#synthesize window;
#synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
viewController.ballSize = [NSNumber numberWithInt:200];
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
As you can see, there's an ugly cast in my viewDidLoad method. I was hoping I'd be able to make the connection of the ballSize properties in IB, but it won't let me.
So my question simply is, what's the correct way of passing this data from my view controller to my view without doing that cast? I know I'm missing something fundamental, but I just don't see it. Any help would be greatly appreciated!
EDIT: Here's the source code. http://bit.ly/uKyp9 Maybe someone can have a look and see if I'm doing anything wrong.
Are you trying to connect one IBOutlet (in the controller) to another IBOutlet (in the view)? Unfortunately, I don't think it's that easy :-)
You're also storing the data (ballSize) in the controller and the view.
I'd make MVCConfusionViewController a data source for MyCustomView, and then let MyCustomView ask its datasource for the ballSize, inside the -drawRect: method.
#class MyCustomView;
#protocol MyCustomViewDataSource
- (NSNumber *)ballSizeForMyCustomView:(MyCustomView *)view;
#end
#interface MyCustomView {
id<MyCustomViewDataSource> dataSource;
}
#property (nonatomic, assign) IBOutlet id<MyCustomViewDataSource> dataSource;
#end
#implementation MyCustomView
- (void)drawRect:(CGRect) rect {
if (self.dataSource == nil) {
// no data source, so we don't know what to draw
return;
}
float floatValue = [[self.dataSource ballSizeForMyCustomView:self] floatValue];
// ...
}
#end
In Interface Builder, hook MVCConfusionViewController up to the view's dataSource property. Then implement the protocol:
#interface MVCConfusionViewController : UIViewController <MyCustomViewDataSource> {
[...]
}
[...]
#end
#implementation MVCConfusionViewController
- (NSNumber *)ballSizeForMyCustomView:(MyCustomView *)view {
return self.ballSize;
}
#end
This way your view controller could also be the data source for multiple MyCustomViews, because the protocol method takes a MyCustomView as an argument.
If you need more than one ball, have a look at the UITableViewDataSource and implement similar methods, something like:
-(NSInteger)numberOfBallsInMyCustomView:(MyCustomView *)view;
-(NSNumber *)myCustomView:(MyCustomView *) ballSizeAtIndex:(NSInteger)index;
Your view should already be set in IB, so you can use it as is. If you want to use MyCustomView, you can do it like this:
- (void)viewDidLoad {
[super viewDidLoad];
CGRect frame = CGRectMake(0, 0, 320, 480);
MyCustomView *myView = [[MyCustomView alloc] initWithFrame:frame];
myView.backgroundColor = [UIColor greenColor];
self.view = myView;
[myView release];
CGRect rectangle = CGRectMake(20, 20, 20, 20);
[self.view drawRect:rectangle];
}
I couldn't make your drawing code work, I don't know much about that.
One way to avoid the cast would be to add a separate outlet property for the custom view on the controller, and refer to that instead.
In Interface Builder, make an instance of MyCustomView and drag it into the existing view to make it a subview, then attach it to its own outlet on the controller.