NSInvocation invocationWithMethodSignature, method signature argument cannot be nil - objective-c

I followed tutorial from cocos2d official site . I try to create some items for a menu when creating them i pass a selector with one parameter. For each item i pass different selector . I think here is the problem , but i dont see realy why here is the problem. My header file looks :
// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"
#import "CCTouchDispatcher.h"
// HelloWorldLayer
#interface HelloWorldLayer : CCLayer {
CCSprite *first;
CCSprite *second;
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
- (void) setUpMenus;
- (void) doSomethingOne: (CCMenuItem *) menuItem;
- (void) doSomethingTwo: (CCMenuItem *) menuItem;
- (void) doSomethingThree: (CCMenuItem *) menuItem;
#end
Implementation file :
// Import the interfaces
#import "HelloWorldLayer.h"
// HelloWorldLayer implementation
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
- (void) doSomethingOne: (CCMenuItem *) menuItem
{
NSLog(#"The first menu was called");
}
- (void) doSomethingTwo: (CCMenuItem *) menuItem
{
NSLog(#"The second menu was called");
}
- (void) doSomethingThree: (CCMenuItem *) menuItem
{
NSLog(#"The third menu was called");
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init])) {
first = [CCSprite spriteWithFile:#"seeker.png"];
first.position = ccp(100, 100);
[self addChild:first];
second = [CCSprite spriteWithFile:#"Icon.png"];
second.position = ccp(50, 50);
[self addChild:second];
[self schedule:#selector(nextFrame:)];
[self setUpMenus];
self.isTouchEnabled = YES;
}
return self;
}
- (void) registerWithTouchDispatcher {
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
}
- (BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
return YES;
}
- (void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [self convertTouchToNodeSpace: touch];
[second stopAllActions];
[second runAction: [CCMoveTo actionWithDuration:1 position:location]];
}
- (void) nextFrame:(ccTime)dt {
first.position = ccp( first.position.x + 100*dt, first.position.y );
if (first.position.x > 480+32) {
first.position = ccp( -32, first.position.y );
}
}
- (void) setUpMenus {
CCMenuItemImage *menuItem1 = [CCMenuItemImage itemFromNormalImage:#"myfirstbutton.png"
selectedImage:#"myfirstbutton_selected.png"
target:self
selector:#selector(doSomenthingOne:)];
CCMenuItemImage *menuItem2 = [CCMenuItemImage itemFromNormalImage:#"mysecondbutton.png"
selectedImage:#"mysecondbutton_selected.png"
target:self
selector:#selector(doSomenthingTwo:)];
CCMenuItemImage *menuItem3 = [CCMenuItemImage itemFromNormalImage:#"mythirdbutton.png"
selectedImage:#"mythirdbutton_selected.png"
target:self selector:#selector(doSomenthingThree:)];
CCMenu *myMenu = [CCMenu menuWithItems:menuItem1,menuItem2,menuItem3, nil];
[myMenu alignItemsVertically];
[self addChild:myMenu];
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
#end

You've got the same typo in all three menu item creation calls. You're telling the menu items that the selector they should use is called doSomenthing... (note the spurious n in the middle):
CCMenuItemImage *menuItem1 = [... selector:#selector(doSomenthingOne:)];
CCMenuItemImage *menuItem2 = [... selector:#selector(doSomenthingTwo:)];
CCMenuItemImage *menuItem3 = [... selector:#selector(doSomenthingThree:)];
but the actual names of your methods are doSomethingOne:, doSomethingTwo:, and doSomethingThree:.
The exact cause of the error message is that later, when the menu item needs to perform that selector, it will ask your class to tell it the method signature for the selector you gave it. Since you gave the item an incorrect selector, your class doesn't know the signature, and it returns nil. The menu item tries to construct an NSInvocation object anyways to perform its action, which fails because the invocation can't be created with a nil signature.
Fix the typos and everything should work fine.

Related

CCLayer is null

I am trying to change the color of a CCLayerColor called bgColorLayer, however when I check to see if it is initialized it returns null. I have a color picker that calls the setBGColor: method. I know the colorpicker is calling the method and it is spitting out the correct colors. I am just at a loss as to why the bgColorLayer is null.
This is Cocos2D for Mac.
Any thoughts on why?
In my AppDelegeate method I have an IBOUTLET that is is tied to the NSColorWell
- (IBAction)colorwellBackground:(id)sender {
NSLog(#"Color Well: %#", [sender color]);
// Yes I know the sender color isn’t passing the correct value
AnimationViewerLayer * bkg = [AnimationViewerLayer alloc];
[bkg setBGColor:[sender color]];
}
AnimationViewerLayer.h
#interface AnimationViewerLayer : CCLayer
{
CCLayerColor * bgColorLayer;
}
+ (CCScene *) scene;
#end
AnimationViewLayer.m
#import "AnimationViewerLayer.h"
#implementation AnimationViewerLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
AnimationViewerLayer *layer = [AnimationViewerLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init])) {
float red = 25.0 * 255;
bgColorLayer = [CCLayerColor layerWithColor:ccc4(57, 109, 58, 255)];
[self addChild:bgColorLayer z:1];
}
return self;
}
- (void) setBGColor: (ccColor3B) color{
NSLog(#"SET BG COLOR");
[bgColorLayer setColor:ccRED];
}
- (void) dealloc {
[super dealloc];
}
#end

Array of buttons returning null

I am trying to add the buttons I create to an array and then remove them buttons from the array. My array keeps returning null so I get the feeling my buttons are not even being added to my array?
I am a beginner. I am using Xcode 4.3. Here is my code:
//
// MainViewController.h
// Test-Wards
//
// Created by Dayle Pearson on 5/12/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "FlipsideViewController.h"
#interface MainViewController : UIViewController <FlipsideViewControllerDelegate>
{
/*This stuff creates a timer */
IBOutlet UILabel *opponentsBlue;
NSTimer *timer;
int redBlue;
/*Stuff for making a label creator */
CGPoint startPoint;
int xStuff, yStuff;
/*array for storing wards*/
NSMutableArray *wardArray;
}
#property CGPoint startPoint;
- (IBAction)startRedBlue:(id)sender;
- (IBAction)removeWard:(id)
sender;
- (void)countdown;
#end
//
// MainViewController.m
// Test-Wards
//
// Created by Dayle Pearson on 5/12/12.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "MainViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize startPoint;
- (void)countdown
{
if (redBlue < 2) {
[timer invalidate];
timer = nil;
}
redBlue -= 1;
opponentsBlue.text = [NSString stringWithFormat:#"%i", redBlue];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *theTouch = [touches anyObject];
startPoint = [theTouch locationInView:self.view];
}
- (IBAction)startRedBlue:(id)sender
{
UIButton *wardButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
wardButton.frame = CGRectMake((startPoint.x - 5), (startPoint.y - 5), 10, 10);
[wardButton setTitle:#"180" forState:UIControlStateNormal];
//add targets and actions
/*[wardButton addTarget:self action:#selector() forControlEvents:<#(UIControlEvents)#>*/
//add to a view
[self.view addSubview:wardButton];
[self->wardArray addObject: wardButton];
NSLog(#"This elemnt = %#", wardArray);
}
- (IBAction)removeWard:(id)sender
{
[self->wardArray removeLastObject];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - Flipside View
- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showAlternate"]) {
[[segue destinationViewController] setDelegate:self];
}
}
#end
You forgot to initialize your wardArray. You should add
wardArray = [NSMutableArray array];
to your designated initializer.
In Objective-C sending messages to nil objects is legal - these messages are simply ignored. That's why you do not see the items that you added.
I also noticed that you add buttons to the view, but you never remove them. To remove the buttons from the screen, change the code as follows:
- (IBAction)removeWard:(id)sender
{
[[self->wardArray lastObject] removeFromSuperview];
[self->wardArray removeLastObject];
}
You have to initialize your array before you can add to it
wardArray = [NSMutableArray array]; // quick and easy
wardArray = [[NSMutableArray alloc] init]; // oldschool
I recommend doing it like so in your method. This will only initialize it once if it doesn't exist so theres no chance of it never being ready to have objects :)
- (IBAction)startRedBlue:(id)sender
{
....
// If wardArray doesn't exist we create it. Otherwise we add our ward to it.
if (!wardArray) {
wardArray = [NSMutableArray array];
} else {
[self->wardArray addObject: wardButton];
}
}
- (IBAction)removeWard:(id)sender
{
UIButton *ward = (UIButton *)sender;
[ward removeFromSuperview]; // Takes it off the screen.
[self->wardArray removeObject:ward]; //Takes it out of the array
}

How to fixing bad access error in callback using NSMethodSignature?

I am creating a custom modal layer. the idea is a user see's a city, clicks on said city and accepts or rejects the location.
I use NSMethodSignature to handle the callback so I know whether the user clicked Tick (Accept) or Cross (Reject) buttons in the modal layer.
However, for some reason the app crashes once it invokes the callback and gives me a bad access error when it returns from the modal.
0x000d584e <+0174> mov %eax,0x4(%esp)
0x000d5852 <+0178> call 0xd6006 <dyld_stub_objc_msgSend>
0x000d5857 <+0183> mov -0x8(%ebp),%eax Thread 1: Program received signal: EXC_BAD_ACCESS
I do not understand why this is happening as the city object is defined in the class.
For example, my .h file has:
#interface MapMenuLayer : CCLayer
{
CCArray *listOfCities;
City *city;
}
#property (nonatomic, retain) CCArray *listOfCities;
#property (nonatomic, retain) City *city;
And my .m file has:
#synthesize listOfCities, city;
Later on I define the display each city on the page as clickable CCMenu items. When the user clicks on a city it calls:
-(void) onMenuItem:(id)sender
{
NSLog(#"sender = %d", [sender tag]);
self.city = [self.listOfCities objectAtIndex:[sender tag]];
NSString *cityName = self.city.name;
NSLog(#"cityName = %#", cityName);
// Launch the modal layer
CityModalLayer *cityModalLayer = [[[CityModalLayer alloc] initWithCity:self.city target:self selector:#selector(onDialogButton:)] autorelease];
[cityModalLayer show:self];
}
// This is called when the modal is closed or actioned upon
- (void) onDialogButton:(NSInteger)buttonIndex
{
NSLog(#"onDialogButton:buttonIndex: %d", buttonIndex);
NSString *cityName = self.city.name;
NSLog(#"You selected: cityName = %#", cityName);
}
The bad access error occurs when the application flow returns from the modal layer and launches the onDialogButton method is actioned.
It outputs the log fine, but it crashes when it hits the city object. I have no idea why this is happening, it should not be null or causing any formal error.
Okay, so the modal layer is a bit complex, but I cut it down for the purposes of this question:
-(id) initWithCity:(City *)cityObj target:(id)target selector:(SEL)selector
{
if((self=[super init]))
{
[self initWithColor:ccc4(0, 0, 0, 255)];
[self setOpacity:80];
[self setIsTouchEnabled:YES];
self.city = cityObj;
// Setup the signature class
NSMethodSignature *sig = [[target class] instanceMethodSignatureForSelector:selector];
callback = [NSInvocation invocationWithMethodSignature:sig];
[callback setTarget:target];
[callback setSelector:selector];
[callback retain];
// -----
// MENU
// The frames are not in this code, but they do exist
// Add modal menu
// Modal Menu (Tick/Cross)
CCMenu *modalMenu = [CCMenu menuWithItems:nil];
CCSprite *closeButtonOff = [CCSprite spriteWithSpriteFrameName:#"closeButton_Off.png"];
CCSprite *closeButtonOn = [CCSprite spriteWithSpriteFrameName:#"closeButton_On.png"];
CCSprite *tickButtonOff = [CCSprite spriteWithSpriteFrameName:#"tickButton_Off.png"];
CCSprite *tickButtonOn = [CCSprite spriteWithSpriteFrameName:#"tickButton_On.png"];
// Tick button
CCMenuItemSprite *tickBtnItem = [CCMenuItemSprite itemFromNormalSprite:tickButtonOff selectedSprite:tickButtonOn target:self selector:#selector(onButtonPressed:)];
[tickBtnItem setTag:1];
[tickBtnItem setPosition:CGPointMake(130, -95)];
[tickBtnItem setIsEnabled:YES];
// Close button
CCMenuItemSprite *closeBtnItem = [CCMenuItemSprite itemFromNormalSprite:closeButtonOff selectedSprite:closeButtonOn target:self selector:#selector(onButtonPressed:)];
[closeBtnItem setTag:0];
[closeBtnItem setPosition:CGPointMake(-130, -95)];
[closeBtnItem setIsEnabled:YES];
// Add stuff to modal
[modalMenu addChild:closeBtnItem];
[modalMenu addChild:tickBtnItem];
// Add menu to the modalFrame
[modalFrame addChild:modalMenu z:2];
// --
// Add modalFrame to modalLayer
[self addChild:modalFrame];
} // end if
return self;
}
// This invokes the action
-(void) onButtonPressed:(id) sender
{
NSInteger buttonIndex = [sender tag];
NSLog(#"onButtonPressed: %d", buttonIndex);
[callback setArgument:&buttonIndex atIndex:1];
[callback invoke];
[self removeFromParentAndCleanup:YES];
}
-(void) dealloc
{
[callback release];
[super dealloc];
}
I have tracked the issue down to when the callback is invoked, however I do not understand why it is crashing, or giving me the error. It should still have the city object in memory?
What could be causing this?
I've done it now. It was the autorelease. Which I have removed
In order to prevent clicks under the modal, or someone pressing on a button lots of times really quickly I put a CoverLayer inside my ModalLayer.m file
// class that implements a black colored layer that will cover the whole screen
// and eats all touches except within the dialog box child
#interface CoverLayer : CCLayerColor {
}
#end
#implementation CoverLayer
- (id)init {
self = [super init];
if (self) {
[self initWithColor:ccc4(0,0,0,0)
width:[CCDirector sharedDirector].winSize.width
height:[CCDirector sharedDirector].winSize.height];
self.isTouchEnabled = YES;
}
return self;
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint touchLocation = [self convertTouchToNodeSpace: touch];
CCNode *dialogBox = [self getChildByTag: kDialogTag];
// eat all touches outside of dialog box
return !CGRectContainsPoint(dialogBox.boundingBox, touchLocation);
}
- (void) registerWithTouchDispatcher {
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:INT_MIN+1 swallowsTouches:YES];
}
#end
Then I can init this using my ModalLayer implementation and then dismiss the modal with a small animation, ie,
-(void) onButtonPressed:(id) sender
{
NSInteger buttonIndex = [sender tag];
[callback setArgument:&buttonIndex atIndex:2];
[callback invoke];
id fadeOut = [CCFadeTo actionWithDuration:0.2f opacity:0];
id remove = [CCCallFuncND actionWithTarget:self selector:#selector(removeFromParentAndCleanup:) data:(void*)NO];
[self.coverLayer runAction:
[CCSequence actions:
fadeOut, remove,
nil]];
}
Anyway, I believe I resolved the problem as it seemed to relate to autorelease

How do I use UIPageViewController to load separate XIBs?

I'm delving into the new world of UIPageViewControllers and there are a lot of tutorials out there, however all of them seem to create one view, and then just use new instances of it with different content.
I'd really like to be able to create multiple XIBs and then just chain them together with the UIPageViewController but it's too new and I can't get my head around the way it works.
Well, here's a long answer that you should be able to copy and paste. (This code was adapted from Erica Sadun (https://github.com/erica/iOS-5-Cookbook))
First, create a new class of type UIPageViewController. Call it BookController. Now paste the following code in your .h file.
// Used for storing the most recent book page used
#define DEFAULTS_BOOKPAGE #"BookControllerMostRecentPage"
#protocol BookControllerDelegate <NSObject>
- (id) viewControllerForPage: (int) pageNumber;
#optional
- (void) bookControllerDidTurnToPage: (NSNumber *) pageNumber;
#end
#interface BookController : UIPageViewController <UIPageViewControllerDelegate, UIPageViewControllerDataSource>
+ (id) bookWithDelegate: (id) theDelegate;
+ (id) rotatableViewController;
- (void) moveToPage: (uint) requestedPage;
- (int) currentPage;
#property (assign) id <BookControllerDelegate> bookDelegate;
#property (nonatomic, assign) uint pageNumber;
and in your .m file:
#define IS_IPHONE ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
#define SAFE_ADD(_Array_, _Object_) {if (_Object_ && [_Array_ isKindOfClass:[NSMutableArray class]]) [pageControllers addObject:_Object_];}
#define SAFE_PERFORM_WITH_ARG(THE_OBJECT, THE_SELECTOR, THE_ARG) (([THE_OBJECT respondsToSelector:THE_SELECTOR]) ? [THE_OBJECT performSelector:THE_SELECTOR withObject:THE_ARG] : nil)
#pragma Utility Class - VC that Rotates
#interface RotatableVC : UIViewController
#end
#implementation RotatableVC
- (void) loadView
{
[super loadView];
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
self.view.backgroundColor = [UIColor whiteColor];
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
#end
#pragma Book Controller
#implementation BookController
#synthesize bookDelegate, pageNumber;
#pragma mark Debug / Utility
- (int) currentPage
{
int pageCheck = ((UIViewController *)[self.viewControllers objectAtIndex:0]).view.tag;
return pageCheck;
}
#pragma mark Page Handling
// Update if you'd rather use some other decision style
- (BOOL) useSideBySide: (UIInterfaceOrientation) orientation
{
BOOL isLandscape = UIInterfaceOrientationIsLandscape(orientation);
return isLandscape;
}
// Store the new page and update the delegate
- (void) updatePageTo: (uint) newPageNumber
{
pageNumber = newPageNumber;
[[NSUserDefaults standardUserDefaults] setInteger:pageNumber forKey:DEFAULTS_BOOKPAGE];
[[NSUserDefaults standardUserDefaults] synchronize];
SAFE_PERFORM_WITH_ARG(bookDelegate, #selector(bookControllerDidTurnToPage:), [NSNumber numberWithInt:pageNumber]);
}
// Request controller from delegate
- (UIViewController *) controllerAtPage: (int) aPageNumber
{
if (bookDelegate &&
[bookDelegate respondsToSelector:#selector(viewControllerForPage:)])
{
UIViewController *controller = [bookDelegate viewControllerForPage:aPageNumber];
controller.view.tag = aPageNumber;
return controller;
}
return nil;
}
// Update interface to the given page
- (void) fetchControllersForPage: (uint) requestedPage orientation: (UIInterfaceOrientation) orientation
{
BOOL sideBySide = [self useSideBySide:orientation];
int numberOfPagesNeeded = sideBySide ? 2 : 1;
int currentCount = self.viewControllers.count;
uint leftPage = requestedPage;
if (sideBySide && (leftPage % 2)) leftPage--;
// Only check against current page when count is appropriate
if (currentCount && (currentCount == numberOfPagesNeeded))
{
if (pageNumber == requestedPage) return;
if (pageNumber == leftPage) return;
}
// Decide the prevailing direction by checking the new page against the old
UIPageViewControllerNavigationDirection direction = (requestedPage > pageNumber) ? UIPageViewControllerNavigationDirectionForward : UIPageViewControllerNavigationDirectionReverse;
[self updatePageTo:requestedPage];
// Update the controllers
NSMutableArray *pageControllers = [NSMutableArray array];
SAFE_ADD(pageControllers, [self controllerAtPage:leftPage]);
if (sideBySide)
SAFE_ADD(pageControllers, [self controllerAtPage:leftPage + 1]);
[self setViewControllers:pageControllers direction: direction animated:YES completion:nil];
}
// Entry point for external move request
- (void) moveToPage: (uint) requestedPage
{
[self fetchControllersForPage:requestedPage orientation:(UIInterfaceOrientation)[UIDevice currentDevice].orientation];
}
#pragma mark Data Source
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
[self updatePageTo:pageNumber + 1];
return [self controllerAtPage:(viewController.view.tag + 1)];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
[self updatePageTo:pageNumber - 1];
return [self controllerAtPage:(viewController.view.tag - 1)];
}
#pragma mark Delegate
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
NSUInteger indexOfCurrentViewController = 0;
if (self.viewControllers.count)
indexOfCurrentViewController = ((UIViewController *)[self.viewControllers objectAtIndex:0]).view.tag;
[self fetchControllersForPage:indexOfCurrentViewController orientation:orientation];
BOOL sideBySide = [self useSideBySide:orientation];
self.doubleSided = sideBySide;
UIPageViewControllerSpineLocation spineLocation = sideBySide ? UIPageViewControllerSpineLocationMid : UIPageViewControllerSpineLocationMin;
return spineLocation;
}
-(void)dealloc{
self.bookDelegate = nil;
}
#pragma mark Class utility routines
// Return a UIViewController that knows how to rotate
+ (id) rotatableViewController
{
UIViewController *vc = [[RotatableVC alloc] init];
return vc;
}
// Return a new book
+ (id) bookWithDelegate: (id) theDelegate
{
BookController *bc = [[BookController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
bc.dataSource = bc;
bc.delegate = bc;
bc.bookDelegate = theDelegate;
return bc;
}
This Class can now be used to control any book you create in any project, and for multiple books in a single project. For each book, create a delegate UIPageViewController with the #interface:
#interface NameOfBookController : UIPageViewController <BookControllerDelegate>
In the .m file of this delegate, include:
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView
{
[super loadView];
CGRect appRect = [[UIScreen mainScreen] applicationFrame];
self.view = [[UIView alloc] initWithFrame: appRect];
self.view.backgroundColor = [UIColor whiteColor];
self.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
// Establish the page view controller
bookController = [BookController bookWithDelegate:self];
bookController.view.frame = (CGRect){.size = appRect.size};
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
// Add the child controller, and set it to the first page
[self.view addSubview:bookController.view];
[self addChildViewController:bookController];
[bookController didMoveToParentViewController:self];
}
Then add:
- (id) viewControllerForPage: (int) pageNumber
{
// Establish a new controller
UIViewController *controller;
switch (pageNumber) {
case 0:
view1 = [[FirstViewController alloc] init];
view1.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
controller = view1;
//rinse and repeat with each new view controller
break;
case 1:
//etc.
break;
default:
return nil;
break;
}
return controller;
}
For the record, this code is not memory-safe. If using ARC, add in your #autoreleasePool{}; if not, don't forget your retain/release cycle.
I hope this helps!
This article shows how to create an app using UIPageViewController with custom viewcontrollers for each page: http://www.informit.com/articles/article.aspx?p=1760500&seqNum=6

CCSprite not rendering when made in a method from an external class

I'm sure this is really obvious to someone, but this simple thing is really frustrating me.
I have a class I made called Class_Sprite, which is a sub-class of CCSprite.
I have a method in this class that is supposed to both create the texture for any given instance of Class_Sprite, and then move it to (200,200).
The program runs in the sim but all I get is a black screen.
I was able to render the sprite directly from the layer class.
Here are the files.
Class_Sprite:
#import "Class_Sprite.h"
#implementation Class_Sprite
-(id)init
{
if ((self = [super init]))
{
}
return self;
}
-(void)make:(id)sender
{
sender = [Class_Sprite spriteWithFile:#"Icon.png"];
[sender setPosition: ccp(200, 200)];
}
#end
Class Sprite header:
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface Class_Sprite : CCSprite {
}
-(void)make:(id)sender;
#end
HelloWorldLayer.m (where the method is being called)
#implementation HelloWorldLayer
+(CCScene *) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
HelloWorldLayer *layer = [HelloWorldLayer node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self = [super init])) {
Class_Sprite *pc = [[Class_Sprite alloc] init];
[pc make:self]; //here is where I call the "make" method
[self addChild:pc];
[pc release];
}
return self;
}
// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
// in case you have something to dealloc, do it in this method
// in this particular example nothing needs to be released.
// cocos2d will automatically release all the children (Label)
// don't forget to call "super dealloc"
[super dealloc];
}
#end
And finally the header file for HelloWorldLayer
#import "cocos2d.h"
#import "Class_Sprite.h"
// HelloWorldLayer
#interface HelloWorldLayer : CCLayer
{
}
// returns a CCScene that contains the HelloWorldLayer as the only child
+(CCScene *) scene;
#end
Thanks for your time
Try changing to this in Class_Sprite.m:
#implementation Class_Sprite
-(id)init
{
if ((self = [super initWithFile:#"Icon.png"]))
{
}
return self;
}
-(void)make:(CCNode *)sender
{
[self setPosition: ccp(200, 200)];
[sender addChild:self];
}
#end
And use it in HelloWorldLayer as follows:
Class_Sprite *pc = [[Class_Sprite alloc] init];
[pc make:self];
[pc release];