UIPickerView not reloading until scrolling - objective-c

Using a segment control I'm trying to reload 2 UIPickerViews with a new array of data.
My problem is the new array doesn't show until I scroll up or down on the picker (old data will go away once out of view). I've tried using the reloadAllComponents method to no luck. Here is what the code looks like:
//Segment Control
-(IBAction)unitType:(id)sender {
if([sender selectedSegmentIndex]==0){
NSLog(#"unitType change 1");
NSLog(#"before values = %#",units);
[units removeAllObjects];
[units addObject:#"in"];
//etc.
[self.inputUnits reloadAllComponents];
NSLog(#"current values = %#",units);
}else {
NSLog(#"unitType change 2");
NSLog(#"before values = %#",units);
[units removeAllObjects];
[units addObject:#"in^3"];
//etc.
[self.inputUnits reloadAllComponents];
NSLog(#"current values = %#",units);
}
}
IB has 2 UIPickerViews wired up to the file's owner for both delegate and datasource.

You haven't hooked up the UIPickerView to your inputUnits property. Thus, your call to -reloadAllComponents is getting sent to nil, and things are only getting updated when the pickerView wants to show something new (which it does when you scroll).

Related

Setting text and image on NSTableCellView

Hello I'm trying to use an NSTableView in my program and I'm having a problem setting the values for the NSTableCellView and getting them to display in the NSTableView. When I run my program, only blank cells show up. Using NSLog's, I can see that the cell imageView gets set, but doesn't display. When I go to set stringValues for the NSTableCellViews however, I only get null from my NSLog's despite the string containing data. Here's the delegate method I'm having a problem with:
-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSString *cellIdentifier;
NSImageView *pageImageView;
NSString *pageString;
int pageVotes;
if (_connectionArray.count == 0) {
return nil;
}
NSTableCellView *cellView = [[NSTableCellView alloc] init];
if (tableColumn == tableView.tableColumns[0]) {
cellIdentifier = #"firstColumn";
pageImageView = [[_connectionArray objectAtIndex:row] getImage]; //Gets imageView from Page Object
cellView.imageView = pageImageView; //Set image view for cell
NSLog(#"%#", cellView.imageView); //This works
}
if (tableColumn == tableView.tableColumns[1]) {
cellIdentifier = #"secondColumn";
pageString = [[_connectionArray objectAtIndex:row] getTitle];
cellView.textField.stringValue = pageString; //Set text for cell
NSLog(#"%#", cellView.textField.stringValue); //Does not work, returns null
}
if (tableColumn == tableView.tableColumns[2]) {
cellIdentifier = #"thirdColumn";
pageVotes = [[_connectionArray objectAtIndex:row] getVotes];
pageString = [NSString stringWithFormat:#"%i", pageVotes]; //Convert int to string
cellView.textField.stringValue = pageString; //Set text for cell.
NSLog(#"%#", cellView.textField.stringValue); //Does not work, returns null
}
[_tableView makeViewWithIdentifier:cellIdentifier owner:self];
return cellView;
}
I think everything set-up correctly between the Storyboard and the ViewController as well, but I could very well be wrong since this is my first time working with NSTableViews. I've also tried using:
[cellView setImage:pageImageView];
[cellView setTextField:[NSTextField textFieldWithString:pageString]];
but I run into the same issue. If anyone can help I greatly appreciate it! I feel like I'm missing something simple...
Setting the textField and imageView properties of NSTableCellView does not add a text field or an image view to the cell view. Those outlets are just intended to inform the cell view about which of its subviews are the primary text field and/or primary image view. You are still responsible for adding those views to the cell view as subviews or, possibly, as deeper descendant views.
Also, it's a bad idea for your model to vend views. That's not how it should work. Among other things, that will specifically interfere with adding those views to the cell view's subview hierarchy.
It's also strange that you're both creating the cell view and asking the table view to make it (by calling -makeViewWithIdentifier:owner:). Normally, you'd do one or the other, or first try -makeViewWithIdentifier:owner: and only create a view if that fails. And, of course, you wouldn't ignore the return value.
Frankly, the best thing to do is set this all up in Interface Builder. If you do it right, there's no need to implement -tableView:viewForTableColumn:row: at all. Is there a reason you didn't go that route?

MKNetworkKit - displaying cached images

UPDATE AT BOTTOM
I branched off of the MKNetworkKit Flickr demo for this. I have several images on a webserver I want to display in a table. I have a UITableViewCell subclass, ImageCell.
Here is the custom method for retrieving remote images:
-(void)setImageForCell:(NSString *)remoteFileName {
self.loadingImageURLString =
[NSString stringWithFormat:#"http://myserver.com/%#.png",remoteFileName];
self.imageLoadingOperation = [ApplicationDelegate.imageDownloader imageAtURL:[NSURL URLWithString:self.loadingImageURLString]
onCompletion:^(UIImage *fetchedImage, NSURL *url, BOOL isInCache) {
if([self.loadingImageURLString isEqualToString:[url absoluteString]]) {
if (isInCache) {
self.imageView.image = fetchedImage;
[self.contentView drawRect:self.contentView.frame];
NSLog(#"Image is in cache");
} else {
self.imageView.image = fetchedImage;
[self.contentView drawRect:self.contentView.frame];
NSLog(#"Image is not in cache");
}
}
}];
}
//TableView.h
//it is called like this
//in cellForRowAtIndexPath...
ImageCell *cell = (ImageCell *)[tableView dequeue...etc];
MyObject *obj = [dataSource objectAtIndex:indexPath.row];
cell.textLabel.text = obj.name;
[cell setImageForCell:obj.name];
return cell;
I have inspected the contents of my default cache directory, and there are now items inside. Scrolling the table constantly now prints "Image is in cache". The problem is, the cell's imageView never updates. Mugunth has a class method automaticallyNotifiesObserversForKey: but I don't ever see it implemented anywhere. I'm guessing that there's another step involved to tell the tableView instance to update that row with the new contents.
Thanks for your input.
UPDATE
I got this to work by using a custom Interface Builder xib file with a Cell and a UIImageView IBOutlet. Not sure why it wasn't working with self.imageView.image, and would be interested to find out why, exactly. I still consider this an open question because I'd like to just use the standard UITableViewCell class.
I the call to prepareForReuse. Are you setting the self.imageView.image to nil?
If yes, dont do it because it looks like it's never re-initialized.
Why do you call "drawRect" from your code. That's blasphemy!
Inspect your imageView and check if the IB connections are good.

Issue with a checkBox in a viewbased NSTableView

I have an NSDictionary that holds all the data:
One title (not important for this question)
One link (not important for this question)
One array of NSDictionary containing again 1 title and 1 link
I'm displaying this data in a view based table view like this:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tv
{
if (tv == _downloadTable)
//I use this "if" because I have another tableView that has nothing to do
//with this one
{
return [[myDictionary objectForKey:#"myArray"] count];
}
}
I want 2 columns in this tableView, one to display the title and one with a checkbox, that would do something letting me know which row is checked.
- (NSView *)tableView:(NSTableView *)tv viewForTableColumn :(NSTableColumn *)tableColumn row :(NSInteger)row
{
if (tv == _downloadTable)
{
if (tableColumn == _downloadTableTitleColumn)
{
if ([[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"])
{
NSString *title = [[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"];
NSTableCellView *result = [tv makeViewWithIdentifier:tableColumn.identifier owner:self];
result.textField.stringValue = title;
return result;
}
}
if (tableColumn == _downloadTableCheckColumn)
{
NSLog(#"CheckBox"); //I wanted to see exactly when that was called
//But it didn't help me :(
NSButton *button = [[NSButton alloc]init];
[button setButtonType:NSSwitchButton];
[button setTitle:#""];
return button;
}
}
}
Right now when I run it and click on the checkbox it does nothing
(of course because I don't know how to make it do something.
Where should I put the code that should do something?
The main goal is an editable list of downloads, right now the list is displayed, with the checkbox right next to the title at each lines.
I would like to know which checkBox are checked and which are not.
I tried this:
[button setAction:#selector(checkBoxAction:)];
- (void)checkBoxAction: (id)sender
{
NSLog(#"I am button : %# and my state is %ld", sender, (long)[sender state]);
}
But I can't figure out how to get the row of that button, to know which title is associated with this checkBox.
I also tried the setObjectValue method of the tableView without success.
The way I would like it to work is:
I have a "start downloading" button that check if each checkbox is checked or not and launch the next action (downloading) only with the checked row.
I would like to avoid bindings because I plan to make it work on iOS too and I don't want to have different code for iOS.
You can use the NSTableView method -rowForView: to get the row a particular view is in.
In your case you'd have something like this:
- (void)checkBoxAction:(id)sender
{
NSInteger row = [_downloadTable rowForView:sender];
NSLog(#"The button at row %ld was clicked.", row);
}
Here are the docs for NSTableView: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSTableView_Class/Reference/Reference.html
You could try using the button' tag property setting it for each button you place as the number (location) in the tableview. Look here!!!
Detecting which UIButton was pressed in a UITableView
[EDIT1]
If people actually decided to read the linked post you would realize that the answer is actually there.
Try adding:
[button setTag:row];
[button addTarget:self action:#selector(checkBoxAction:) forControlEvents:UIControlEventTouchUpInside];
inside the else of your viewForTableColumn routine:
In your checkBoxAction routine:
- (void)checkBoxAction: (id)sender{
NSLog(#"I am button : %# and my state is %#", sender.tag, [sender state]);
}
I also think that once you begin digging further into your code, you are going to want to start using the auto-dequeuing capability of the TableViewCell objects. I believe that you are going to find yourself in a memory alloc/dealloc problem.

Reload Data in TableView and group

i have a normal table view, and i want to reload the data and make de table separated with groups changing the tableview style to group,i was trying to use the method to give a title for each header its goes ok,but only if i init with it,not for change in runtime, is that possible,or i have to load another view?
-(NSString *) tableView: (UITableView *) tableView titleForHeaderInSection: (NSInteger) section {
if(group){
switch (section) { case 0: return #"A"; break; case 1: return #"B"; break; case 2: return #"C"; break; case 3: return #"D"; break; case 4: return #"E"; break; } }return nil;
}
i try to put a boolean to verify the time to reload data but didnt work....
Well I think tableView:titleForHeaderInSection: only gets called when loading the UITableView or when reloading it. So if you want to change it a runtime, you could have an NSArray that holds the titles for all the headers and have the tableView:titleForHeaderInSection: use that array.
return [YourArray objectAtIndex:section];
And you can modify this array wherever you want in your code. You would have to call [YourTableView reload] anyways to fire up the delegate and get the headers titles updated in your view.
I don't know if you still need the information bellow so I'll leave it here.
To reload a UITableView all you have to do is call [YourTableView reload];.
As for groups, that's a UITableView style. You can modify this either through IB in the Attributes Inspector in Table View > Style > Grouped. Or programmatically using UITableViewStyleGrouped in the TableView's init.
For example:
YourTableViewController *foo = [[YourTableViewController alloc] initWithStyle:UITableViewStyleGrouped];

Save preference to show or hide NSStatusItem

I've got an application which runs as a normal app but also has a NSStausItem.
I wanted to implement the ability to set in the preferences a checkbox and when this checkbox is turned on the status item should be shown, but when the checkbox is off the status item should be removed or be invisible.
I found someone facing a similar problem in a forum here: How do you toggle the status item in the menubar on and off using a checkbox?
But the problem I have with this solution is that it does not work as expected. So I make this checkbox and all works fine, but when I open the application a second time the app does not recognize the choice I took at the first run. This is because the checkbox isn't bound to a BOOL or something, the checkbox only has an IBAction, which removes or adds the status item at runtime.
So my question is: how can I make a checkbox in the preferences which allows me to choose whether the status item should show up or not.
Ok actually i tried the following i copied the from the post i gave you the link
In AppDelegate.h :
NSStatusItem *item;
NSMenu *menu;
IBOutlet NSButton myStatusItemCheckbox;
and then in the Delegate.m :
- (BOOL)createStatusItem
{
NSStatusBar *bar = [NSStatusBar systemStatusBar];
//Replace NSVariableStatusItemLength with NSSquareStatusItemLength if you
//want the item to be square
item = [bar statusItemWithLength:NSVariableStatusItemLength];
if(!item)
return NO;
//As noted in the docs, the item must be retained as the receiver does not
//retain the item, so otherwise will be deallocated
[item retain];
//Set the properties of the item
[item setTitle:#"MenuItem"];
[item setHighlightMode:YES];
//If you want a menu to be shown when the user clicks on the item
[item setMenu:menu]; //Assuming 'menu' is a pointer to an NSMenu instance
return YES;
}
- (void)removeStatusItem
{
NSStatusBar *bar = [NSStatusBar systemStatusBar];
[bar removeStatusItem:item];
[item release];
}
- (IBAction)toggleStatusItem:(id)sender
{
BOOL checked = [sender state];
if(checked) {
BOOL createItem = [self createStatusItem];
if(!createItem) {
//Throw an error
[sender setState:NO];
}
}
else
[self removeStatusItem];
}
then in the IBaction i added this one :
[[NSUserDefaults standardUserDefaults] setInteger:[sender state]
forKey:#"MyApp_ShouldShowStatusItem"];
and in my awakefromnib i added this one : `
NSInteger statusItemState = [[NSUserDefaults standardUserDefaults] integerForKey:#"MyApp_ShouldShowStatusItem"];
[myStatusItemCheckbox setState:statusItemState];
Then in the interface builder i created a new checkbox connected it with "myStatusItemCheckbox" and added an IBaction also i clicked on the bindings inspector and set in the value the following bind to : NSUserDefaultController and as ModelKeyPath i set: MyApp_ShouldShowStatusItem.
Unfortunately this doesnt work at all what am i doing wrong ?
What you need to do is to use the User Defaults system. It makes it very easy to save and load preferences.
In the button's action, you will save its state:
- (IBAction)toggleStatusItem:(id)sender {
// Your existing code...
// A button's state is actually an NSInteger, not a BOOL, but
// you can save it that way if you prefer
[[NSUserDefaults standardUserDefaults] setInteger:[sender state]
forKey:#"MyApp_ShouldShowStatusItem"];
}
and in your app delegate's (or another appropriate object) awakeFromNib, you will read that value back out of the user defaults:
NSInteger statusItemState = [[NSUserDefaults standardUserDefaults] integerForKey:#"MyApp_ShouldShowStatusItem"];
[myStatusItemCheckbox setState:statusItemState];
and then make sure to call removeStatusItem if neccessary.
This procedure will apply to almost any preference you might want to save.