Request for member in something not a structure or union - cocos2d-iphone

I'm trying to do some saving/loading in my AppDelegate, for which I need my enemy and hero sprites. I'm using cocos2d. Here's the method that's getting the warning.
-(void)applicationDidFinishLaunchingWithOptions:(UIApplication *)application {
NSMutableArray *loadedMoles = [DataBase loadDocs];
NSMutableArray *loadedBunnies = [DataBase loadDocs];
UINavigationController *navigationController;
viewController = (RootViewController *) [navigationController.viewControllers objectAtIndex:0];
viewController.mole = loadedMoles; //error
viewController.bunny = loadedBunnies; //error
}
Even though this is the AppDelegate, I've imported both classes, and I'm still getting the errors.

Relevant portion of comments
Jonathan
Given that the problem is not just . vs ->, the other main option, then, is that your viewController does contain any moles or bunnies.
Joe
I'm using the tutorial at http://www.raywenderlich.com/1914/how-to-save-your-app-data-with-nscoding-and-nsfilemanager. (There is code there to download.)
Doing:
viewController->mole = loadedMoles;
says
'struct RootViewController' has no member named 'mole'
How do I add it to viewController?
Although in the tutorial they use
NSMutableArray *loadedBugs = [ScaryBugDatabase loadScaryBugDocs];
RootViewController *rootController = (RootViewController *)
[navigationController.viewControllers objectAtIndex:0];
rootController.bugs = loadedBugs;
Jonathan
In the downloaded code (ScaryBugs3/Classes/rootViewController.h), the demo has:
#class EditBugViewController;
#interface RootViewController : UITableViewController {
NSMutableArray *_bugs;
EditBugViewController *_editBugViewController;
}
#property (retain) NSMutableArray *bugs;
#property (retain) EditBugViewController *editBugViewController;
#end
Does your equivalent have 'mole' and 'bunny' properly defined? If so, I'm at a loss to help you much further.
Joe
I never downloaded the source code, so I didn't see any of that. Thanks, I was wondering if he might have bugs as an array instead of a bug sprite.
Not very relevant portion of answer
In regular C or C++ with GCC, the error message normally occurs when either:
You use structptr->member and you should use structvar.member, or
You use structvar.member and you should use structptr->member.
Objective-C is close enough to C at this juncture that you probably need to review your use of . vs -> notation, I believe.
Now that your code is legible, the lines giving the error are:
viewController.mole = loadedMoles; //error
viewController.bunny = loadedBunnies; //error
You probably need to use viewController->mole and viewController->bunny instead? (I'm not sure of that, but to the extent Objective-C is a superset of C, that would be a necessary change. However, it could be that Objective-C does away with the need to distinguish between . and ->.)

At the link you gave is used RootViewController class and you are trying to use UINavigationController that simply does not have such properties as mole and bunny as #Jonathan said

I also had the error 'Request for member "options" in something not a structure or union' come up.
#interface Dialog : NSManagedObject {}
#property (nonatomic, retain) NSSet* options;
#implementation Dialog
#dynamic options;
Where I simply forgot to import "Dialog.h" in the class that was trying to access this instance.

Related

Storing NSTimer instance inside C++ wrapper

In an ARC enabled project I am trying to store an allocated NSTimer inside a C++ wrapper (the NSTimer instance is not initialized):
#ifndef Wrapper_h
#define Wrapper_h
class Wrapper {
public:
Wrapper(id data): data_(data) { }
private:
id data_;
};
#endif /* Wrapper_h */
and the code in question:
-(void)test {
id timer = [NSTimer alloc];
Wrapper* w = new Wrapper(timer); // <-- BAD_ACCESS
}
My end goal is to extend the lifetime of the local id variable with the lifetime of the wrapper (later the wrapper pointer will be stored inside another global variable). Of course when the wrapper is deleted I would like the timer reference count to be decreased to 0.
Here's the stacktrace which looks like a recursive call to retain (stackoverflow):
Trying to bridge retain the timer also crashes:
-(void)test {
id timer = [NSTimer alloc];
CFTypeRef retained = (__bridge_retained CFTypeRef)timer; // <-- BAD_ACCESS
}
Trying to create an std::unique_ptr also will crash:
-(void)test {
id timer = [NSTimer alloc];
std::unique_ptr<id> ptr = std::make_unique<id>(timer); // <-- BAD_ACCESS
}
The code works if I initialize the NSTimer instance:
-(void)test {
id timer = [[NSTimer alloc] init];
Wrapper* w = new Wrapper(timer); // <-- OK
}
I also noticed that other Objective-C types work (such as NSObject, NSString, NSDictionary, NSArray, ...):
-(void)test {
id timer = [NSObject alloc];
Wrapper* w = new Wrapper(timer); // <-- OK
}
So what is special about NSTimer and what would be the proper way to store such instance inside my C++ wrapper? Are there any other examples such as NSTimer that would exhibit similar behaviour?
And a very important detail: this code only crashes iOS 10 (iOS > 10 works fine).
One of golden rule in software development is to follow contracts. For this particular case API states never initialize an object without reassigning any pointer to that object:
Note: It’s possible for init to return a different object than was created by alloc, so it’s best practice to nest the calls as shown.
Never initialize an object without reassigning any pointer to that object. As an example, don’t do this:
NSObject *someObject = [NSObject alloc];
[someObject init];
If the call to init returns some other object, you’ll be left with a pointer to the object that was originally allocated but never initialized.
I should admit though that it doesn't prohibit storing instance returned by the alloc method elsewhere, but Objective-C peculiarities make any use of such instances (apart from initialization) extremely error prone.
First, treat whatever you get from alloc and init... family of methods two different instances to be safe. That comes down to the fact that you have a possibility to return completely different object (even of different class) from an Objective-C constructor. It's one of the reasons why you see expression like self = [super init] (and not just [super init]) in subclassing documentation.
Second, Foundation framework uses Class Cluster design pattern heavily. It's the worst scenario of the previous point and the vast majority of the framework classes are abstract interfaces which hide the actual concrete classes returned by constructors (and even by the alloc method itself).
Thus storing instances returned by alloc essentially means storing abstract factories and it doesn't meet requirements you set for your wrapper (extending lifetime of local variables). Instead you want to keep instances of concrete classes, so wrap instances returned from constructors.
You already found that [[NSTimer alloc] init] doesn't make the code crash but it doesn't look quite correct to me either because the class API doesn't offer argument-less constructor, (it's impossible to get rid of default init from base NSObject in Objective-C, so you need to refer to API documentation to ensure what set of instance initialization is actually available).
What is special about NSTimer?
As i mentioned above Foundation framework classes are all special. And every class is special in its particular way. It's hard to say what exactly is different for NSTimer, however when passing Objective-C instance to a C++ function it follows the same rules, and ARC adds retain/release boilerplate for us, so we can inspect these variables from this standpoint.
I also noticed that other Objective-C types work (such as NSObject,
NSString, NSDictionary, NSArray, ...)
Here is a function which has variables of the given classes:
- (void) listVariables {
NSObject *allocObject = [NSObject alloc];
NSObject *initObject = [allocObject init];
NSString *allocString = [NSString alloc];
NSString *initString = [allocString init];
NSArray *allocArray = [NSArray alloc];
NSArray *initArray = [allocArray init];
NSDictionary *allocDictionary = [NSDictionary alloc];
NSDictionary *initDictionary = [allocDictionary init];
NSTimer *allocTimer = [NSTimer alloc];
NSTimer *initTimer = [allocTimer init];
NSTimer *properlyInitTimer = [allocTimer initWithFireDate:[NSDate date] interval:10 repeats:YES block:nil];
return;
}
Let's see what lldb debugger can reveal when stopped at the line with return expression:
(lldb) frame variable
...
(NSObject *) allocObject = 0x00006000025a0070
(NSObject *) initObject = 0x00006000025a0070
(NSPlaceholderString *) allocString = 0x00007fff801d75e8 class name = NSPlaceholderString
(__NSCFConstantString *) initString = 0x00007fff801dcfa0 ""
(__NSPlaceholderArray *) allocArray = 0x00007fff80198af0
(__NSArray0 *) initArray = 0x00007fff8002e970 0 elements
(__NSPlaceholderDictionary *) allocDictionary = 0x00007fff801a6a40
(__NSDictionary0 *) initDictionary = 0x00007fff8019fb60 0 key/value pairs
(NSCFTimer *) allocTimer = 0x00006000025a02f0
(NSTimer *) initTimer = nil
(__NSCFTimer *) properlyInitTimer = 0x00006000012a8180
Here you can see what these variables are turned into under the hood. This are private classes of course and they may change in future release but i would not expect drastic changes. The most simple is NSObject, an instance returned from alloc matches the instance returned from a constructor (this is part of API description, btw, so i would expect the same transparency for this project in all releases). If i print retain count for this instance, it gives pretty much expected value:
(lldb) po [allocObject retainCount]
2
(lldb) po [initObject retainCount]
2
If i print retainCount value for any of NSString, NSArray or NSDictionary variables in this frame, they all are equal to 2^64-1.
(lldb) po [initString retainCount]
18446744073709551615
Such a huge value essentially means that this instance is a singleton object. Such objects have release and retain methods overridden in a way that it doesn't affect their referenceCount and they exist within entire application life. That is a special kind of optimization for these objects.
From frame command output we can see that initTimer is nil and it doesn't make much sense to check its retain count or how retain works with it - this is a null object. If i print retainCount for the properlyInitTimer, it's quite straightforward:
(lldb) po [properlyInitTimer retainCount]
1
If i do the same for the allocTimer variable the result is kind of unexpected. The debugger gets frozen and entire process starts consuming 100% of CPU. My best bet it could be the reason behind the BAD_ACCESS error. (some kind of Reference Counting suppression introduced as part of the NSTimer abstract factory instance so it could not be removed) and Apple just made it less harmful in latest releases, after iOS 10, but of course i cannot know what exactly is there. (you can freely use retain and release methods on this instance but it apparently cannot be destroyed)

