I don't know if it's some setting I accidentally ticked, but tell me how to fix it please:
Whenever I create a new Obj-C class, it automatically looks like:
#import <Foundation/Foundation.h>
#interface MathUtilities : NSObject {
**#private**
}
#end
That line is automatically inserted. It never was there before, but something is not adding it. My files also now come with init and dealloc methods. Did something happen? Also, shouldn't it be importing Cocoa instead of Foundation?
This is XCode 4
There is nothing to fix. XCode is creating stubs for you to fill out your code into. It's a time saver, thats all. It should be generating a header and implementation stub file for you, which you can extend like so:
Your header file (MathUtilities.h):
#import <Foundation/Foundation.h>
#interface MathUtilities : NSObject {
#private:
NSNumber * num;
}
- (void) doSomeWork;
#end
Your implementation file (MathUtilities.m) :
#import "MathUtilities.h"
#implementation MathUtilities
- (id) init {
self = [super init];
if(self) {
// Initialization code here.
}
return self;
}
- (void) dealloc {
[super dealloc];
}
- (void) doSomeWork {
return;
}
#end
Related
My name is Bob. I code for the Parks Department of NYC. I'm starting to learn Objective C and have a "Semantic Issue." I must have a blind spot, because I checked all the following code and don't see the problem. Thank you for ant help you can give
"No visible #interface for 'Greeter' declares the selector 'setGreetingText::"
#import <Foundation/Foundation.h>
#import "Greeter.h"
int main (int argc, const char * argv[])
{
#autoreleasepool {
Greeter* myGreeter = [[Greeter alloc] init];
// error on this line
[myGreeter setGreetingText: #"Hello Objective-C!!" : #"Hello VIP Objective-C!!"];
[myGreeter issueGreeting];
}
return 0;
}
======================================
import "Greeter.h"
import "NewGreeter.h"
#implementation Greeter
NewGreeter *VTS;
- (NSString*) greetingText
{
return [self greetingText];
}
- (void) setGreetingText:(NSString*) newText01
andThisToo:(NSString*) newText02
{
greetingText = newText01;
[VTS setNewGreetingText: newText02];
}
- (void) issueGreeting
{
NSLog(#"%#", greetingText);
}
#import "NewGreeter.h"
#implementation NewGreeter
- (NSString*) NewGreetingText
{
return greeting;
}
- (void) setNewGreetingText:(NSString*) newText
{
greeting = newText;
}
- (void) issueNewGreeting
{
NSLog(#"%#", [self NewGreetingText]);
}
#end
#import <Foundation/Foundation.h>
#import "NewGreeter.h"
#interface Greeter : NSObject
{
NSString *greetingText;
}
- (void) setGreetingText:(NSString*) newText01
andThisToo:(NSString*) newText02;
- (NSString*) greetingText;
- (void) setGreetingText:(NSString*) newText;
- (void) issueGreeting;
#import <Foundation/Foundation.h>
#interface NewGreeter : NSObject
{
NSString *greetingText;
}
- (NSString*) NewGreetingText;
- (void) setNewGreetingText:(NSString*) newText;
- (void) issueNewGreeting;
#end
#import <Foundation/Foundation.h>
#interface NewGreeter : NSObject
{
NSString *greetingText;
}
- (NSString*) NewGreetingText;
- (void) setNewGreetingText:(NSString*) newText;
- (void) issueNewGreeting;
#end
You implement the method named -setGreetingText:andThisToo:, but you're trying to use it incorrectly. You need to change your call to:
[myGreeter setGreetingText: #"Hello Objective-C!!" andThisToo:#"Hello VIP Objective-C!!"];
Notice the andThisToo bit.
If you're only trying to set your object's properties, then you don't need to expose custom methods for that. Instead, you could do:
// In Greeter.h
#interface Greeter: NSObject
#property NSString *greetingText;
#end
// In Greeter.m
#implementation Greeter
#synthesize greetingText = _greetingText; // Create a backing instance variable
#end
This creates an instance variable setter method named setGreetingText and an instance variable getter named greetingText. I'd recommend you read up on creating object properties.
Im toying around with SwipeGestureRecognizer.
It´s working as I expect, but when I exit the app in the simulator and run it again, the SwipeGestureRecognizer no longer responds. If i run it again after quitting iOS simulator, it works.
This is what I have tried:
#import <UIKit/UIKit.h>
#interface swipeTestUI : UIViewController
#property (strong, nonatomic) IBOutlet UIImageView *imageView;
- (IBAction)mangeSwipeControl:(UIGestureRecognizer*)sender;
#end
Implementation file:
#import "swipeTestUI.h"
#interface swipeTestUI ()
#end
#implementation swipeTestUI
#synthesize imageView;
int listOfImages = 0;
- (IBAction)mangeSwipeControl:(UIGestureRecognizer *)sender {
NSLog(#"swipe ok");
NSArray *images=[[NSArray alloc]initWithObjects:
#"1.png",
#"2.png",
#"3.png",
#"4.png",
#"5.png",
#"5.png",nil];
UISwipeGestureRecognizerDirection direction = [(UISwipeGestureRecognizer *) sender direction];
switch (direction) {
case UISwipeGestureRecognizerDirectionLeft:
listOfImages++;
break;
case UISwipeGestureRecognizerDirectionRight:
listOfImages--;
break;
default:
break;
}
listOfImages = (listOfImages < 0) ? ([images count] -1):listOfImages % [images count];
imageView.image = [UIImage imageNamed:[images objectAtIndex:listOfImages]];
}
- (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.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
I think this is an iOS simulator issue. I have modified the code a bit, I think its more effective
the header file is the same, the implementation file is as followed.
-(IBAction)manageSwipeControl:(UISwipeGestureRecognizer *)gesture {
NSArray *images=[[NSArray alloc]initWithObjects:
#"1.png",
#"2.png",
#"3.png",
#"4.png",
#"5.png",
#"6.png",nil];
if (gesture.direction == UISwipeGestureRecognizerDirectionLeft)
{
listOfImages++;
}
else if (gesture.direction == UISwipeGestureRecognizerDirectionRight)
{
listOfImages--;
}
listOfImages = (listOfImages < 0) ? ([images count] -1):listOfImages % [images count];
imageView.image = [UIImage imageNamed:[images objectAtIndex:listOfImages]];
//[self.imageView removeGestureRecognizer:sender];
}
Works like a charm. Funny thing. When I quit the application in the iOS simulator, and reopen it. It still works. If I quit and remove it from iOS simulator memory - it does not. If I launch the iOS simulator directly from the OS, no problem what so ever. I can both quit and remove it from memory, and it still works.
Still, a fun way to spend on a rainy weekend. Hope this info is useful to other new developers like myself.
Silly question. Cocos2d is build around the parent-child hierarchy. I was wondering if it is ok to have a parent class (e.g. GameScene) and initialize a child class (e.g. SpriteHandler) with a pointer to a member of the parent class (e.g. CCSpriteBatchNode*).
I am trying to do this to optimize the number of CCSpriteBatchNodes. Here is a code snippet of my main class (GameScene style).
#import <Foundation/Foundation.h>
#import "cocos2d.h"
enum ShooterSceneLayerTags {
HudLayerTag = 0,
};
#interface ShooterScene : CCLayer {
CCSpriteBatchNode* sharedSpriteBatchNode;
}
-(id) initWithSharedBatchNodeReference:( CCSpriteBatchNode*) sharedSpriteBatchNode;
+ (id) sceneWithId:(int)sceneId;
#end
#import "ShooterScene.h"
#import "MainMenuScene.h"
//Layers
#import "LevelSpritesLayer.h"
#import "HudLayer.h"
#interface ShooterScene (PrivateMethods)
-(void) addLayers:(int)sceneId;
-(void) loadGameArtFile;
-(BOOL) verifyAndHandlePause;
#end
#implementation ShooterScene
+ (id) sceneWithId:(int)sceneId
{
CCScene *scene = [CCScene node];
ShooterScene * shooterLayer = [[self alloc] initWithId:sceneId];
[scene addChild:shooterLayer];
return scene;
}
-(id) initWithId:(int)sceneId
{
if ((self = [super init]))
{
//Load game art before adding layers - This will initialize the batch node
[self loadGameArtFile:sceneId];
//Will add sprites to shared batch node for performance
[self addLayers:sceneId];
[self addChild:sharedSpriteBatchNode];
//Do other stuff..
[self scheduleUpdate];
}
return self;
}
-(void) addLayers:(int)sceneId
{
LevelSpritesLayer * levelData = [LevelSpritesLayer node];
[levelData initWithSharedBatchNodeReference:sharedSpriteBatchNode];
[self addChild:levelData];
switch (sceneId) {
case 1:
[levelData loadLevelOneSprites];
break;
case 2:
[levelData loadLevelTwoSprites];
break;
default:
break;
}
HudLayer * hud = [HudLayer node];
[hud setUpPauseMenu];
[self addChild:hud z:1 tag:HudLayerTag];
}
-(BOOL) verifyAndHandlePause
{
HudLayer * hud = [self getChildByTag:HudLayerTag];
if(hud.pauseRequested){
[[CCDirector sharedDirector] replaceScene:[MainMenuScene scene]];
return true;
}
else {
return false;
}
}
-(void) update:(ccTime)delta
{
if([self verifyAndHandlePause]==false)
{
//Continue with animation etc..
}
}
/**
This is tricky. Could have loaded this in LevelData but as I am expecting to use the same SpriteSheet for HudLayer as well then
I prefer to have the control here of this. Also, the same sheet could be used for more level, hence specific function is not bad
**/
-(void) loadGameArtFile:(int) sceneId
{
CCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"game-art-hd.plist"];
sharedSpriteBatchNode = [CCSpriteBatchNode batchNodeWithFile:#"game-art-hd.png"];
}
//As dealloc is deprecated, I prefer to remove unused sprites and texture on cleanup
-(void) cleanup
{
[[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
}
And here is one of the loadLevelData methods, it uses the sharedSpriteBAtchNodeReference
-(void) loadLevelOneSprites
{
//Just a proof of concept example
testSprite = [CCSprite spriteWithSpriteFrameName:#"File0.png"];
testSprite.anchorPoint = CGPointMake(0.5f, 0.5f);
testSprite.position = CGPointMake(160.0f, 240.0f);
[sharedSpriteBatchNodeReference addChild:testSprite];
}
You can do that but if you are using ARC you should make your sharedSpriteBatchNode a weak pointer. If you don't you could end up with a circular reference.
What will happen with the circular reference is when the Director releases your game scene after it has finished running your game scene will still have your child retaining it and your game scene will still be retaining that child. This circle will float off and never be able to be released as it is abandoned.
What [Ben] said. It should not be a retaining or strong reference, the latter being the default in ARC for instance variables.
There is one way to ensure under ARC that you're retain-cycle-safe even if you use a strong reference. Override the cleanup method and nil the reference there (under MRC you should also call release here, if you retained the reference):
-(void) cleanup
{
sharedSpriteBatchNode = nil;
[super cleanup];
}
Doing this in dealloc won't work. As long as a child node has a strong reference to a parent, it will not be deallocated. So you need to do this in cleanup, and ensure that all method calls where you can set the cleanup flag has that parameter set to YES.
But there are other, and I think better, solutions than passing a parent node in the initializer. For example you could get the shared batch node via a common tag from the parent, and either do that every time you need it (wrap it into a small function) or store it in a weak (non-retaining) instance var:
// onEnter is typically called right after init (during addChild)
// parent is already set here
-(void) onEnter
{
[super onEnter];
CCSpriteBatchNode* sharedBatchNode = [parent getChildByTag:kSharedBatchNodeTag];
}
Or get the parent and cast it, assuming the sharedBatchNode to be a property of the parent class:
-(void) whereEver
{
ShooterScene* scene = (ShooterScene*)parent;
CCSpriteBatchNode* sharedBatchNode = scene.sharedSpriteBatchNode;
…
// you can also reduce the above to a single line:
CCSpriteBatchNode* batch = ((ShooterScene*)parent).sharedSpriteBatchNode;
}
Especially this latter solution is recommended. Even if you need to do that often it's fast. Casting is free, property access no more than a message send. Just be sure that the parent is in fact an object of the class you're casting it to.
Am writing a simple multi view application with one root controller and two view controllers (blue and yellow). When I try to run it in the iPhone Simulator, I get an error by the #synthesize property. I have commented out the error on that line.
Can you tell me what the error means, and how can I get the app to run?
Thank you.
#import "SwitchViewController.h"
#import "BlueViewController.h"
#import "YellowViewController.h"
#interface SwitchViewController ()
#end
#implementation SwitchViewController
#synthesize yellowViewController;
#synthesize blueViewController; //Thread 1:EXC_BAD_ACCESS(code=2, address=0xbf7ffffc)
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)loadView
{
// If you create your views manually, you MUST override this method and use it to create your views.
// If you use Interface Builder to create your views, then you must NOT override this method.
}
- (void)viewDidLoad
{
self.blueViewController = [[BlueViewController alloc]initWithNibName:#"BlueView" bundle:nil];
[self.view insertSubview:self.blueViewController.view atIndex:0];
[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 == UIInterfaceOrientationPortrait);
}
- (IBAction)switchViews:(id)sender
{
if(self.yellowViewController.view.superview==nil) {
if(self.yellowViewController==nil) {
self.yellowViewController =
[[YellowViewController alloc] initWithNibName:#"YellowView" bundle:nil];
}
[blueViewController.view removeFromSuperview];
[self.view insertSubview:self.yellowViewController.view atIndex:0];
} else {
if (self.blueViewController == nil) {
self.blueViewController =
[[BlueViewController alloc] initWithNibName:#"BlueView" bundle:nil];
}
}
}
- (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
if (self.blueViewController.view.superview == nil) {
self.blueViewController = nil;
} else {
self.yellowViewController = nil;
}
}
#end
Comment out the loadView method in your SwitchViewController, BlueViewController, and YellowViewController. The empty application template was changed to leave these uncommented in recent versions of XCode, but the Beginning iOS Development book you are following used an older version with the stubbed methods pre-commented.
I'm still on a learning curve with Obj-c.
I'm trying to override the setColumnCount method in the TTThumbsTableViewCell from Three20,
but I don't know why It wont work.
In the method setColumnCount from the super class (TTThumbsTableViewCell) I've added a NSLog(#"Test Super") and the subclass of TTThumbsTableViewCell in setColumnCount method I've add NSLog(#"Test Sub") and the subclass method never prints out "Test Sub".
I'm not sure if I'm overriding correctly in Obj-C, basically I copy the whole method setColumnCount from TTThumbsTableViewCell to the subClass and modify it there, but it still doesn't run the overridden method in the subclass.
Is there something I'm missing?
Im working with XCode 4
Thanks in advance
Brett
South Africa
I have a TTThumbsTableViewCell subClass called GridImage
#interface GridImage : TTThumbsTableViewCell '<'TTPhoto>{
//Code...
#end
The .m override's the setColumnCount method
'#'import "GridImage.h"
#implementation GridImage
(void)setColumnCount:(NSInteger)columnCount {
NSLog(#"Test Sub");
if (_columnCount != columnCount) {
for (TTThumbView* thumbView in _thumbViews) {
[thumbView removeFromSuperview];
}
[_thumbViews removeAllObjects];
_columnCount = columnCount;
for (NSInteger i = _thumbViews.count; i < _columnCount; ++i) {
TTThumbView* thumbView = [[[TTThumbView alloc] init] autorelease];
[thumbView addTarget:self action:#selector(thumbTouched:)
forControlEvents:UIControlEventTouchUpInside];
[self.contentView addSubview:thumbView];
[_thumbViews addObject:thumbView];
if (_photo) {
[self assignPhotoAtIndex:_photo.index+i toView:thumbView];
}
}
}
}
Could it be something to do with the '<'TTPhoto> protocol from Three20?