Cannot get Length of a NSString - unrecognized selector sent to instance - objective-c

What I'm trying to get is to search for the Anime Titile's ID, compare the length and perform some action afterwards. Here is what I get in the debugger:
2010-08-09 14:30:48.818 MAL Updater OS X[37415:a0f] Detected : Amagami SS - 06
2010-08-09 14:30:48.821 MAL Updater OS X[37415:a0f] http://mal-api.com/anime/search?q=Amagami%20SS
2010-08-09 14:30:49.635 MAL Updater OS X[37415:a0f] 8676
2010-08-09 14:30:49.636 MAL Updater OS X[37415:a0f] -[NSCFNumber length]: unrecognized selector sent to instance 0x384aa40
2010-08-09 14:30:49.637 MAL Updater OS X[37415:a0f] -[NSCFNumber length]: unrecognized selector sent to instance 0x384aa40
The code in question:
if ([self detectmedia] == 1) { // Detects Media from MPlayer via LSOF
NSLog(#"Detected : %# - %#", DetectedTitle, DetectedEpisode);
NSString * AniID = [self searchanime]; // Perform a Search Operation and Returns the ID of the time from JSON
NSLog(#"%#",AniID);
if (AniID.length > 0) { // Compare the length of AniID to make sure it contains a ID
// Other Action here
}
//Release Detected Title and Episode
[DetectedTitle release];
[DetectedEpisode release];
}
SearchAnime method:
-(NSString *)searchanime{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//Escape Search Term
NSString * searchterm = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)DetectedTitle,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8 );
//Set Search API
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://mal-api.com/anime/search?q=%#",searchterm]];
NSLog(#"%#",[NSString stringWithFormat:#"http://mal-api.com/anime/search?q=%#",searchterm]);
//Release searchterm
[searchterm release];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
//Ignore Cookies
[request setUseCookiePersistence:NO];
//Set Token
[request addRequestHeader:#"Authorization" value:[NSString stringWithFormat:#"Basic %#",[defaults objectForKey:#"Base64Token"]]];
//Perform Search
[request startSynchronous];
// Get Status Code
int statusCode = [request responseStatusCode];
NSString *response = [request responseString];
if (statusCode == 200 ) {
return [self RegExSearchTitle:response]; // Returns ID as NSString
}
else {
return #"";
}
}
RegExSearchTitle
-(NSString *)RegExSearchTitle:(NSString *)ResponseData {
OGRegularExpressionMatch *match;
OGRegularExpression *regex;
//Set Detected Anime Title
regex = [OGRegularExpression regularExpressionWithString:DetectedTitle];
NSEnumerator *enumerator;
// Initalize JSON parser
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSArray *searchdata = [parser objectWithString:ResponseData error:nil];
for (id obj in searchdata) {
// Look in every RegEx Entry until the extact title is found.
enumerator = [regex matchEnumeratorInString:[obj objectForKey:#"title"]];
while ((match = [enumerator nextObject]) != nil) {
// Return the AniID for the matched title
return [obj objectForKey:#"id"];
}
}
// Nothing Found, return nothing
return #"";
}
This behavior is unusual because I have compared the NSString's length in the past and it never failed on me. I am wondering, what is causing the problem?

The declared return type of RegExSearchTitle is NSString *, but that doesn’t force the returned object to actually be an NSString. The "id" element of obj (from the JSON) is a number, so an NSNumber is being returned. The compiler can’t warn you about this because it doesn’t know what classes will be found in a collection.
There are other bugs in the code. Having an unconditional return in a while statement in a for statement does not make sense.
On a side note, by convention Objective-C method names start with a lowercase letter.

Well, it's because you assigned an NSNumber to AniID, not an NSString. NSNumber doesn't have a length method.

Related

Strange "zombie" in forwardInvocation: + getArgument:atIndex methods

Here is part from my code:
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect frame = [[UIScreen mainScreen] bounds];
_webView = [[UIWebView alloc] initWithFrame:frame];
[_webView setHidden:NO];
[self.view addSubview:_webView];
_vk = [[DPVkontakteCommunicator alloc] initWithWebView:_webView];
DPVkontakteUserAccount *user;
NSString *accessToken = [[NSUserDefaults standardUserDefaults]
objectForKey:#"accessToken"];
NSInteger userId = [[[NSUserDefaults standardUserDefaults]
objectForKey:#"userId"] integerValue];
user = [[DPVkontakteUserAccount alloc]
initUserAccountWithAccessToken:accessToken
userId:userId];
NSLog(#"%#", user);
[user setSuccessBlock:^(NSDictionary *dictionary)
{
NSLog(#"%#", dictionary);
}];
NSDictionary *options = #{#"uid":#"1"};
// [user usersGetWithCustomOptions:#{#"uid":#"1"}]; // Zombie
[user usersGetWithCustomOptions:options]; // Not zombie
// __block NSDictionary *options = #{};
//
// [_vk startOnCancelBlock:^{
// NSLog(#"Cancel");
// } onErrorBlock:^(NSError *error) {
// NSLog(#"Error: %#", error);
// } onSuccessBlock:^(DPVkontakteUserAccount *account) {
// NSLog(#"account:%#", account);
//
// [account setSuccessBlock:^(NSDictionary *dictionary)
// {
// NSLog(#"%#", dictionary);
// }];
//
// [account docsGetUploadServerWithCustomOptions:options];
// }];
}
and here is the part which processes the userGetWithCustomOptions: method:
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSString *methodName = NSStringFromSelector([anInvocation selector]);
NSDictionary *options;
[anInvocation getArgument:&options
atIndex:2];
NSArray *parts = [self parseMethodName:methodName];
NSString *vkURLMethodSignature = [NSString stringWithFormat:#"%#%#.%#",
kVKONTAKTE_API_URL,
parts[0],
parts[1]];
// appending params to URL
NSMutableString *fullRequestURL = [vkURLMethodSignature mutableCopy];
[fullRequestURL appendString:#"?"];
[options enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)
{
[fullRequestURL appendFormat:#"%#=%#&", key, [obj encodeURL]];
}];
[fullRequestURL appendFormat:#"access_token=%#", _accessToken];
// performing HTTP GET request to vkURLMethodSignature URL
NSURL *url = [NSURL URLWithString:fullRequestURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation;
operation = [AFJSONRequestOperation
JSONRequestOperationWithRequest:urlRequest
success:^(NSURLRequest *request,
NSHTTPURLResponse *response,
id JSON)
{
_successBlock(JSON);
}
failure:^(NSURLRequest *request,
NSHTTPURLResponse *response,
NSError *error,
id JSON)
{
_errorBlock(error);
}];
[operation start];
}
problem is that when I am using "options" variable - it works fine, but when using direct values - it fails, app crashes. Using Profile I have found that method call directs to deallocated object.
Why this happens?
There is no other code that can help.
ViewController.m code: https://gist.github.com/AndrewShmig/5398546
DPVkontakteUserAccount.m: https://gist.github.com/AndrewShmig/5398557
The problem is that the parameter of getArgument: is type void *. And you are passing &value, which is NSDictionary * __strong * (pointer to a strong reference) to it. The cast is valid because it is possible to assign any non-object pointer to and from void * without any warnings.
When you pass a "pointer to strong" to a function, that means the function should expect the pointer to a "strong reference", and when the function exits, it should preserve the fact that the pointer points to a "strong reference". What this means is that if the function changes the reference (pointed to by the pointer), it must first release the previous value and then retain the new value.
However, what does getArgument:atIndex: do with its void * argument? It is agnostic about the thing pointed to, and simply copies the value into the memory pointed to. Therefore, it does not do any of this retain and release stuff. Basically, it performs a plain-old pre-ARC non-retaining assignment into your value variable.
So why is it crashing? What is happening is that value is at first nil, and then inside the getArgument:atIndex:, it assigns the new value into it, but it does not retain it. However, ARC assumes that it has been retained, since value is a strong reference. So at the end of the scope, ARC releases it. This is an over-release, since it was never retained.
The solution is to not pass a "pointer to strong" into getArgument:, because that method does not know anything about "strong". Instead, pass a "pointer to unsafe_unretained" or "pointer to void" into it, and then convert it to a strong reference later:
NSDictionary * __unsafe_unretained temp;
[anInvocation getArgument:&temp atIndex:2];
NSDictionary *options = temp; // or you can just use temp directly if careful
or alternately:
void *temp;
[anInvocation getArgument:&temp atIndex:2];
NSDictionary *options = (__bridge NSDictionary *)temp;

UnitTesting: assertThat arguments incompatible type or pointer to integer without a cast

I am trying to set up my project TDD, so I've got the following unit test:
- (void)testOnDoesUsernameExistsShouldReturnFalseWhenInvalidJSONResponseFromService {
id mock = [OCMockObject partialMockForObject:(NSObject *) (id <ServiceHelperProtocol>) self.serviceHelper];
[[[mock stub] andReturn:#"invalid-json-response"] get:[OCMArg any]];
assertThat([self.signUpService doesUsernameExist:#"testusername"], true);
}
This test runs against this method:
- (BOOL)doesUsernameExist:(NSString *)userName {
NSString *url = [[NSString alloc] initWithFormat:#"%#/%#/api/signup.username_exists/?username=%#", kAPPLICATION_HOST, kAPPLICATION_NAME, userName];
NSString *responseString = [self.serviceHelper get:url];
if (responseString != nil && ![responseString isEqualToString:#""]) {
#try {
NSDictionary *dictionary = [responseString JSONValue]; // auto-released
NSString *usernameExists = [dictionary objectForKey:#"username_exists"];
return usernameExists != nil && ![usernameExists isEqualToString:#"null"];
}
#catch (NSException *e) {
NSLog(#"Unable to parse JSON: %#", e.description);
}
}
[responseString release];
[url release];
return false;
}
When I run this test, I get the following warning on line 94 (the assertThat line):
passing argument 2 of 'HC_assertThatWithLocation' makes pointer from integer without a cast
When I substitute the macro I get this line of code:
HC_assertThatWithLocation(self, [self.signUpService doesUsernameExist:#"testusername"], HC_is(0), "_file_name_", 0);
For some reason my test fails, but I can't figure out what is wrong. Is the test case wrong, is the implemented method wrong or does it has something to do with the OCMock framework in conjunction with the OCHamcrest matchers ?
I'm using Xcode 4.2 with both OCMock 1.66 and OCHamcrest 1.7.
Any thoughts ?

HTTP server works in Cocoa application but not test case -- run loop issue?

I'm trying to add a GHUnit test case to this SimpleHTTPServer example. The example include a Cocoa application that works fine for me. But I can't duplicate the behavior in a test case.
Here is the test class:
#import <GHUnit/GHUnit.h>
#import "SimpleHTTPServer.h"
#interface ServerTest : GHTestCase
{
SimpleHTTPServer *server;
}
#end
#implementation ServerTest
-(void)setUpClass
{
[[NSRunLoop currentRunLoop] run];
}
- (NSString*)requestToURL:(NSString*)urlString error:(NSError**)error
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:1];
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error];
NSString *page = nil;
if (error == nil)
{
NSStringEncoding responseEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)[response textEncodingName]));
page = [[NSString alloc] initWithData:data encoding:responseEncoding];
[page autorelease];
}
return page;
}
- (void)testPortReuse
{
unsigned int port = 50001;
NSError *error = nil;
NSString *path, *url;
server = [[SimpleHTTPServer alloc] initWithTCPPort:port delegate:self];
sleep(10);
path = #"/x/y/z";
url = [NSString stringWithFormat:#"http://localhost:%u%#", port, path];
[self requestToURL:url error:&error];
GHAssertNil(error, #"%# : %#", url, error);
[server release];
}
- (void)processURL:(NSURL *)path connection:(SimpleHTTPConnection *)connection
{
NSLog(#"processURL");
}
- (void)stopProcessing
{
NSLog(#"stopProcessing");
}
#end
I've tried sending requests via NSURLRequest and also (during the sleep) via a web browser. The delegate methods -processURL and -stopProcessing are never called. The problem seems to be that [fileHandle acceptConnectionInBackgroundAndNotify] in SimpleHTTPServer -initWithTCPPort:delegate: is not causing any NSFileHandleConnectionAcceptedNotifications to reach the NSNotificationCenter -- so I suspect a problem involving run loops.
The problem seems to be with the NSFileHandle, not the NSNotificationCenter, because when [nc postNotificationName:NSFileHandleConnectionAcceptedNotification object:nil] is added to the end of initWithTCPPort:delegate:, the NSNotificationCenter does get the notification.
if (error == nil)
That should be:
if (data != nil)
error here is the passed-in pointer to an NSError* - it will only be nil if the caller passed nil instead of a reference to an NSError* object, which isn't what your -testPortReuse method does.
It would also be incorrect to dereference it (as in if (*error == nil)), because error arguments are not guaranteed to be set to nil upon error. The return value indicates an error condition, and the value returned in the error argument is only meaningful or reliable if there is an error. Always check the return value to determine if an error happened, then check the error parameter for details only if something did in fact go wrong.
In other words, as it's written above, your -requestToURL:error: method is incapable of handling success. Much like Charlie Sheen. :-)

Adding Objects from an Array into Core Data

So, for the past two days or so I've been struggling with something that should honestly be a simple task. Here's a little introduction on what I'm trying to achieve.
What I'm doing is utilising a web service of my own, sending a request and parsing the returned JSON with SBJSON. What I know want to accomplish with this parsed JSON is to insert it into Core Data.
I have built a object model already which looks like the following:
#import <CoreData/CoreData.h>
#interface Event : NSManagedObject
{
}
#property (nonatomic, retain) NSString * summary;
#property (nonatomic, retain) NSString * content;
#property (nonatomic, retain) NSDate * updated;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSDate * created;
#property (nonatomic, retain) NSString * ID;
#end
These are all built in regards to what is being parsed, I think I may have to change the NSDate's to NSStrings at a later date, but for now they are NSDates.
So, now to show you what is being parsed. The JSON returns the following.
[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"},
{"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"},
{"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]
What I am wanting to do is create an entity "Event" and each entity stores the respective values for that event. Easy, right? Obviously not for me.
What I have tried...
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
Yet this returns an error.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "title"; desired type = NSString; given type = __NSArrayI; value = (
Car,
"Premium Users",
"Welcome!"
).'
Any ideas or code samples would help. I really need to get this fixed, all dependent on how this is being stored.
EDIT
Here's how we build the request and parse the string returned.
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
EDIT
Just thought I'd let people know that I'm currently using the Resty RESTful framework to make my calls to my own API. I thought this was the best alternative and easiest way for myself to build a wrapper for it. Here is the full request.
Resty documentation.
-(void)pullNotes {
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:url parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NotaciousAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSManagedObject *newNote;
newNote = [NSEntityDescription insertNewObjectForEntityForName:#"Event" inManagedObjectContext:context];
[newNote setValue:[object valueForKey:#"note title"] forKey:#"title"];
[newNote setValue:[object valueForKey:#"note summary"] forKey:#"summary"];
[newNote setValue:[object valueForKey:#"note updated"] forKey:#"updated"];
NSError *error;
[context save:&error];
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
}
}];
}
EDIT
So, now that I have fixed the JSON issue and am grabbing the individual strings and such from each array, I'm having issues storing the parsed strings into Core Data.
I'll show you what I currently have.
[newNote ] is the name given to the Core Data entity in the header file of the following.
-(void)pullNotes {
UIApplication *app = [UIApplication alloc];
app.networkActivityIndicatorVisible = YES;
NSDictionary *params = [NSDictionary dictionaryWithObject:api_key forKey:#"api_key"];
[[LRResty client] get:#"http://notacio.us/api/note" parameters:params withBlock:^(LRRestyResponse *response){
if(response.status == 200) {
NSLog(#"Pulling the users notes \n%#", [response asString]);
// Create SBJSON object to parse JSON
SBJSON *parser = [[SBJSON alloc] init];
// parse the JSON string into an object - assuming [response asString] is a NSString of JSON data
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray *notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
// newNote.created = [singleNote objectForKey:#"note created"]; Need to work on parsing these properly...
// newNote.updated = [singleNote objectForKey:#"note updated"]; Need to work on parsing these properly...
NSString *notetitle = [singleNote objectForKey:#"note title"];
NSString *notesummary = [singleNote objectForKey:#"note summary"];
NSString *noteid = [singleNote objectForKey:#"note id"];
NSString *notecontent = [singleNote objectForKey:#"note content"];
// NSDate *createdDate =
// NSDate *updatedDate =
// If appropriate, configure the new managed object.
[newNote setValue:notetitle forKey:#"title"];
[newNote setValue:notesummary forKey:#"summary"];
[newNote setValue:noteid forKey:#"ID"];
[newNote setValue:notecontent forKey:#"content"];
NSLog(#"value is %#", notetitle);
NSError *error = nil;
if (![newNote.managedObjectContext save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
[tableView reloadData];
app.networkActivityIndicatorVisible = NO;
}
}
if (response.status == 404) {
NSLog(#"FAIL\n%#", [response asString]);
app.networkActivityIndicatorVisible = NO;
}
}];
}
#end
However, running this code doesn't actually store the strings into the Core Data entity. As you can see it isn't finalised, a lot of commented code, but the basis is there. ANYWAY, I'm curious as to whether or not it is how I actually implement this in the pulling of the notes itself from the RootViewController...
In viewDidLoad() I'm calling the following...
ntIndex = [IndexNotes alloc];
ntIndex.api_key = api_key;
ntIndex.tableView = self.tableView;
[ntIndex pullNotes];
[ntIndex release];
[self.tableView reloadData];
}
Any help would be great, I'd love to hear what others think the issue is. I don't get any errors with the above code, just nothing is inserted into the Core Data and in turn isn't displayed in my UITableView in RootViewController...
The first thing I would do is log what this line returns:
[object valueForKey:#"note title"]
You'll find it's not the string you're expecting, but is an array of note titles.
eg:
NSLog(#"value is %#", [object valueForKey:#"note title"]);
Then you'll either need to fix your JSON or change the way you parse it.
Edit:
So when I say fix your JSON, I'm no expert, but I think it should look like this:
{"result":[{"note id":"525","note title":"Car","note summary":"","note content":"","note created":"1297130179","note_updated":"1297233954"}, {"note id":"252","note title":"Premium Users","note summary":"","note content":"","note created":"1296046367","note_updated":"1296699888"}, {"note id":"253","note title":"Welcome!","note summary":"","note content":"","note created":"1296046367","note_updated":"1296561871"}]}
Then:
NSDictionary *object = [parser objectWithString:[response asString] error:nil];
NSArray notes = [object valueForKey:#"result"];
for (NSDictionary *singleNote in notes){
[singleNote objectForKey:"note title"] //this gives you the title of the current note your on
}
It's to do with the fact [object valueForKey:#"note title"] is returning an array.
You'll like want to insert something more like [[object valueForKey:#"note title"] objectAtIndex:1] to take an object out of the array. However working out what index you want to insert from the title array is the hardest part.
Tim
EDIT:
Having looked into some others responses its apparent it's returning all the titles in one object. There's something either incredibly funky going on with your JSON. A way around this would be to possibly for loop over your results set from your JSON request and using the index from this loop to insert the correct title.
eg:
int count;
for (count = 0; count < [[object valueForKey:#"note title"] count]; count++)
{
// Do your other insert stuff here
[newNote setValue:[[object valueForKey:#"note title"] objectAtIndex:count] forKey:#"title"];
}
again this is just a dirty example of what you could possibly do so solve this problem.

ObC : app crashes after returning NSMutableArray?

I am new to ObC and have a problem that i just cant fix. There may be other issues as well but the main issue is this:
Starting the app
Press button = load new view
In the new viewDidLoad i call another object/function and send a NSMutableArray
Process data and send back a NSMutableArray
App crash, see comment where. Most often when i go back and back again but sometimes the first time
As i am new to this i guess i do a lot of this wrong but could someone nice take a look at the code and give me some advice. I would assume i have problem with releasing something.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#" ");
NSLog(#"viewDidLoad ");
NSLog(#" ");
NSLog(#">>Processing prepareGame<<");
NSMutableArray *propArray1 = [[NSMutableArray alloc] initWithObjects:#"9999", nil]; //Init with dummy numbers
AccessPropertiesFile *readMyProperties = [AccessPropertiesFile new]; //Init function call to read file
NSLog(#"Prepare to call readProperties");
propArray1 = [readMyProperties readPropertiesFile:propArray1];
NSLog(#"Back from readProperties:error after this");
/*
for (NSString *element in propArray1) {
NSLog(#"Elements in prop2Array; %#", element);
}
*/
[readMyProperties release];
[propArray1 release];
}
-(NSMutableArray *)readPropertiesFile:(NSMutableArray *)readDataArray {
NSLog(#"Processing readProperties");
// For error information
NSError *error;
//Prepare File Manager
NSString *filePath = [self dataFilePath];
NSFileManager *fileMgr;
fileMgr = [NSFileManager defaultManager];
NSArray *propertiesArray = [NSArray alloc]; //Alloc array
//Check from what module the call is coming from to ecide what to do
if ([fileMgr fileExistsAtPath: filePath] == NO) {
NSLog (#"File not found");
//File does not exists, this is the first time the game starts
//Set up default parameters
NSString *fileString =#"0\n30\n30\n10\n1\n1\n1\n2\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n";
// Write default parameters to file
[fileString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error];
propertiesArray = [fileString componentsSeparatedByString:#"\n"]; // each line, adjust character for line endings
}
else { //File exists
NSLog (#"File exists");
NSString *fileString = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding error:nil]; // reads file into memory as an NSString
propertiesArray = [fileString componentsSeparatedByString:#"\n"]; // each line, adjust character for line endings
}
//Clean readDataArray
[readDataArray removeAllObjects];
//Populate return array
for (NSString *element in propertiesArray) {
//NSLog(#"Elements in propertiesArray; %#", element);
[readDataArray addObject:element];
}
NSLog(#"readDataArray: %#", readDataArray);
[propertiesArray release];
[readDataArray autorelease];
NSLog(#"returning from readProperties");
return readDataArray;
}
#end
You are over-releasing readDataArray (known as propArray1 in the method that didn't create it). You create it and autorelease it in your second method, then you release it again at the end of your first method (where it wasn't created).
I suggest you use Analyze feature that comes with latest XCode. It is a good feature that I always use to track if I forget to release or release too much.
I also spotted that you also over-release the propertiesArray because it contains the result from [fileString componentsSeparatedByString:], which will be autorelease according to Cocoa convention.