(iOS) How can I get the UIViewController from a C++ Application?

I need to use a library in my C++ project that needs to call an extern function:
SetGameViewController(UIViewController* gameViewController)
I have zero knowledge of Objective C and iOS yet. I need to get UIViewController and pass it to that function.
So this code should get the UIViewController:
UIWindow *window = [UIApplication sharedApplication].keyWindow;
UIViewController *rootViewController = window.rootViewController;
I also added this import:
#if defined(OS_IPHONE)
#import <UIKit/UIKit.h>
#endif
I get compiler errors like:
Expected unqualified-id
Unknown type name 'NSString'
I've started learning Objective C and read a few articles but couldn't get much further than that yet.
So basically my question is how do I basically import and use Objective C code in C++ code so that I can get and use the UIViewController?
Easiest way will be to rename your source file with the extension ".mm" - it will then be compiled as objective-c++, which means you get all the wonders of c++ while still being able to interact with objective-c objects (counted pointers to things 'derived' from NSObject).

Xcode: Impossible to use c++ with Scenekit?

I'm a beginner with Xcode...
I'm trying to use openCV c++ with Scenekit=> to make an AR scene.
Well, I was too optimistic.
1/I started to use the default XCode template for game.=> works!
2/openCV without scenekit=> works
3/ mixing...
I imported some c++ headers in the gameviewController file (basically a UIViewController with scenekit inside).
If I let it so, I get compiler error (cstddef not defined). Fair enough, it's C++ so, from what I read, I just have to rename .m to .mm
But, in this case, I get a full list of linker errors such as Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_SCNAction", referenced from:
=> I guess it is more tricky to mix objective C and C++ but on a simpler project, without Scenekit but with a very similar code otherwise, it worked nicely.
Any clue or guide for mixing them? Should I use swift?
Thanks a lot,
Michael
I just need to add "SceneKit.framework" to Link Binary With Libraries:
Same problem here. I had a pure Objective-C class, simply named "GameViewController.m". To turn it into an Obj-C++ class, change the ".m" to ".mm".
However, just by changing the extension, the linker spat back 13 undefined symbols....
"_OBJC_CLASS_$_SCNTransaction", referenced from: ...
"_OBJC_CLASS_$_SCNFloor", referenced from: ...
"_OBJC_CLASS_$_SCNMaterial", referenced from: ...
etc...
To get around this, just create a different (new) Obj-C++ class, with a .mm extension, and place your C++ code in that class.
Now you can instantiate that new class from the class containing SceneKit calls and call the methods in the new Obj-C++ class.
Inside the GameViewcontroller.m class:
...
scene = [SCNScene sceneNamed:#"art.scnassets/grid.dae"];
kinematics = [[KinematicScene alloc] init];
[kinematics setupCharacters];
...
And inside the new Obj-C++ class (KinematicsScene.mm)
#implementation KinematicScene
{
AI::Location *location;
}
-(id) init
{
self = [super init];
if( self )
{
AI::KinematicSeek* seek = new AI::KinematicSeek[2];
location = new AI::Location[2];
}
return self;
}
-(void) setupCharacters
{
.....
}
... etc ....
#end
This worked for me:
Disable module support [CLANG_ENABLE_MODULES, -fmodules]. This has user experience downsides. Read the online help for this setting before disabling it, and also be aware that if you disable it you will become responsible for hunting down the libraries and frameworks you need to link against, and this can be tedious if you are not an old hand.
Build and (attempt to) link. Add the frameworks and libraries you need to resolve the link errors. I recommend creating a group in your project and directing it to your SDK, then adding the frameworks and libraries relative to that SDK.

Problems with implementing QRCodeReader (ZXing)

So I've followed the steps mentioned here: http://zxing.googlecode.com/svn/trunk/iphone/README
And I made sure everything is alright but yet my QRCodeReader isn't being recognized in myVC.mm file.
This is what's the situation:
The project is put into my own project as described in the link.
I've imported the #import "ZXingWidgetController.h" in the header file and it is being recognized.
I've imported the #import "QRCodeReader.h" in the implementation file (.mm)
Then I alloced them both in a targetmethod of some button like this:
ZXingWidgetController *widController = [[ZXingWidgetController alloc] initWithDelegate:self showCancel:YES OneDMode:NO];
widController.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"qr_code_initialising_bg.png"]];
QRCodeReader* qrcodeReader = [[QRCodeReader alloc] init];
NSSet *readers = [[NSSet alloc ] initWithObjects:qrcodeReader,nil];
[qrcodeReader release];
widController.readers = readers;
[readers release];
[self presentModalViewController:widController animated:YES];
Now it tells me that this is the problem:
QRCodeReader* qrcodeReader = [[QRCodeReader alloc] init];
NSSet *readers = [[NSSet alloc ] initWithObjects:qrcodeReader,nil];
[qrcodeReader release];
It says: Use of undeclared identifier 'QRCodeReader'
Why does it not see my import of the QRCodeReader in the seem .mm
file?
What did I forget that is not in the description that I used?
And most important, how do I fix this to recognize the QRCodeReader?
The straight C++ code (not Objective C++) uses C++ namespaces.
You need to either say zxing::qrcode::QRCodeReader or use using statements like
using namespace zxing;
using namespace zxing::qrcode;
Update:
The code above does bring in the C++ class but there's actually a widget class of the same name which I forgot about. It is an Objective C class that wraps the C++ class and is what you want. Instead of the code above, just #import "QRCodeReader.h" ... which you said you did. I expect the two files of the same name are colliding. Did you set the "recursive" option when including the cpp files? The README says "don't need to" but should probably say "must not". That could cause the cpp file to be included and not the widget version.
I had this exact same problem at the end the solution was kind of easy.
I put the .mm file with "Location" -> "Relative to Project".
Hope this help

