Parse Issue: Expected Expression (Objective C) - objective-c

For what ever reason my xcode has decided it doesn't like me... I'm getting the error stated in the title on this line
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row = [_tableView selectedRow];
if (row == –1) //<---- this line
{
return;
}
NSString *selectedVoice = [_voices objectAtIndex:row];
[_speechSynth setVoice:selectedVoice];
NSLog(#"new voice = %#", selectedVoice);
}
I do believe that it has something to do with _tableView being befuddled because when I attempted to get the IDE to help me to type (you know when it guesses what you might what to finish your word with by doing an API lookup of available functions) it doesn't show selectedRow as a possibility :(
incase it's needed i've put the .m and .h in a pastebin to save some space on your screens... FYI I'm following the Coca Programming for Mac OSX fourth Edition chapter 6.10

In your line
if (row == –1)
the minus-sign is not the real minus-sign, but an "EN DASH" (Unicode U+2013). Perhaps you accidentally pressed the option-key together with the minus-key when typing that code.
Replacing that character with a minus-sign fixes the problem.

UITableView doesn't have a method called selectedRow.
Perhaps you should be using:
- (NSIndexPath *)indexPathForSelectedRow

Related

buttonTitleAtIndex not working with iOS6

I just finished updating an app for support for iPhone 5 and iOS6 and I found an odd bug.
in iOS5 this code works fine, but on every iOS6 device nothing happens when the buttons are pressed and the debugger sees buttonTitleAtIndex:buttonIndex as an unknown method. I made a work around using the actual buttonIndex number instead of the string, but I'm confused why this would happen, as I know of no reason why support for this should change with iOS6.
if([actionSheet buttonTitleAtIndex:buttonIndex] == #"Email to a friend") {
NSLog(#"Email");
[self displayComposerSheet];
}
else if ([actionSheet buttonTitleAtIndex:buttonIndex] == #"Add to Favorites") {
NSLog(#"favorites");
[self addFavorite];
}
else if ([actionSheet buttonTitleAtIndex:buttonIndex] == #"Post to Facebook") {
NSLog(#"Facebook");
[self shareOnFacebook];
}
else if ([actionSheet buttonTitleAtIndex:buttonIndex] == #"Tweet this") {
NSLog(#"tweet");
[self tweet];
}
You cannot compare Objective-C objects by address. == will not work the way you want it to. That it was working for you on iOS 5 was a quirk only, and could change with a simple recompile.
You must use -isEqual: to compare two objects:
if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqual:#"Email to a friend"]) {
...
}
A better approach would be to compare the button index to a known list (an enum for instance, however. This will make localization easier and prevent bugs if you happen to rename a button later.
The following prints correct title for me:
NSLog(#"TITLE: %#", [actionSheet buttonTitleAtIndex: buttonIndex]);
For comparison, do like following:
[[actionSheet buttonTitleAtIndex: buttonIndex] isEqualToString: #"Email to a friend"]
It might be because you are not using isEqualToString. "==" is not really doing a string comparison, it's simply comparing the same spot in memory, which may be the reason it's failing in iOS 6.

populate UITableView

I am struggling with a UITableView that I previously had working and somehow I have broken it!
It is part of a unit in Paul Hegarty's course
The symptom is that the view loads but it is empty. I am clearly misunderstanding something fairly basic.
So far as I understand the two key methods are 1 the section rows count which in my case is returning zero, which I know is wrong!
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// #warning Incomplete method implementation.
// Return the number of rows in the section.
NSLog(#"TopPlaces %#",self.topPlaces);
//return 100;
return [self.topPlaces count];
}
Because of the above the following method is never called because there are no rows.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
And the second is within ViewDidLoad where I can log my data to the console and everything appears fine. i.e. my data is generated within ViewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_queue_t dowloadQueue = dispatch_queue_create("flick downloader", NULL);
dispatch_async(dowloadQueue, ^{
NSArray *topPlaces = [FlickrFetcher topPlaces];
//NSLog(#"Array is %#",topPlaces); // array is OK here
dispatch_async(dispatch_get_main_queue(), ^{
NSSortDescriptor *woeDescriptor = [[NSSortDescriptor alloc] initWithKey:#"_content" ascending:YES];
NSArray *woeDescriptors = #[woeDescriptor];
NSArray *sortedReturns = [topPlaces sortedArrayUsingDescriptors:woeDescriptors];
self.topPlaces = sortedReturns;
//all the data is present here, count is 100 and array will log to console
NSLog(#"count here is %u",[self.topPlaces count]);
});
});
// Uncomment the following line to preserve selection between presentations.
self.clearsSelectionOnViewWillAppear = NO;
}
The problem is that you make an asynchronous call to fetch the data (which means that your array should be full of data at some point in the future), but you do not reload your tableview afterwards. Calling reloadData will do the trick:
...
self.topPlaces = sortedReturns;
//all the data is present here, count is 100 and array will log to console
NSLog(#"count here is %u",[self.topPlaces count]);
[self.tableView reloadData]; // Assuming that 'tableView' is your outlet
This will instruct your tableview to query once again its datasource and will eventually load all the data in your (now non-empty) topPlaces array.
Further Explanation:
I saw in the comment of #nerak99 that he is not completely sure why the problem fixed with reloadData.
Well, let's use an example:
Imagine that you've got a restaurant.
You open the place at 06:00 in the morning and you see that you've got nothing to cook. So you ask from one of your guys to go to the market for supplies (that's your asynchronous call).
At the same time you instruct a waitress to write today's menu, so she writes... well, nothing (that's your tableview asking for number of rows).
Now at 07:00 the guy who went to the market returns with 10 items. What is the next logical step in order to update your menu? To actually inform the waitress (that's your reloadData) about the items you've returned with.
I hope that this makes sense :)
What is self.topPlaces? Try to NSLog the array and see if there's any contents. If not, make sure that it's being set.
I'll be able to write a more specific answer if you provide more info.

Assertion failure in -[UITableView _endCellAnimationsWithContext:]

Hopefully this will be a quick fix. I have been trying to figure out the error that i keep getting. The error is listed below and the appdelagate is below that.
Any help is appreciated.
Thanks
2012-04-12 21:11:52.669 Chanda[75100:f803] --- Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1914.84/UITableView.m:1037
2012-04-12 21:11:52.671 Chanda[75100:f803] --- Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize databaseName,databasePath;
- (BOOL)application: (UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
self.databaseName = #"Customers.db";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [documentPaths objectAtIndex:0];
self.databasePath = [documentDir stringByAppendingPathComponent:self.databaseName];
[self createAndCheckDatabase];
return YES;
}
- (void)createAndCheckDatabase {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:databasePath];
if (success) return;
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:self.databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
}
#end
I don't see the reason for you to show us this part of code. Your error must be connected to this part in your code I assume
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Probably you are making a mistake in one of these data source methods. Currently it's impossible to say what exactly is wrong but I assume it could be something like: You are telling the table view in the numberOfRowsInSection you would like to have n rows reserved and setup and in the cellForRowAtIndexPath you then only handle n - 1 rows for example.
Sorry that this answer can't be as precise as it should be. If you show us your implementation of your data source it would be much easier to tell what's going on.
Like Sun Tzu said: it's best to win without fighting. In my case whenever I see this kind of error message (ie discrepancy between rows added deleted etc).. I don't even debug anything.. I simply avoid making that extra call where I reload the rows etc.. that's 99% of the cases where this error happens.
This is a common scenario where this bug happens: I have a UINavigationController and it has a UITableView, when I click on a row it pushes a new UITableView and so on. This error always happens to me when I pop the last UITableview and go back to the UITableView before it, at this point I make an unnecessary call to the loadIt function which basically inserts the rows and relaods the UITableView.
The reason this happens is because I erroneously place my loadIt function in viewDidAppear:animated rather than viewDidLoad. viewDidAppear:animated is called every time the UITableView is displayed, viewDidLoad is only called once.
When removing rows, remember that it also checks sections when updating, in:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)theTableView
If you want to remove a row that is the last item in a section you need to remove the whole section instead (otherwise it might get section count wrong and throw this exception).
Don't forget to update your array which determines numberOfRowsInSection. It needs to be updated before you animate and remove
We check if number of rows in section is 1 because we will have to delete the entire section.
Do correct me if anyone can make this answer clearer.
[self.tableView beginUpdates];
if ([tableView numberOfRowsInSection:indexPath.section] == 1) {
[tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
} else {
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
[self.tableView endUpdates];
I put each section elements in separated arrays. Then put them into another array( arrayWithArray). My solution here for this problem:
[quarantineMessages removeObject : message];
[_tableView beginUpdates];
if([[arrayWithArray objectAtIndex: indPath.section] count] > 1)
{
[_tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indPath] withRowAnimation:UITableViewRowAnimationBottom];
}
else
{
[_tableView deleteSections:[NSIndexSet indexSetWithIndex:indPath.section]
withRowAnimation:UITableViewRowAnimationFade];
}
[_tableView endUpdates];
I had the same error.
I was using the following lines
UINib *myCustomCellNib = [UINib nibWithNibName:#"CustomNib" bundle:nil];
[tableView registerNib:myCustomCellNib forCellReuseIdentifier:#"CustomNib"];
to register the nib in the viewDidLoad method, since I had a different nib that was also associated with the same class. Hence, the line
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"GBFBLoadingCell"];
was returning nil unless I registered the nib in the viewDidLoad.
My problem was that I forgot to set the identifier in the attributes inspector for my file "CustomNib.xib" and "CustomNib~iphone.xib". (Or more precisely, that I forgot to press enter after typing the identifier in the attribute inspector in XCode, so that the new name failed to save.)
Hope this helps.
If you're using an NSFetchedResultsController like me and updating data in a background thread, don't forget to begin and end updates in the delegate:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
I Had the same error , which when trying with [tableView reloadData] was working fine .
The error was actually in the line
[TabView insertRowsAtIndexPaths:indexPathsArray withRowAnimation:UITableViewRowAnimationRight];
When i tried to check the indexPath values , they weren't correct as required .
I fixed it by changing values in indexPathsArray .
Hope this helps .
Its could be one of UITableViewDataSource protocol methods
For
- tableView:numberOfRowsInSection:
it should return an integer equal to the sum or result of
-insertRowsAtIndexPaths:withRowAnimation: and/or -deleteRowsAtIndexPaths:withRowAnimation:
For
- numberOfSectionsInTableView:
it should return an integer equal to the sum or result of
-insertRowsAtIndexPaths:withRowAnimation: and/or
-deleteSections:withRowAnimation:
I had the same problem with a Core Data base. If your using many FRC, you just need to reload the tableview inside each condition in numberOfSectionsInTableView.
I just had this happen to me while using Swift and a FRC backed data store to manage information. Adding a simple check to the delete operation to evaluate the current indexPath.section allowed me to avoid an extraneous call. I think I understand why this problem occurs... Basically I load a message into the top row whenever my dataset is empty. This creates an off by one issue as there is a faux row.
My Solution
... delete my entity, save the datastore and call reloadData on tableView
//next I add this simple check to avoid calling deleteRows when the system (wrongly) determines that there is no section.
if indexPath.section > 0 {
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .None)
}
Simply check that you call [yourTableView reloadData]; after modify array of values.

XCode 4 Will Not Let Me Add New Methods

I have been working with xcode 4 for a few months now with no problem, well with some problems but that is another story, and now have a weird problem. I can not add any new methods... What I mean to say is when I add a new method xcode doesn't recognize it. The tag follow doesn't see it and the debugger errors saying there is no method by that name. However, the method just above it with the exact same signature minus the name works famously.
Has anyone ever seen this before? If so could you please send me in the right direction. Any help and I would be eternally grateful.
- (void)showMyCalendar:(TKCalendarMonthView*) calendar1
{
if (calendar1.frame.origin.y == -calendar1.frame.size.height+calendarShadowOffset)
{
[self displayCalendar:calendar1];
}
else
{
[self hideCalendar:calendar1];
}
[self showMyCalendar:calendar1]; // If I put a call here xcode sees it.
}
- (void)anotherMethod:(TKCalendarMonthView*) calendar1
{
if (calendar1.frame.origin.y == -calendar1.frame.size.height+calendarShadowOffset)
{
[self displayCalendar:calendar1];
}
else
{
[self hideCalendar:calendar1];
}
[self showMyCalendar:calendar1]; // If I put a call here xcode DOES NOT see it.
}
Thanks,
Ed
Did you include a method definition in your .h file for the .m file that this method is contained in?
- (void)anotherMethod:(TKCalendarMonthView*) calendar1;

Cocoa Touch - Keyboard Capturing

How can I tell what keys the user pressed into a textView?
And before you ask since it sounds similar to a keylogger, I'm making a typing app and I need to know if what they entered of the correct matching key to what they were prompted.
Thanks!
You should set the delegate of the UITextView to one of your classes. (in IB or programmatically, does not matter)
In your delegate, you can put the following function, or something similar:
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text
{
if ( [text length] == 0 ) return YES; // always allow deletion of characters
NSString *new = [textView.text stringByReplacingCharactersInRange:range
withString:text];
if ( [new length] > 100 ) // PUT IN YOUR MAGIC CONDITION HERE
{
return NO; // don't allow the edit to happen
}
return YES; // by default, allow the edit to happen
}
this will only limit input to 100 chars, but you can make it as complicated as you see fit.
edit ps, you asked "what key the user pressed", but since we also have copy&paste and auto-correction, this may give a text which is longer than 1 char!