So this is fairly beginner, but I'm trying to really grasp this concept. So in my sample code I have an Init method with two Constants defined at the beginning of the .m :
#define NUM_TOP_ITEMS 5
#define NUM_SUBITEMS 6
- (id)init {
self = [super init];
if (self) {
topItems = [[NSArray alloc] initWithArray:[self topLevelItems]];
subItems = [NSMutableArray new];
currentExpandedIndex = -1;
for (int i = 0; i < [topItems count]; i++) {
[subItems addObject:[self subItems]];
}
}
return self;
}
What is the init method doing here? Could i initiate the two constants in their separate alloc/init methods? Any clarity here would be great! thanks
OK, line by line...
#define NUM_TOP_ITEMS 5 // defining a macro for the number 5
#define NUM_SUBITEMS 6 // and 6
- (id)init
{
self = [super init]; // here you are initialising the object by calling the super class method
// this is important as you still want the functionality/properties etc... from the super class.
if (self) { //check the object actually exists.
topItems = [[NSArray alloc] initWithArray:[self topLevelItems]]; //This looks like it's running a method called topLevelItems
// that returns an NSArray. You are then saving it in an iVar (I guess)
subItems = [NSMutableArray new]; // this creates a new mutable array in an iVar called subItems
currentExpandedIndex = -1; // this sets an iVar int value
for (int i = 0; i < [topItems count]; i++) { // set up a for loop for the topItems array
[subItems addObject:[self subItems]]; //...wat?
// not quite sure what's going on here.
// I don't think it's doing what you think it's doing
}
}
return self; // return the object whether it has been allocated successfully or not.
}
Constants defined using #define are like a search and replace for tokens which happens at compile time. This is the C pre-processor, it means that code like this,
#define NUM_TOP_ITEMS 5 + 1
int i = NUM_TOP_ITEMS + NUM_TOP_ITEMS;
gets pre-processed to something like this,
int i = 5 + 1 + 5 + 1;
before the next compilation step happens.
Related
I want to list the lldb variables in Xcode debugger
such as
$0 = ...
$1 = ...
Which command should i enter?
For example
You can use frameVariable to get a list of all variables in the stack frame.
- (void)viewDidLoad {
[super viewDidLoad];
NSHashTable *hashTable = [NSHashTable weakObjectsHashTable];
ABC *object = [[ABC alloc] init];
[hashTable addObject:object];
//NSLog(#"%#", [hashTable anyObject]);
object = nil;
int i = 0;
int j = 1;
}
frame variable
(ViewController *) self = 0x00007fa2275047d0
(SEL) _cmd = "viewDidLoad"
(NSConcreteHashTable *) hashTable = 0x000061000013f5e0
(ABC *) object = nil
(int) i = 0
(int) j = 1
You want to list all the variables you have defined in or are the result of expressions you've evaluated, right?
If so, there isn't a way to do that currently. But it would be straightforward to add. Please file an enhancement request with the lldb bug reporter:
https://bugs.llvm.org
and somebody will get to it.
I'm pretty new to Objective C, and I've been having quite the roadblock in my code...
I am making a (very) simple card game to run on iOS. All you are supposed to do is draw cards until a Joker is drawn, then the game ends.
My app has been crashing at a curly bracket at the end of a for loop that is making card objects to put into the array
Here's my Deck.m:
#import "Deck.h"
#import "Card.h"
#implementation Deck
#synthesize deckArray;
- (void)removeCard {
[deckArray removeObjectAtIndex:deckArray.count];
}
- (void)generate {
NSLog(#"Generating deck...");
NSMutableArray *deckArray = [[NSMutableArray alloc]init];
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Hearts";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
}
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Spades";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
}
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Diamonds";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
}
for (int i = 0; i < 14; i++) {
//Make a card
Card *card = [[Card alloc]init];
//Give it some values
card.value = i + 1;
card.suit = #"Clubs";
//Put card in array
[deckArray addObject:card];
NSLog(#"Added object (%#) to array",card);
} //Crashes on this line: Thread 1: Breakpoint 2.1
NSLog(#"Generated deck");
}
- (Card *)topCard {
return [deckArray objectAtIndex:deckArray.count];
}
#end
I'm pretty sure it is the most obvious thing in the world but, again, I am pretty new on programming in general
Thank you in advance!
I can see issue in tow methods: removeCard and topCard.
You try access object which is out of bounds:
[deckArray objectAtIndex:deckArray.count]
If you have 5 items in the array deckArray.count returns 5 but last index is 4 (arrays index are zero based) so you have to replace call to deckArray.count to deckArray.count-1.
- (Card *)topCard {
return [deckArray objectAtIndex:deckArray.count-1];
}
And do the same in removeCard method.
This line : NSMutableArray *deckArray = [[NSMutableArray alloc]init];
You already declared deckArray in your header file(.h).
You should do: deckArray = [[NSMutableArray alloc] init];
As told in the Crash log, I had my 'remove card' method take away an object that didn't exist because arrays are zero-based. Also, I put self. in front of deckArray seemed to help. I should've learned a bit more Obj-C before posting this question, so my apologies to you. .count - 1 also helped on the other methods.
I'm a total noob and need help with a method I'm writing.
The method creates a deck of cards (using NSMutableArray). I'm first experimenting with loading the array with numbers 1-13 randomly (each number appearing once).
When I run a simple test program to print the values in the array, I get a "Build Successful" but an error once the program starts. The error says "[__NSArrayM insertObject:atIndex:]: object cannot be nil".
Once I understand what I'm doing wrong, I can then expand on the method properly. Thanks!
NB: This is my first post. Is this type of question ok?
- (void) createDeck {
int r;
BOOL same;
deck = [[NSMutableArray alloc]init];
NSNumber *randNum;// = nil;
randNum = [[NSNumber alloc]init];
[randNum initWithInt: (arc4random()%13)+1];
[deck addObject: randNum]; // First card added to deck
same = FALSE;
while (!same) {
for (int i=1; i<13; i++) {
same = FALSE;
for (r=0; r<=i; r++) {
[randNum initWithInt: (arc4random()%13)+1];
if ([deck objectAtIndex:r] == [deck objectAtIndex:i]) {
same = TRUE;
}
[deck addObject: randNum]; // Next card added to deck
}
}
}
}
you cannot re-init randNum:
NSNumber *randNum;// = nil;
randNum = [[NSNumber alloc]init];
[randNum initWithInt: (arc4random()%13)+1];
and the third line is missing the assignment anyway. just do:
NSNumber *randNum = [[NSNumber alloc] initWithInt:(arc4random()%13)+1];
and put that inside the inner for loop, like this:
BOOL same = FALSE;
NSMutableArray *deck = [[NSMutableArray alloc] initWithCapacity:13];
[deck addObject:[[NSNumber alloc] initWithInt:(arc4random()%13)+1]]; // First card added to deck
while (!same) {
for (int i = 1; i < 13; i++) {
same = FALSE;
for (int r = 0; r <= i; r++) {
NSNumber *randNum = [randNum initWithInt:(arc4random()%13)+1]; // modern ObjC will assign a register for this outside the while loop, but restrict the variable's scope to the inner-most loop
if ([deck objectAtIndex:r] == [deck objectAtIndex:i])
same = TRUE;
[deck addObject: randNum]; // Next card added to deck
}
}
Note that I haven't thought through the logic of what you are trying to do here, I've only attempted to resolve the NULL object reference. The error was referring to the first line [deck addObject: randNum] outside of the loop.
Try to use this line of code where you using NSNumber
NSNumber * randNum = [NSNumber numberWithInt: (arc4random%13)+1];
Instead of
[[NSNumber alloc] initWithInt: ]
I have a piece of code that returns an object of type Card like so:
-(Card*) drawRandomCard {
if ([self.cards count]) {
unsigned index = arc4random() % self.cards.count;
Card *randomCard = self.cards[index];
[self.cards removeObjectAtIndex:index];
NSLog(#"%#", randomCard.description); **//returns a description and not null**
return randomCard;
} else {
NSLog(#"nil");
return nil;
}
}
This actually works fine when I use it in other functions, but there is a problem with this one below:
- (IBAction)addCards:(UIButton *)sender {
int numberOfCardsToAdd = EXTRA_CARDS_NUMBER;
if ([[self.collectionView visibleCells] count] == 0) {
numberOfCardsToAdd = self.startingCardCount;
}
for (int i = 0; i < numberOfCardsToAdd; i++) {
if (!self.game.deck.isEmpty){
Card *cardToAdd = [self.game.deck drawRandomCard];
NSLog(#"%#", cardToAdd.description); **// gives (null)**
if (cardToAdd) { **// this does not get called**
// do stuff with cardToAdd
}
}
}
[self.collectionView reloadData];
}
So for some reason it seems my drawRandomCard, when called with the method above, does not work. Does anyone know how to fix this?
Thanks very much!
Edit: my method for initializing the game object that has the deck property:
- (id) initWithNumberOfCards: (int) numberOfCards withDeck: (SetsPlayingDeck *) deck {
self = [self init];
self.score = 0;
_deck = deck;
_cards = [[NSMutableArray alloc] initWithCapacity:numberOfCards];
for (int i = 0; i < numberOfCards; i++) {
[_cards addObject: [_deck drawRandomCard]];
}
return self;
}
This method is called right at the start of the program.
Edit #2:
Here is the code that initializes the game object, along with a deck object that is its property:
- (SetsGame *) game {
if (!_game) {
SetsPlayingDeck *deck = [[SetsPlayingDeck alloc] init];
_game = [[SetsGame alloc] initWithCardCount:self.startingCardCount usingDeck:deck];
}
NSLog(#"%#", _game.deck.description); **// this returns null!!**
return _game;
}
As far as I can see, the issue should lie with the method initWithCardCount:usingDeck:, where you probably forgot to assign the deck argument to the deck property (or for some reason the assignment is not executed):
_game = [[SetsGame alloc] initWithCardCount:self.startingCardCount usingDeck:deck];
So, please review this or post that method definition.
Maybe the problem is that you're running out of cards. Inside your init method you have the following line inside a for-loop:
[_cards addObject: [_deck drawRandomCard]];
And inside your drawRandomCard method you have the following line:
[self.cards removeObjectAtIndex:index];
I'm assuming that _cards(1st line) and self.cards(2nd line) are different objects.
Probably, by the time you call Card *cardToAdd = [self.game.deck drawRandomCard]; inside your addCards: method you don't have any cards left.
Try to set a breakpoint and step in the for-loop and let me know,
Hope this helps!
is there any way in Objective-C to check whether an Object has been created inside a loop (while, for)?
Thanks in advance.
NSString *obj = nil;
while()
{
//Create object
obj = [[NSString alloc] init];
}
//check obj is nil or not
if(nil == obj)
{
// obj not created
}
Yes but for an accurate answer can you tell us what the object is and when it is declared? Can you post the code you have?
int x=0;
while (x<3) {
NSString *i = #"hello world";
x++;
}
NSLog(#"i is %#", i) // i is only declared inside the while loop so not available here
Alternatively,
int x=0;
NSString *i;
while (x<3) {
i = #"hello world";
x++;
}
NSLog(#"i is %#", i); // i is declared beforehand outside the while loop so is available here
If you then need to act on whether it's been created or not use Anil's answer but it's the scope that's important here
I don't think you can know if it was created in a loop, but because you are writing the code where the object will be created in a loop you could call a special init method...
SpecialClass * obj = [[SpecialClass alloc] init];
while (isTrue)
{
SpecialClass * loopObj = [[SpecialClass alloc] initCreatedByLoop];
// Do whats needed
}
and in your SpecialClass you create a specific initialiser...
#implementation SpecialClass
-(id)initCreatedByLoop {
self = [super init];
if (self) {
// What ever you want to do
}
return self;
}