Openfeint caused this: ISO C++ forbids of declaration 'myClass' with no type

To cut a long story short, my project (an iPhone app) was all working fine until I started using a C++ sdk (openfeint). Everything was working fine, including the C+++ Openfeint stuff, until I switched from tesitng on the device to testing in the simulator.
Now it won't compile for anything and I'm getting just under 200 errors. It's all just spiralled out of control and wont compile on any device. As I said, everything was working perfectly, I didn't change a single line of code, I simply switched Active SDK's.
So I'll start at the beginning. The first error is...
Error 1: ISO C++ forbids of declaration 'BrickControlLayer' with no type
Clicking on this error takes me to the header file for another class...
// GameScene.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "brickSprite.h"
#import "BrickControlLayer.h"
#import "GameState.h"
#import "ScoreController.h"
#import "FeedbackLayer.h"
#import "TimeBar.h"
#interface GameScene : Layer {
GameState *gameState;
ScoreController *scoreController;
CocosNode *spriteHolder;
brickSprite *targetBrick;
// Heres the line it takes me too <<<<<<<<<<<<<<<<<
BrickControlLayer *controls;
NSInteger difficulty;
NSMutableArray *pointsLookupArray;
BitmapFontAtlas *scoreLabel;
FeedbackLayer *feedback;
NSDate *startTime;
TimeBar *timeProgress;
int rowScanCount, foundRows;
}
// methods here....
#end
I'm new to this, so bear with me. I was confused as I'm clearly stating that *controls is of the type 'BrickControlLayer'. So I'm thinking there's something wrong inside 'BrickControlLayer' itself.
Here's the header...
// BrickControlLayer.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "brickSprite.h"
#import "HighScores.h"
#interface BrickControlLayer : Layer{
CocosNode *spriteHolder;
CGPoint touchedStartPoint, moveFromPoint;
brickSprite *touchedBrick;
BOOL editorMode;
int movecount;
// Control buttons
AtlasSpriteManager *buttonManager;
AtlasSprite *rotLeft, *rotRight, *newBrick, *deleteBrick, *makeTarget, *save, *run;
BOOL tapToContinue;
}
#property (retain, readwrite) CocosNode *spriteHolder;
#property (retain, readwrite) brickSprite *touchedBrick;
-(void)showEditorControls;
-(void)selectBrickAtLocation:(CGPoint)location;
-(void)hideEditorControls;
-(void)deactivate;
#end
I've been over it and over it. It was all working fine before and I simply can't figure it out. I've been googling it and the only thing that crops up is the term "Forward Declaration", but that doesn't mean anything to me and all the info I've found talks about structs.
I suspect the errors are more of an indication that I'm doing lot's of other things wrong, rather than committing a simple one line typo or something. Can anyone explain in laymans terms what's going on here?
Jason here from OpenFeint. If you'd like to send over a code sample to devsupport at openfeint dot com that demonstrates the problem we'll take a look at it for you. It sounds like you may be including the header file from a .CPP instead of a .MM file.
If all you did was change the iPhone Target SDK, double check that when you setup compiler options you did it for all SDKs and build configurations (release, debug).
The error you're getting sounds like the compiler doesn't recognize that you're in an Objective-C declaration OR it can't find the header declaration for BrickControlLayer. Could be a circular include? (do you use include guards or #pragma once?)
Hope that helps,
- Jason Citron
- Founder & CEO, Aurora Feint
Your error is about BrickController not BrickControlLayer so I don't think that you've posted the line that the compiler is actually complaining about.
Having said that, I think that your fundamental problem is that you are trying to compile files that look to be Objective C with something that, from it's error messages, thinks that it is an ISO C++ compiler.
Have you followed all of the steps listed on the Integrating the OpenFeint SDK page?
Alternatively, you could create one single class that is Objective-C++ that interfaces with OpenFeint. Then all your Objective-C classes can remain the same but make calls to the OpenFeint handler class.
Have you renamed all files that include or import OpenFeint to .mm ? Also have you tried turning off (or on) 'compile for thumb' in your build settings?