I keep getting this break point appear on my project which then causes the app to stop running.
It doesn't break in the thread results it seems to break on this line:
[urlString appendString: [URLQueryGenerator createSearchURL]];
The method that that line of code is in is as follows:
- (void)loadData {
[_appDelegate reloadFavourites];
if (_appDelegate.properties.count < 1) {
//Reset Results page number to one. Because the results are starting afresh.
[self setCurrentSearchPage:1];
[self.navigationItem setTitle:NSLocalizedString(#"Search Results", nil) ];
//Create URL String
NSMutableString *urlString = [[NSMutableString alloc] initWithString: #""];
[urlString appendString: [URLQueryGenerator createSearchURL]];
NSLog(#"%#", urlString);
[xmlParser parseXMLPage:urlString withDelegate:self];
[v_loadingView setHidden:NO];
//Do not release Parser here, released in dealloc()
//[xmlParser release];
}
else
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
[self loadCells];
else
[table reloadData];
}
}
I have put a break point on the search button that i have which then takes me to the results page to see if i could debug whats happening but its not giving a clear indication as to why i keep getting this error.
I have tried enabling zombie Object on the project but this still doesn't give me any indication.
Its really bugging me because i don't know how i can debug it well enough to find out why its doing this!
Can any one help please?
Related
I'm developing a native application for a website. The application is basically a wrapper around the website, which implements things like push notifications. When a push notification is clicked, the following code is used to go to the appropriate page:
- (NSString *)handlePush:(NSDictionary *)notification
{
if ([[notification objectForKey:#"aps"] objectForKey:#"badge"]) {
int badgeNum = [[[notification objectForKey:#"aps"] objectForKey:#"badge"] integerValue];
NSLog(#"Badge: %i, got from %#", badgeNum, [[notification objectForKey:#"aps"] objectForKey:#"badge"]);
[UIApplication sharedApplication].applicationIconBadgeNumber = badgeNum;
}
if (!active) {
NSLog(#"Got noti while not active, going to that chat!");
NSString *hash;
if ((hash = [notification objectForKey:#"h"])) {
NSLog(#"Hash: %#", [hash stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]);
return [NSString stringWithFormat:#"#%#", hash];
}
return #"";
}
return nil;
}
Active is changed when the application enters the background and after it resumes, to make sure it does not trigger when a push notification arrives when the user is using the app.
The URL is parsed properly, because if i manually paste the exact same URL in the browser, i do go to the correct page.
I am 100% certain the delegate is set, as the UIWebView: ShouldStartLoadWithRequest method is called:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *url = [[request URL] absoluteString];
NSLog(#"shouldStartLoadWithRequest called with url %#", url);
if ([url hasPrefix:BASE_URL]) {
NSLog(#"Yea, i'll load this one for ya");
// remove any get-params / hash suffix
NSRange r = [url rangeOfString:#"?"];
if (r.location == NSNotFound)
r = [url rangeOfString:#"#"];
if (r.location != NSNotFound)
url = [url substringToIndex:r.location];
if (![url isEqualToString:[defaults valueForKey:#"baseUrl"]]) {
NSLog(#"setting new baseUrl %#", url);
[defaults setValue:url forKey:#"baseUrl"];
[defaults synchronize];
}
NSLog(#"Should go and load it now...");
return YES;
}
}
There's some logic for caching versions of the webpage in there. I stepped through with breakpoints, and it reaches the return YES part, and the logs in there are called. However, in that same delegate, the didStartLoad and didFailLoadWithError are not called, which contain purely NSLogs.
On the initial application start, this does work, and it has worded one time too where i stepped through for a long time using the breakpoint, so it seems it's some timing issue. Hoping not having to use any hacky solutions like timers, i was hoping that anyone around here has experience with a similar problem, or has any other valuable input.
I have a viewController in an app that retrieves Data from JSON, parses it and populates in UITableView. I am using thread to load data so that app does not hang when it is retrieving data.
Problem:
numberOfRowsInSection returns 0 and UITableView does not get populated sometimes when app is started. While sometimes, everything works fine. It is all random :S
Possible Explanation:
The problem is, it seems like, sometimes numberOfRowsInSection is called before data is retrieved. numberOfRowsInSection returns the value of count of a NSMutableArray called 'subjects'. Objects in 'subjects' are added when loadData is called. So the numberOfRowsInSection should return the count of 'subjects' and it should not be called after 'subjects' is populated.
Sometimes when I start the app, numberOfRowsInSection is called after 'subjects' is populated and UITableView shows data but sometimes when I start the app, numberOfRowsInSection is called before 'subjects' is populated and UITableView shows no data.
Code:
Here is my code:
-(void)loadData:(id)sender
{
dispatch_queue_t getRemindersQueue=dispatch_queue_create("reminders JSON downloader with reload Button", NULL);
dispatch_async(getRemindersQueue, ^{
[self getReminders];
dispatch_async(dispatch_get_main_queue(), ^{
self.navigationItem.rightBarButtonItem=sender;
[self.tableView reloadData];
});
});
dispatch_release(getRemindersQueue);
}
-(void)getReminders
{
NSURL * aURL = [NSURL URLWithString: #"http://www.merrycode.com/apps/IELTS/RemindersJSON"];
NSURLRequest *request = [NSURLRequest requestWithURL:aURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];
NSError *responseError=nil;
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&responseError];
if(responseError)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *parsingError = [[UIAlertView alloc] initWithTitle:#"Network Error"
message:#"Can not reach the servers. Make sure you are connected to the internet."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[parsingError show];
});
return;
}
NSString *str = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(#" String of Reminders JSON: %#",str);
NSString *newStr= [self stringByRemovingControlCharacters:str];
response = [newStr dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonParsingError = nil;
NSArray *publicTimeline = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
NSLog(#"%#", jsonParsingError);
NSLog(#" publicTimeline Array Count: %d", [publicTimeline count]);
if([publicTimeline count] == 0)
{
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *parsingError = [[UIAlertView alloc] initWithTitle:#"Error Retriving Data"
message:#"There was an error reciving data from the server."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[parsingError show];
});
return;
}
NSDictionary *colleges;
for(int i=0; i<[publicTimeline count];i++)
{
colleges= [publicTimeline objectAtIndex:i];
NSLog(#"Reminders: %#", [colleges objectForKey:#"title"]);
[self.subjects addObject:[colleges objectForKey:#"title"]];
[self.dates addObject:[colleges objectForKey:#"date"]];
[self.description addObject:[colleges objectForKey:#"desc"]];
}
[self.subjectsInNSUserDefaults removeAllObjects];
[self.datesInNSUserDefaults removeAllObjects];
[self.descriptionInNSUserDefaults removeAllObjects];
[self.userDefaults setObject:self.subjects forKey:#"SUBJECTS"];
[self.userDefaults setObject:self.dates forKey:#"DATES"];
[self.userDefaults setObject:self.description forKey:#"DESCRIPTION"];
[self.userDefaults synchronize];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Array Count in numberOfRowsInSection: %d",[self.subjects count]);
return [self.subjects count];
}
Couple of ideas...
You said this is a UIViewController (as opposed to UITableViewController). How are you setting up your UITableView and the delegate? If you are still setting up your UITableView or its delegates while this background thread is running, it is theoretically possible that the background thread could complete before you are done setting up your UITableView, which could create strange issues (and explain why this happens "randomly").
Also, have you checked to make sure your response object is populated with information about colleges in the cases where your UITableView isn't getting populated (and not some sort of other response, or no response at all)? I see where you are checking for response errors, but you seem to assume that if there isn't an error, it will be a response with information about colleges (which may or may not be a safe assumption).
If you're correct about the data retrieval being the problem, then I have also had this problem. My inelegant solution was just to set a timer to populate the table at a time when I knew the data would be loaded.
Should I check if a file exists at a given path when trying to read the data into an NSData object? Right now I'm not doing at the moment but my code works since my array that is supposed to get populated with data from the file will be set to nil and I can later in my application check if that array is nil. But I'm thinking that the code is perhaps "ugly" and would work better if i did a check (like the one in the commented code).
NSData *codedData = [[NSData alloc] initWithContentsOfFile:[CareersParser dataFilePath]];
/*
if (codedData != nil) {
//do the below (not commented out code)
} else {
//file doesn't exist at the given path
[codedData release];
return nil;
}
*/
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData];
NSArray *careers = [unarchiver decodeObjectForKey:kDataKey];
[unarchiver finishDecoding];
NSMutableArray *ids = [[NSMutableArray alloc] init];
for (Career *career in careers) {
[ids addObject:[career id]];
}
// Sort the array in an orderly fashion
NSArray *sortedIds = [ids sortedArrayUsingSelector:#selector(caseInsensitiveCompare:)];
// Release allocated memory
[ids release];
[unarchiver release];
[codedData release];
return sortedIds;
That seems sensible to me I would reverse the if statement to do away with the else clause.
if (nil == codedDate) {
[codedData release];
return nil;
}
... Do the rest of your code
Apple suggests here that you should attempt to perform an operation such as loading data like you have suggested. As long as you don't try to do [[NSManager defaultManager] fileExistsAtPath:path] you won't be introducing race conditions.
You don't, and this could introduce a race, so it will be more "ugly". Just check if codedData if nil in case of reading failure.
I have some code implemented in my myDocument.m file that simply attempts to load the last used document upon launch. However, upon launching from a fresh install, (or running after deleting the last used file) a 'new' document window does not appear. Does anyone know what to add to my code to do this? Here it is:
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
{
NSURL *lastURL=[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:lastURL display:YES error:nil];
if (lastURL!=nil)
{
[docController openDocumentWithContentsOfURL:lastURL display:YES error:nil];
return NO;
}
return YES;
}
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
{
NSArray* urls = [[NSDocumentController sharedDocumentController] recentDocumentURLs];
if ([urls count] > 0){
NSURL *lastURL= [urls objectAtIndex: 0];
if ([[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:lastURL display:YES error:nil]){
return NO;
}
}
return YES;
}
EDIT
I changed it and tried it out it should work now.
What is docController, and why are you sending -openDocumentWithContentsOfURL:display:error: twice? Note that that method returns a document, not a URL, so using the return value as a URL wouldn’t work anyway.
The following is a cleaner, equivalent code:
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
{
id lastDoc = [[NSDocumentController sharedDocumentController]
openDocumentWithContentsOfURL:lastURL
display:YES error:NULL];
return (lastDoc == nil);
}
However, it still doesn’t explain why you don’t get an untitled document. What happens if you comment out -applicationShouldOpenUntitledFile: so that the application follows standard Cocoa behaviour? It could be the case that the problem lies elsewhere.
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.