std::list problem for iPhone development - iphone

I found some problems for std::list when I'm doing some iPhone development under Xcode. Here is the code:
///////////// interface //////////////
class CObj
{
public:
int value;
};
typedef std::list<CObj*> ObjList;
#interface testAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ObjList m_objs;
}
//////////// implementation /////////
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
for (int i = 0; i< 10; i++ )
{
CObj* obj = new CObj;
obj->value = i;
m_objs.push_back(obj);
}
NSLog(#"%d objects",m_objs.size() );
ObjList::iterator it = m_objs.begin();
while (it != m_objs.end())
{
CObj* obj = *it;
if ( obj->value == 3 )
it = m_objs.erase(it);
else
it++;
}
NSLog(#"%d objects",m_objs.size() );
}
The application simply crashes at m_objs.push_back. But if I change the std::list to std::vector, everything's fine. Any idea? Thanks

By default Objective-C does not call the constructor for c++ types on initialization.
If you set this flag in the build settings "Call C++ Default Ctors/Dtors in Objective-C", it will change the default behavior. Be aware that the flag only shows up if you have the target set to Device.

Related

Terminating app due to uncaught exception 'NSUnknownKeyException' : iOS app crash [duplicate]

This question already has answers here:
Xcode - How to fix 'NSUnknownKeyException', reason: … this class is not key value coding-compliant for the key X" error?
(79 answers)
Closed 9 years ago.
I'm a beginner programmer working on iPhone apps. I was wondering if anybody could help me with a bug in my app. When programming on XCode I found that my app suddenly crashed on launch after adding a little more code. The output panel showed the following error:
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key play.'
* First throw call stack:
(0x1c91012 0x10cee7e 0x1d19fb1 0xb7ae41 0xafc5f8 0xafc0e7 0xb26b58 0x230019 0x10e2663 0x1c8c45a 0x22eb1c 0xf37e7 0xf3dc8 0xf3ff8 0xf4232 0x433d5 0x4376f 0x43905 0x8eceab6 0x4c917 0x1096c 0x1194b 0x22cb5 0x23beb 0x15698 0x1becdf9 0x1becad0 0x1c06bf5 0x1c06962 0x1c37bb6 0x1c36f44 0x1c36e1b 0x1117a 0x12ffc 0x222d 0x2155)
libc++abi.dylib: terminate called throwing an exception
(lldb)
The code that shows up when the app terminates is as follows
#import <UIKit/UIKit.h>
#import "CIAAppDelegate.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([CIAAppDelegate class]));
}
}
My ViewController.h shows:
#import <UIKit/UIKit.h>
#interface CIAViewController : UIViewController {
IBOutlet UILabel *cruzia;
IBOutlet UILabel *textarea;
IBOutlet UIButton *playbtn;
IBOutlet UIButton *tutorialbtn;
IBOutlet UIButton *optionsbtn;
IBOutlet UIButton *trainingbtn;
IBOutlet UIButton *back;
}
-(IBAction)press;
-(IBAction)press2;
-(IBAction)press3;
-(IBAction)press4;
-(IBAction)press5;
Also my ViewController.m shows
#import "CIAViewController.h"
#interface CIAViewController ()
#end
#implementation CIAViewController
-(IBAction)press {
cruzia.hidden = 0;
textarea.hidden = 0;
playbtn.hidden = 1;
tutorialbtn.hidden = 1;
optionsbtn.hidden = 1;
trainingbtn.hidden = 1;
back.hidden = 0;
cruzia.text = #"Play";
textarea.text = #"Hello! You are playing the game of Cruzia!";
}
-(IBAction)press2 {
cruzia.hidden = 0;
textarea.hidden = 0;
playbtn.hidden = 1;
tutorialbtn.hidden = 1;
optionsbtn.hidden = 1;
trainingbtn.hidden = 1;
back.hidden = 0;
cruzia.text = #"Tutorial";
textarea.text = #"Welcome! You are watching the Cruzia tutorial!";
}
-(IBAction)press3 {
cruzia.hidden = 0;
textarea.hidden = 0;
playbtn.hidden = 1;
tutorialbtn.hidden = 1;
optionsbtn.hidden = 1;
trainingbtn.hidden = 1;
back.hidden = 0;
cruzia.text = #"Options";
textarea.text = #"You are now in the Options screen. You can edit the settings of the game!";
}
-(IBAction)press4 {
cruzia.hidden = 0;
textarea.hidden = 0;
playbtn.hidden = 1;
tutorialbtn.hidden = 1;
optionsbtn.hidden = 1;
trainingbtn.hidden = 1;
back.hidden = 0;
cruzia.text = #"Training";
textarea.text = #"This is the training area. You can improve your Cruzia skills here!";
}
-(IBAction)press5 {
cruzia.hidden = 0;
textarea.hidden = 0;
playbtn.hidden = 0;
tutorialbtn.hidden = 0;
optionsbtn.hidden = 0;
trainingbtn.hidden = 0;
back.hidden = 1;
cruzia.text = #"Cruzia";
}
- (void)viewDidLoad
{
textarea.hidden = 1;
playbtn.hidden = 0;
tutorialbtn.hidden = 0;
optionsbtn.hidden = 0;
trainingbtn.hidden = 0;
back.hidden = 1;
cruzia.text = #"Cruzia";
[super viewDidLoad];
}
#end
I am sorry to waste your time but I have had this error for a long time and would like it if you had a solution.
What The Problem Is:
At runtime your view controller is going to get deserialized from its XIB/Storyboard. During this process, it's going to read all the objects that are in your IB files and start instantiating them with an NSCoder. As it is instantiating those objects in your view, it's going to read the IBOutlet and IBAction connections in your storyboard and start assigning the hydrated objects to those properties that were connected at design time so that you have programmatic access to them at run time. But here's the kicker: If you have a connection that points to a property that doesn't exist, then this exception will be thrown because it was told a property was there that really isn't.
What's happening is that your Storyboard/XIB is expecting your class to have a property called play. As your interface shows, you do not have a property called that. I suspect though, that you used to, but renamed it playbtn.
This is what is meant by
this class is not key value coding-compliant for the key play
It means it tried to do something like this under the covers:
[self setValue:button forKey:#"play"]
For additional enlightenment about Key/Value Coding and serialization, grab a comfy chair and read Key Value Coding Programming Guide and Archives and Serializations Programming Guide
How To Fix It:
In Interface Builder, right click on your view controller and see the list of connections:
See how there is a connection for the property play and it has a little yellow triangle next to it? This is Interface Builder trying to warn you that you have a connection set there, but the header isn't showing that there is an IBOutlet of that name.
All you need to do is click that little x to break the connection to the missing property.
How To Prevent This In The Future
Anytime you change a property in your code, you'll need to make sure that you break any associated connection in Interface Builder.

How to extend my method that checking if 2 cards are matched to 3 cards that are matched?

I'm following the Stanford course, and we had to build a method for the app that checks for 2 cards matching, this is how the model that have the logic looks like (the method to look there is flipCardAtIndex):
#import "CardMatchingGame.h"
#import "PlayingCardsDeck.h"
#interface CardMatchingGame()
#property (readwrite, nonatomic) int score;
#property (strong, nonatomic) NSMutableArray *cards;
#property (strong, nonatomic) NSString *notification;
#end
#implementation CardMatchingGame
-(NSMutableArray *) cards {
if (!_cards) _cards = [[NSMutableArray alloc] init];
return _cards;
}
-(id)initWithCardCount:(NSUInteger)count usingDeck:(Deck *)deck {
self = [super init];
if (self) {
for (int i = 0; i < count; i++) {
Card *card = [deck drawRandonCard];
if (!card) {
self = nil;
} else {
self.cards[i] = card;
}
}
}
return self;
}
-(Card *) cardAtIndex:(NSUInteger)index {
return (index < self.cards.count) ? self.cards[index] : nil;
}
#define FLIP_COST 1
#define MISMATCH_PENALTY 2
#define BONUS 4
-(void) flipCardAtIndex:(NSUInteger)index {
Card *card = [self cardAtIndex:index];
if (!card.isUnplayable) {
if (!card.isFaceUp) {
for (Card *otherCard in self.cards) {
if (otherCard.isFaceUp && !otherCard.isUnplayable) {
int matchScore = [card match:#[otherCard]];
if (matchScore) {
otherCard.unplayble = YES;
card.unplayble = YES;
self.notification = [NSString stringWithFormat:#"%# & %# match!", card.contents, otherCard.contents];
self.score += matchScore * BONUS;
} else {
otherCard.faceUp = NO;
self.score -= MISMATCH_PENALTY;
self.notification = [NSString stringWithFormat:#"%# did not matched to %#", card.contents, otherCard.contents];
}
break;
}
}
self.score -= FLIP_COST;
}
card.faceUp = !card.isFaceUp;
}
}
#end
And this is the class model of the whole game, that got the actual matching method:
#import "PlayingCards.h"
#implementation PlayingCards
#synthesize suit = _suit;
//overriding the :match method of cards to give different acore if its only a suit match or a number match
-(int)match:(NSArray *)cardToMatch {
int score = 0;
if (cardToMatch.count == 1) {
PlayingCards *aCard = [cardToMatch lastObject];
if ([aCard.suit isEqualToString: self.suit]) {
score = 1;
} else if (aCard.rank == self.rank) {
score = 4;
}
}
return score;
}
//more stuff...
W already created it with an array so we will be able to extend it for more objects, but now i'm trying to figure out how do I extend it :/
This is my github for the project https://github.com/NirOhayon/Matchismo
i'm new to objective C and would appreciate it munch if you could help me to figure it out.
Thanks a bunch
You can chain these with a loop to check them all. Very basic way of doing it. Just loop through each card and check it against the "self" card that you have and increment the score instead of setting it.
-(int)match:(NSArray *)cardToMatch {
int score = 0;
for(int i = 0; i < cardToMatch.count; i++) {
PlayingCards *aCard = cardToMatch[i];
if ([aCard.suit isEqualToString: self.suit]) {
score += 1;
} else if (aCard.rank == self.rank) {
score += 4;
}
}
return score;
}
For flipCardAtIndex: , I would change it to flipCardsAtIndexes:(NSArray*)indexes, where indexes is an NSArray of NSNumbers. Then I would run a for loop checking and removing any cards that are unplayable or faceup, and pass through the remaining cards at those indexes to check match, and retrieve the match score.
To tell your view controller to add another card depends on how you have your view controller set up. You could do a protocol in a method that your view controller becomes the delegate of, and through a protocol method, tell it to switch. It could also be simpler than that, depending on how it checks your model of cards to decide what to show, if it sees three cards available instead of two, it could switch.
As the point of this exercise is to learn iOS programming, I want to give you a good head start and you should tweak and figure some stuff out on your own. I have a feeling you're a novice at programming, and if you are, you'll be surprised how much programming at your stage is trial and error. Eventually it will become second nature.

Accessing Structure in objective C class makes error on XCode 4.2

In my iPhone app, I am using structure and access it from Objective C UIViewController class, In one of my AudioInput.h file, I have the below:
typedef struct
{
AudioStreamBasicDescription format;
AudioQueueRef queue;
AudioQueueBufferRef buffers[ NUM_AUDIO_BUFFERS ];
SampleBuffer samples;
bool running;
bool done;
UInt32 playPos;
} AudioRecording;
In My ViewController MainViewController.m I implemented the AudioInputCallback() as below:
static void AudioInputCallback(
void *userData,
AudioQueueRef queue,
AudioQueueBufferRef buffer,
const AudioTimeStamp *startTime,
UInt32 numPackets,
const AudioStreamPacketDescription *packetDescriptions
)
{
// TRACE( "AudioInputCallback\n" );
MainViewController *controller = (MainViewController *) userData;
AudioRecording *audioRecording = & controller->audioRecording;
if( audioRecording->done )
{
TRACE( "AudioInputCallback: done\n" );
return;
}
if( numPackets == 0 && audioRecording->format.mBytesPerPacket > 0 )
{
numPackets = buffer->mAudioDataByteSize / audioRecording->format.mBytesPerPacket;
}
if( numPackets == 0 )
{
TRACE( "not packets received\n" );
return;
}
const SInt16 *inSamples = (const SInt16 *) buffer->mAudioData;
const UInt32 remain = audioRecording->samples.size - audioRecording->samples.count;
if( numPackets > remain )
{
numPackets = remain;
}
if( numPackets == 0 )
{
TRACE( "AudioInputCallback: no packets received\n" );
}
if( numPackets > 0 )
{
/* Save samples. */
if( audioRecording->samples.data )
{
UInt16 *in = (UInt16 *) inSamples;
UInt16 *out = (UInt16 *)( audioRecording->samples.data + audioRecording->samples.count );
for( UInt32 i = 0; i < numPackets; ++i )
{
*out ++ = ntohs( *in++ );
}
}
audioRecording->samples.count += numPackets;
}
if( audioRecording->samples.count < audioRecording->samples.size )
{
OSStatus result = AudioQueueEnqueueBuffer( queue, buffer, 0, NULL );
if( result )
{
TRACE( "AudioQueueEnqueueBuffer(..) failed with status %d\n", result );
}
}
else
{
TRACE( "AudioInputCallback: enough material, stop recording\n" );
audioRecording->done = true;
AudioQueueStop( audioRecording->queue, true );
}
[controller performSelectorOnMainThread:#selector(bufferFilled) withObject:nil waitUntilDone:NO];
}
In this method on the below line It gives error as "instance variable is protected"
MainViewController *controller = (MainViewController *) userData;
AudioRecording *audioRecording = & controller->audioRecording;
This error is occurs while running for iOS 5 with XCode 4.2 but the same code is running without any error building for below iOS 5 in XCode 4.0.2.
Can anyone help me why this error occurs? and your ideas to solve this is welcome!
It's nothing to do with your structure, it's to do with how you've defined the members of your UIViewController subclass. Take a look at this :
#interface MainViewController : UIViewController
{
#public
AudioRecording audioRecording1;
#protected // This is the default
AudioRecording audioRecording2;
#private
AudioRecording audioRecording3;
}
#end
Here, this controller has three AudioRecording members. However, only audiorecording1 can be access directly from outside the class. audiorecording3 cannot be accessed by anything other than the MainViewController and audiorecording2 can be accessed by MainViewController and any subclasses of it.
You need to make your audiorecording public if you want to access it directly without going though an accessor method (or a property).

How to use CARingBuffer class in an iOS (iPhone, iPad) project?

I'm currently trying to create an iOS audio project and I need to use the CARingBuffer class available in the Extras/CoreAudio/PublicUtility folder of XCode.
The problem is when I include the CARingBuffer.h in the header of my viewController and I declare a CARingBuffer object, I receive 4 compile errors.
To reproduce my problem it's pretty simple. Just create a new view based application and try to #include "CARingBuffer.h" in the header of your viewController.
Here's the content of my testViewController.h :
#import <UIKit/UIKit.h>
#include "CARingBuffer.h"
#interface testViewController : UIViewController {
}
#end
Here's the content of my testViewController.m :
#import "testViewController.h"
#implementation testViewController
- (void)dealloc
{
[super dealloc];
}
- (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.
}
#pragma mark - View lifecycle
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
*/
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
Bellow the 4 compile errors located (strangely) in the CARingBuffer according to XCode 4 :
1) Initializer element is not a constant on line :
const UInt32 kGeneralRingTimeBoundsQueueMask = kGeneralRingTimeBoundsQueueSize - 1;
2) Expected ';' after top level declarator, Expected '='... or 'atribute' before 'CARingBuffer' :
class CARingBuffer {
3) Initializer element is not a constant on line :
const UInt32 kGeneralRingTimeBoundsQueueMask = kGeneralRingTimeBoundsQueueSize - 1;
4) Expected ';' after top level declarator, Expected '='... or 'atribute' before 'CARingBuffer' :
class CARingBuffer {
Thanks in advance for your help.
Also take a look at this alternative
You need to rename the class that you are including the ring buffer in to be a .mm file.
This tells the compiler to use objective c++ .
You need change your testViewController.m to testViewController.mm because CARingBuffer is c++ class.
About how to use it, here is an extend of CARingBuffer : CARingBufferEx
//header file
#include "CARingBuffer.h"
class CARingBufferEx : public CARingBuffer {
public:
CARingBufferEx();
~CARingBufferEx();
CARingBufferError Store(const AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber);
CARingBufferError Fetch(AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber);
private:
SInt64 firstInputSampleTime;
SInt64 firstOutputSampleTime;
SInt64 offset;
};
//Class
#include "CARingBufferEx.h"
#include "stdio.h"
CARingBufferEx::CARingBufferEx():firstInputSampleTime(-1), firstOutputSampleTime(-1), offset(0) {
}
CARingBufferEx::~CARingBufferEx() {
}
CARingBufferError CARingBufferEx::Store(const AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber) {
if (firstInputSampleTime < 0) {
firstInputSampleTime = frameNumber;
if (firstOutputSampleTime > 0 && offset == 0) {
offset = firstInputSampleTime - firstOutputSampleTime;
}
}
return CARingBuffer::Store(abl, nFrames, frameNumber);
}
CARingBufferError CARingBufferEx::Fetch(AudioBufferList *abl, UInt32 nFrames, SampleTime frameNumber) {
if (firstOutputSampleTime < 0) {
firstOutputSampleTime = frameNumber;
if (firstInputSampleTime > 0 && offset == 0) {
offset = firstInputSampleTime - firstOutputSampleTime;
}
}
return CARingBuffer::Fetch(abl, nFrames, frameNumber + offset);
}
Usage:
CARingBufferEx* _musicMixerRingBuffer;
_musicMixerRingBuffer = new CARingBufferEx();
_musicMixerRingBuffer->Allocate(2, sizeof(AudioUnitSampleType), 1024 * 50);
//1024 is length for one package. and 50 means this buffer contains 50 packages at most.
//store
//ioData is AudioBufferList ,inTimeStamp is AudioTimeStamp
musicMixerRingBuffer->Store(ioData, inNumberFrames, inTimeStamp->mSampleTime);
//Fetch
musicMixerRingBuffer->Fetch(ioData, inNumberFrames, inTimeStamp->mSampleTime);

Playing audio on the iPhone decoded by a third-party library

The third-party library generates sequential buffers of 16-bit signed stereo samples of any desired size. I can't figure out which framework/functions to use to play from these buffers. I've been working off the example in this answer using AudioQueue but it's obviously incomplete in ways I can't resolve (local variables are used as if they are object members, undeclared variables, etc).
The code in Apple's SpeakHere example project only shows how to use AudioQueue to play audio from a file. Can someone point me in the right direction?
Figured it out. Here's a simple, complete and working white noise generator using AudioQueue created from the Window-based Application project template.
StaticAppDelegate.h:
// StaticAppDelegate.h
#import <UIKit/UIKit.h>
// STATIC ADDITIONS
// Add > Existing Frameworks... > AudioToolbox.framework to your Target
#import <AudioToolbox/AudioToolbox.h>
// END STATIC ADDITIONS
#interface StaticAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
// STATIC ADDITIONS
- (void)startStatic;
- (void)handleBufferCompleteForQueue:(AudioQueueRef)inAQ
buffer:(AudioQueueBufferRef)inBuffer;
// END STATIC ADDITIONS
#end
StaticAppDelegate.m:
// StaticAppDelegate.m
#import "StaticAppDelegate.h"
// STATIC ADDITIONS
#define kNumberBuffers 4
#define kBufferSize 2048
// AudioQueue callback
void AQOutputCallback(
void *inData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer
)
{
StaticAppDelegate *staticApp = (StaticAppDelegate *)inData;
[staticApp handleBufferCompleteForQueue:inAQ buffer:inBuffer];
}
// END STATIC ADDITIONS
#implementation StaticAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch
[window makeKeyAndVisible];
// STATIC ADDITIONS
[self startStatic];
// END STATIC ADDITIONS
}
- (void)dealloc {
[window release];
[super dealloc];
}
// STATIC ADDITIONS
- (void)startStatic
{
srandom(time(NULL));
// initiate audio session
AudioSessionInitialize(NULL, NULL, NULL, NULL);
UInt32 category = kAudioSessionCategory_MediaPlayback; // plays through sleep lock and silent switch
AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(category), &category);
AudioSessionSetActive(true);
// following is modified from http://stackoverflow.com/questions/1710133/playing-generated-audio-on-an-iphone
// setup queue
AudioQueueRef audioQueue;
AudioQueueBufferRef buffers[kNumberBuffers];
AudioStreamBasicDescription format;
memset(&format, 0, sizeof(format));
format.mSampleRate = 44100;
format.mFormatID = kAudioFormatLinearPCM;
format.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
format.mChannelsPerFrame = 1;
format.mBitsPerChannel = 16;
format.mBytesPerFrame = (format.mBitsPerChannel / 8) * format.mChannelsPerFrame;
format.mFramesPerPacket = 1;
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
AudioQueueNewOutput(&format,
AQOutputCallback,
self,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&audioQueue);
// allocate and fill the buffers
for (int i = 0; i < kNumberBuffers; ++i)
{
AudioQueueAllocateBuffer(audioQueue, kBufferSize, &buffers[i]);
AQOutputCallback(self, audioQueue, buffers[i]);
}
AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, 1.0);
AudioQueueStart(audioQueue, NULL);
}
- (void)handleBufferCompleteForQueue:(AudioQueueRef)inAQ
buffer:(AudioQueueBufferRef)inBuffer
{
inBuffer->mAudioDataByteSize = inBuffer->mAudioDataBytesCapacity;
int *buffer = (int *)inBuffer->mAudioData;
for (int i = 0; i < inBuffer->mAudioDataByteSize/sizeof(int); ++i)
{
buffer[i] = (int)rand(); // refill the buffer
}
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
}
// END STATIC ADDITIONS
#end
Once I figured out how to actually refill the buffer (inBuffer->mAudioData with some type casting) everything else fell into place.