Check whether an object was created inside a loop or not - ios

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;
}

Related

unsure of (id)init explanation

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.

make retain count in ARC

I am using an external library in my project which is being build in an ARC environment. As per the library the socket object gets deallocated only when the retain count=0. As far as I know its not liable to use retain count in ARC but I am forced to remove all the reference of the socket object which is not possible in my project. How can I resolve this issue? A gist of code issue is below:
-(void)callConnect{
for(int i = 0; i<[userArray count];i++){
[self connect:(NSString*)[userArray objectAtIndex:i]];
}
}
-(void)connect:(NSString *)username{
RTMPCLient *socket = [[RTMPClient alloc] init];
BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket];
NSMutableDictionary *stream = [NSMutableDictionary dictionaryWithObject:stream forKey:username];
}
-(void)disconnect{
for(int i = 0; i<[userArray count];i++){
[stream objectForKey:[NSString stringWithFormat:#"%#",[userArray objectAtIndex:i]]] = nil; //error on this line
BroadCastClient *tempStream = [stream objectForKey:[userArray objectAtIndex:i]];
tempStream = nil;
}
}
I am trying to make the stream object nil which gives an error. Cannot save it another variable as it increases the references of socket object.By making the tempStream nil doesn't affect the original instance created.
I want to remove the reference of socket object from stream in the disconnect method. How can I do so?
ARC will put the invisible release message in your code (in connect), but the array will have strong reference on them, so they will stay in memory. All you have to do in disconnect remove all the objects from your collection ([stream removeAllObjects] and [userArray removeAllObjects]) and the collection will release them.
UPDATE:
By following your code I see the following:
In this code you are creating an instance of BroadCastClient and adding it to NSDictionnary (stream), but NSDictionary has no reference to it, so it will be deallocated after the method call
-(void)callConnect{
for(int i = 0; i<[userArray count];i++){
[self connect:(NSString*)[userArray objectAtIndex:i]];
}
}
-(void)connect:(NSString *)username{
RTMPCLient *socket = [[RTMPClient alloc] init];
BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket];
NSMutableDictionary *stream = [NSMutableDictionary dictionaryWithObject:stream forKey:username];
}
Now here the disconnect stream dictionary (I don't know what is this object, because in your code I don't see any creating or adding to it) the object BroadCastClient is retained by the dictionary, so just removing this object from the dictionary will free it from memory (assuming you have no other strong reference to it)
-(void)disconnect{
for(int i = 0; i<[userArray count];i++){
[stream objectForKey:[NSString stringWithFormat:#"%#",[userArray objectAtIndex:i]]] = nil; //error on this line
BroadCastClient *tempStream = [stream objectForKey:[userArray objectAtIndex:i]];
tempStream = nil;
}
}
I would recommend some refactoring for your code, but before that please have some time to read this guid: https://developer.apple.com/library/mac/documentation/cocoa/conceptual/memorymgmt/Articles/mmPractical.html
IN ARC, you have to just make the objects to nil to maintain RC. So you can do it in the following way.
-(void)disconnect{
socket = nil;
stream = nil;
stream = nil;
}
-(void)connect:(NSString *)username{
if (socket != nil )
socket = nil;
RTMPCLient *socket = [[RTMPClient alloc] init];
if (stream != nil )
stream = nil;
BroadCastClient *stream = [[BroadCastClient alloc] initWithClient:socket];
NSMutableDictionary *stream = [NSMutableDictionary dictionaryWithObject:stream forKey:username]; // Make it using alloc...then you must use nil only
}
It looks like stream is an instance variable of type NSMutableDictionary *. So if you want to remove the references in your stream dictionary, you could do it like this:
- (void)disconnect {
for (int i = 0; i<[userArray count]; i++) {
[stream removeObjectForKey:[userArray objectAtIndex:i]];
}
}
// Alternative version using Fast Enumeration:
- (void)disconnect {
for (id key in userArray) {
[stream removeObjectForKey:key];
}
}
But if all you want to do is remove all references from stream, simply do:
- (void)disconnect {
[stream removeAllObjects];
}

My method won't work

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: ]

Method does not return what it should when called

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!

Access a variable outside the method in objective-c

I have this function that is storing the contents of an array in three different variables. My question is how can I access to the contents stored in _company.address from another function in the same class.
-(NSArray *) csvArray2CompaniesArray:(NSArray *) csvArray
{
int i=0;
NSMutableArray *ma = [[NSMutableArray alloc] init];
for (NSArray * row in csvArray)
{
if (i>0)
{
Company *_company = [[Company alloc] init];
_company.name = [row objectAtIndex:0];
_company.address = [row objectAtIndex:1];
_company.telephone = [row objectAtIndex:2];
[ma addObject:_company];
}
i++;
}
return (NSArray *) ma;
}
Thank you in advance.
You cannot the accessibility of an object is private in a function.Either you declare it as global or declare it in class's scope.Better in .h file
You can use the functios value as :-
YourViewControllerWithFunction *accessFunc=[[YourViewControllerWithFunction alloc]]init];
Company *_company=[accessFunc csvArray2CompaniesArray:youInputArray];
[_company objectAtIndex:intVallue];//Use in loop
You should correct the return value of your function to NSMutableArray or make a copy to get the NSArray of the NSMutableArray you created.
After that, you can access the contents of your array from anywhere inside your class like:
for (Company *c in [self csvArray2CompaniesArray:csvarray])
{
NSLog(#"%#", c.address);
}

Resources