make retain count in ARC - ios

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

Related

Potential leaks in iOS project

Hello i have this function, that gets dummy data from file in project:
Issues are shown in those lines:
NSString *path = [[NSBundle mainBundle] pathForResource: #"StatisticsDataJSON" ofType: #"TXT"]; - potential leak of an object.
NSMutableDictionary *statisticsResponse = [jsonParser objectWithString:data]; - potential leak of an object stored into 'jsonParser'
for (id key in statisticsResponse) { - potential leak of an object stored into 'statisticArray'
for (int i = 0; i < statsForDate.count; i++) { - potential leak of an object stored into 's'
if (self.statistics==nil)
{
self.statistics = [[NSMutableDictionary alloc]init];
NSString *path = [[NSBundle mainBundle] pathForResource: #"StatisticsDataJSON" ofType: #"TXT"];
NSError *error = nil;
NSString *data = [NSString stringWithContentsOfFile: path
encoding: NSUTF8StringEncoding
error: &error];
//NSLog(#"%#",data);
SBJsonParser *jsonParser = [[SBJsonParser alloc] init];
NSMutableDictionary *statisticsResponse = [jsonParser objectWithString:data];
for (id key in statisticsResponse) {
NSArray *statsForDate = [statisticsResponse objectForKey:key];
NSMutableArray *statisticArray = [[NSMutableArray alloc]init];
for (int i = 0; i < statsForDate.count; i++) {
Statistic *s = [[Statistic alloc]init];
s.locationId = [[statsForDate objectAtIndex:i] objectForKey:#"locationId"];
int value =[[[statsForDate objectAtIndex:i] objectForKey:#"visits"] integerValue];
s.visits = value;
value =[[[statsForDate objectAtIndex:i] objectForKey:#"totalUsers"] integerValue];
s.totalUsers = value;
value= [[[statsForDate objectAtIndex:i] objectForKey:#"uploads"] integerValue];
s.uploads = value;
value = [[[statsForDate objectAtIndex:i] objectForKey:#"downloads"] integerValue];
s.downloads = value;
value = [[[statsForDate objectAtIndex:i] objectForKey:#"apps"] integerValue];
s.apps = value;
[statisticArray addObject:s];
}
[self.statistics setObject:statisticArray forKey:key];
};
}
I have found that autorelease in ststisticsResponse - resolves the problem:
NSMutableDictionary *statisticsResponse = [[jsonParser objectWithString:data]autorelease];
But then something fails in SBJsonStreamParserAccumulator.m in dealoc function.
What is the problem?
Note that the warnings about potential leaks come on the line after the potential leak, because that's the first point at which the referenced object is technically "leaked". So your current fixes are probably over-releasing and causing crashes.
The first statement in your question actually refers to a leak in this line, immediately before:
self.statistics = [[NSMutableDictionary alloc]init];
You've got no further reference to that allocated dictionary, and it's a retained property, so you have a leak.
self.statistics = [[[NSMutableDictionary alloc]init] autorelease];
Will fix that one. The next one, you have to release the jsonParser when you've finished with it (after the parsing is done):
[jsonParser release];
I'm not going to go through all of them but you should get the idea. Basically you need to read the memory management guide, or update to ARC.
Pay attention to the variable names in the warnings. They tell you where the leak is.

TouchXML CXMLNode.m unrecognized selector when adding to NSMutableArray

I'm new to Objective C and XML, so this is going to look pretty rough.
My code is as follows:
#import "dbCommunicator.h"
#import "BookInfo.h"
#import "TouchXML.h"
#implementation dbCommunicator
-(void)getNextBooks {
if(self.bookListing == nil) {
for(int i = 0; i < 5; i++) {
BookInfo *newBook = [[BookInfo alloc] init];
[self.bookListing addObject:newBook];
}
self.currentPage = 0;
}
if(self.currentPage == 10) {
self.currentPage = 0;
}
NSString *test = #"<Authors><Book.Author><Id>1026</Id><Name>Mark Twain</Name></Book.Author></Authors>";
NSString *bookQueryString = [NSString stringWithFormat:#"http://bookworm.azurewebsites.net/api/book/list/5/%d",_currentPage];
NSURL *bookQueryURL = [NSURL URLWithString: bookQueryString];
self.currentPage++;
NSError *theError = NULL;
NSDictionary *mappings = [NSDictionary dictionaryWithObjectsAndKeys:
#"http://schemas.datacontract.org/2004/07/Bookworm.Models.ResponseModels",
#"datacontract",
nil];
CXMLDocument *xmlReturn = [[CXMLDocument alloc] initWithXMLString:test options:0 error:&theError];
NSArray *returnedBooks = [xmlReturn nodesForXPath:#"//Authors" error:&theError];
for(CXMLElement *resultElement in returnedBooks) {
NSLog(#"%s", "We actually got here");
}
}
There's a lot of junk code in there at the moment. The intention is to pull an XML file from a database and put its information into an array of BookInfo classes. For the moment, I simplified by just using a test XMLstring to ensure it wasn't an issue with what the database was sending me. This makes the dictionary (to deal with the namespace issues TouchXML has) superfluous. Anyways.
It always crashes with a unrecognized selector error on this line:
[theArray addObject:[CXMLNode nodeWithLibXMLNode:theNode freeOnDealloc:NO]];
In this context:
if (xmlXPathNodeSetIsEmpty(theXPathObject->nodesetval))
theResult = [NSArray array]; // TODO better to return NULL?
else {
NSMutableArray *theArray = [NSMutableArray array];
int N;
for (N = 0; N < theXPathObject->nodesetval->nodeNr; N++) {
xmlNodePtr theNode = theXPathObject->nodesetval->nodeTab[N];
[theArray addObject:[CXMLNode nodeWithLibXMLNode:theNode freeOnDealloc:NO]];
}
}
and with that, I'm totally at a loss. I've tried plenty of things, scoured every StackOverflow post even closely related and tried their fixes, nothing's working. Any suggestions?
array is a static method on NSArray a super class of NSMutableArray that returns an NSArray object. NSArray does not respond to the method addObject:
Try instead NSMutableArray *theArray = [NSMutableArray new];
The problem probably is on this selector:
nodeWithLibXMLNode:freeOnDealloc:
if you try to see your crash log in the console, should be written the selector unrecognized and should be this. If so check the class reference of the CXMLNode.
I checked now, and that method doesn't exists. Just a method might be useful for you in some way, that is:
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error;
Enjoy ;)

Trying to create an array of dictionaries, keep getting the same dictionary repeated in the array

I'm trying to use NSData to pull information out of a text file, and then load it into a dictionary.
First I create a string of the text file, and load each record into an array.
Then I break apart the each record into individual data elements.
The problem I'm having is that when the dictionary is fully populated, I then use addObject to load it into the array, which it does do successfully. The problem is that when the next loop creates a new dictionary, the same dictionary gets loaded into the array, and I end up an array of all the same dictionaries, instead of multiple different dictionary objects.
I'm guessing there is some simple mistake I'm making that is causing this error. Any help would be appreciated.
NSString *clientListFile = [NSURL URLWithString: #"/textfile"];
NSData *clientListDataFile = [NSData dataWithContentsOfFile:clientListFile];
NSString *clientListString = [[NSString alloc]initWithBytes:[clientListDataFile bytes] length:[clientListDataFile length] encoding:NSUTF8StringEncoding];
NSString *returnDelimiter = #"\n";
NSString *commaDelimiter = #",";
NSString *exclamationDelimiter = #"!";
NSArray *keysAndObjects = [[NSArray alloc]init];
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
NSMutableArray *clientListOfDictionaries = [[NSMutableArray alloc]init];
NSArray *sentenceArray = [clientListString componentsSeparatedByString:returnDelimiter];
for (int i = 0; i < [sentenceArray count]; i=i+1) {
[clientList removeAllObjects]; //to start with a fresh dictionary for the next iteration
NSString *recordSentence = [sentenceArray objectAtIndex:i];
NSArray *attributes = [recordSentence componentsSeparatedByString:commaDelimiter];
for (int j = 0; j < [attributes count]; j = j+1) {
NSString *pairsOfItems = [attributes objectAtIndex:j];
//a small arry, of only two objects, the first is the key, the second is the object
keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
[clientList setObject:[keysAndObjects lastObject] forKey:[keysAndObjects firstObject]];
}
[clientListOfDictionaries addObject:clientList];
}
When I used NSLog to see what's in the dictionary, I mulitple objects of the same dictionary repeated, even though up earlier in the iteration, I can see that the code is creating separate and unique dictionaries.
Instead of this line
[clientListOfDictionaries addObject:clientList];
you can have
[clientListOfDictionaries addObject:[[NSArray alloc] initWithArray:clientList];
That way you will be adding new arrays to clientListOfDictionaries instead of the same one.
Move this line:
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
to just after the first for loop line and then delete the line:
[clientList removeAllObjects];
It's important to create a new dictionary for each iteration.
You should also delete the following line:
NSArray *keysAndObjects = [[NSArray alloc]init];
and change:
keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
to:
NSArray *keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
You are allocated and initialising your clientList dictionary outside of the for loop, so you only have one dictionary, which you are storing in your array multiple times. Adding the dictionary to the array does not copy it, it merely adds a pointer to the object.
you need to move
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
inside your first for loop in place of
[clientList removeAllObjects];
Also, componentsSeparatedByString: returns an NSArray, so you don't need to allocate and initialise one. You can simply define the variable -
NSArray *keysAndObjects;
Because you're using the same clientList variable for each iteration of the loop. You need to create a whole new dictionary object each time.
Try this modified code:
NSData *clientListDataFile = [NSData dataWithContentsOfFile:clientListFile];
NSString *clientListString = [[NSString alloc]initWithBytes:[clientListDataFile bytes] length:[clientListDataFile length] encoding:NSUTF8StringEncoding];
NSString *returnDelimiter = #"\n";
NSString *commaDelimiter = #",";
NSString *exclamationDelimiter = #"!";
NSArray *keysAndObjects = nil;
NSMutableArray *clientListOfDictionaries = [[NSMutableArray alloc] init];
NSArray *sentenceArray = [clientListString componentsSeparatedByString:returnDelimiter];
for (NSUInteger i = 0; i < [sentenceArray count]; ++i) {
NSMutableDictionary *clientList = [[NSMutableDictionary alloc] init]; //to start with a fresh dictionary for the next iteration
NSString *recordSentence = [sentenceArray objectAtIndex:i];
NSArray *attributes = [recordSentence componentsSeparatedByString:commaDelimiter];
for (NSUInteger j = 0; j < [attributes count]; ++j) {
NSString *pairsOfItems = [attributes objectAtIndex:j];
//a small arry, of only two objects, the first is the key, the second is the object
keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
[clientList setObject:[keysAndObjects lastObject] forKey:[keysAndObjects firstObject]];
}
[clientListOfDictionaries addObject:clientList];
}
An alternate option, though likely less efficient, is to to change the line:
[clientListOfDictionaries addObject:clientList];
to
[clientListOfDictionaries addObject:[clientList copy]];
That lets you keep using the same clientList variable, since you're adding a copy of it to the clientListOfDictionaries array. I just point that out because it might help you understand what's going on.
Also, note that I changed this line for you:
NSArray *keysAndObjects = [[NSArray alloc]init];
to
NSArray *keysAndObjects = nil;
Because it's just a pointer that is set by your call to componentsSeparatedByString, you don't need to allocate an array for it. That array will just vanish in your first iteration of the loop.
Should be added the new dictionary to array. Otherwise it will not add to an array. Every object in array have same dictionary mapping. So it will give you the same dictionary value. Create new dictionary for every object and add to array.
for (int i = 0; i < [sentenceArray count]; i=i+1) {
NSMutableDictionary *clientList = [[NSMutableDictionary alloc]init];
NSString *recordSentence = [sentenceArray objectAtIndex:i];
NSArray *attributes = [recordSentence componentsSeparatedByString:commaDelimiter];
for (int j = 0; j < [attributes count]; j = j+1) {
NSString *pairsOfItems = [attributes objectAtIndex:j];
//a small arry, of only two objects, the first is the key, the second is the object
NSArray *keysAndObjects = [pairsOfItems componentsSeparatedByString:exclamationDelimiter];
[clientList setObject:[keysAndObjects lastObject] forKey:[keysAndObjects firstObject]];
}
[clientListOfDictionaries addObject:clientList];
}

NSThread Causing memory Leaks in iPhone

I am uploading images chunk wise, in a background thread, each chunk will be size of 512kb,to the best of my knowledge,i have taken care of memory leaks using release,nsautoreleasepool.
Below is the code for uploading images chunkwise.
- (void)FetchDataFromDB : (NSNumber *) isOffline
{
#autoreleasepool {
#try {
NSLog(#"FetchDatafromDB");
isThreadStarted = YES;
VYukaDBFunctions *vdb = [VYukaDBFunctions getInstance];
NSMutableArray *fileNames = [vdb GetFileNames:[isOffline integerValue]];
for(int j=0 ; j<[fileNames count] ; j++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString * filename = fileNames [j] ;
int _outgoingMsgId = [[vdb SelectMsgId:filename] intValue];
int _totalchunk =[[vdb SelectTotalChunk:filename]intValue];
int currentChunk = [vdb GetCurrentChunk:filename];
for( int i=currentChunk ; i <= _totalchunk ; i++)
{
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
NSString *AsyncRequest = [[NSString alloc] init];
AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];
if(![AsyncRequest isEqual:#""])
{
BOOL status = [self UploadChunkWise :AsyncRequest : 1 : i : vdb : filename : _outgoingMsgId];
// AsyncRequest = NULL;
// [AsyncRequest release];
if(status){
if(i==_totalchunk)
{
NSLog(#"Deleting from medialist , FileName :%#", filename);
[vdb DeleteFromMediaList : filename];
}
}
else{
[vdb DeleteFromMediaList : filename];
break;
}
}
[innerPool drain];
}
[pool drain];
}
[fileNames removeAllObjects];
// [fileNames release];
//recurssive call to check any pending uploads..
if([[vdb GetFileNames:[isOffline integerValue]] count] > 0)
{
NSLog(#"Calling Recursively..");
[self FetchDataFromDB:[isOffline integerValue]];
}
}
#catch (NSException *exception) {
NSLog(#"Exception caught on Uploading from FetchDataFromDB:%#", exception);
}
#finally {
}
}
NSLog(#"thread quit ");
isThreadStarted = NO;
[NSThread exit];
}
-(BOOL) UploadChunkWise :(NSString *) AsyncRequest : (int) count : (int)currentChunk : (VYukaDBFunctions * ) vdb : (NSString *) currentFileName : (int) outgoingMsgId
{
NSHTTPURLResponse *response ;
NSError *error;
//Yes, http
NSMutableURLRequest *httpRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"Url goes here"]];
NSData* data = [AsyncRequest dataUsingEncoding:NSUTF8StringEncoding];
[httpRequest setHTTPMethod:#"POST"];
[httpRequest setHTTPBody:data];
[httpRequest setValue:#"application/xml" forHTTPHeaderField:#"Content-Type"];
NSData *returnedData = [NSURLConnection sendSynchronousRequest: httpRequest returningResponse:&response error:&error] ;
NSString *result= [[NSString alloc] initWithData:returnedData encoding:NSASCIIStringEncoding];
[httpRequest release];
returnedData= NULL;
[returnedData release];
data = NULL;
[data release];
if ([result rangeOfString:#"success"].location != NSNotFound )
{
NSLog(#" success");
[vdb DeleteCurrentChunkFromOutgoingTable:currentChunk : outgoingMsgId];
[result release];
return YES ;
}
else if ([result rangeOfString:#"fail"].location != NSNotFound )
{
[result release];
if (count < 3) {
return [self UploadChunkWise :AsyncRequest : count+1 : currentChunk: vdb : currentFileName : outgoingMsgId ];
}
else
{
NSLog(#" failed");
[vdb DeleteAllCurrentFileChunksFromOutgoingTable:currentFileName];
return NO ;
}
}
return NO;
}
I am starting thread as below
[NSThread detachNewThreadSelector:#selector(FetchDataFromDB:) toTarget:self withObject:[NSNumber numberWithInt:0]];
The problem is after uploading 9 to 12 chunks, i am getting memory error. i am getting 4 to 5 times memory warning and after that app crashes.in console i am getting memory warning first at app delegate class, followed by 4 classes which are extending UIViewController. why i am getting warning at app delegate, and other classes which is of type UIViewController.Why i have to release object of other class if the separate thread is giving me memory error? what i am doing wrong here? I cannot use ARC, as i have integrated this with old code, which is not using ARC, i tried enabling ARC class wise, but it dint work. Can any one help me to find out if there is any memory leaks in this code. Suggestions are welcomed and appreciated.Thanks in advance..
Two things- first, I see this:
NSString *AsyncRequest = [[NSString alloc] init];
AsyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];
This should be consolidated to this:
NSString *asyncRequest = [vdb SelectAsyncRequest: i : _outgoingMsgId];
You instead are creating a new instance, then immediately either generating or referencing another instance.
Second:
Your code is very hard to read and doesn't follow the Objective-C smalltalk conventions.
Variable names should begin with a lowercase letter. Method names should also start with lowercase letters. Class names and functions should begin with capital letters. It makes it difficult to read because I and many others have been trained to see capital letters and think CLASS NAME instead of POSSIBLE VARIABLE NAME. Just FYI
Finally, some of your methods take multiple parameters, like the one above. You really should add a prefix to each parameter so that it's easy to understand what the parameter is for. This:
[vdb SelectAsyncRequest: PARAMETER : PARAMETER];
would look much better if it was :
[vdb selectAsyncRequestForParameter: PARAMETER withOtherParameter:OTHERPARAM];
EDIT: I also don't think you need so many autorelease pools. The entire thing is wrapped in a big autorelease pool already.
EDIT2: I also see a lot of release calls that aren't necessary. In your UploadChunkWise method you are calling release on *data and *returnedData which are both already implicitly autoreleased. Methods that return objects to you will already have ownership given up and "handed over" to you. Essentially, those methods will do this:
NSData *data = [[NSData alloc] init];
return [data autorelease];
When you get it, if you want to keep it you will have to retain it yourself, otherwise it will be destroyed at the return of your method.
However, it is correct for you to call release on the NSString *result instance you created with -init.

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

Resources