I'm creating a coffee timer as a learning exercise and I want to have a different menu based on the brewing method selected. I'm storing my settings in NSUserDefaults and populating my tables with two separate arrays that look like this:
var aero = ([
"Cool Down Time Enabled" : true,
"Cool Down Time" : 30,
"Inverted" : true,
"Base Steep Time" : 150,
"Base Inverted Steep Time" : 180,
])
var french = ([
"Cool Down Time Enabled" : true,
"Cool Down Time" : 30,
"Base Steep Time" : 180,
])
I created two UITableViewControllers, one for FrenchPress and one for AeroPress, they are largely the same code:
FrenchPressTableViewController.swift - settings menu
AeroPressTableViewController.swift - settings menu
Both assign values to instances of my Setting.Swift class (gist) and get stored in different arrays.
In IB I started with my french press controller and created two prototype cells and two prototype classes to go along with them.
SwitchCell.Swift - Model for my UISwitch prototype cell outlets
TimingCell.Swift - Models my TimingButton prototype cell outlets
Initial Steps taken:
Create new tableView in IB for my French Press settings.
Create a designated FrenchPressTableViewController, and assign it to my new French Press table view
Set up two new prototype cells and set up IBOutlets/Actions using my SettingCell & TimingCell classes.
The IBOutlets are connected from my FrenchPressTableViewController to my SettingCell.swift (I later reuse these outlets for my Aero settings).
My FrenchPress Settings Works Fine:
So I decided to add my Aero press settings menu using the same process:
Create new tableView in IB
Create a AeroPressTableViewController, and assign it to my new aero table view
Set up two new prototype cells and assign my previously existing SettingCell & TimingCell to the proper cells.
I utilize the outlets that I previously connected to my FrenchPressTableViewController and I connect them to my Aero controller as well to reuse the cell classes.
The final product looks like like this:
But when I run my Aero settings menu, I get the following error:
fatal error: unexpectedly found nil while unwrapping an Optional value
Question:
From what I can tell from my debugger, it looks like my SettingCell class is returning a nil value with cell.switchLabel.text. This doesn't make sense to me since I'm trying to assign a value to it.
Clearly I'm doing something wrong, what is the proper way to reuse my UITableViewCell classes?
This issue arises while registering the UITableViewCell class as tableView.registerClass(SwitchCell.self,forCellReuseIdentifier:"SwitchCell2")
Remove that line tableView.registerClass(SwitchCell.self,forCellReuseIdentifier:"SwitchCell2") and set the cellIdentifier in storyboard..it works
Related
I have a View with 50 checkboxes (NSButton) in a OS X app. I need to access to each one in code, but the only way I find is to create 50 IBOutlet bindings. The IBOutlet collection is not available in OS X. How can I do?
One way to refer to the 50 checkboxes in your ViewController class (I'm assuming that you use view controllers) is by first retrieving the superview that contains each of the 50 checkboxes. This will be an NSView object. To distinguish between the checkboxes I recommend setting different tag values right in interface builder, but it really depends on what you want to do with the checkboxes. Then, you can use a loop to iterate through each of the subviews in this view, like this:
for i in view.subviews.filter({$0 as? NSButton != nil}).map({$0 as! NSButton}) {
if i.bezelStyle == .regularSquare && !(i.cell as! NSButtonCell).imageDimsWhenDisabled {
print(i.title)
}
}
The if condition basically utilizes two properties of checkboxes to distinguish them from any other type of NSButton.
In this example, I simply printed the title of each checkbox. You can use a switch statement if you want to perform different tasks depending on which checkbox it is. The good thing is that with this method you can have infinitely many checkboxes. The iteration order is left to right, top to bottom.
I have a view (created in a StoryBoard) that has a couple of NSTextFields and a slider control. I have one NSTextField that that takes the value of the another NSTextField and a sliderValue.
When I click the "Add" button (which is connected to the add: action of the array controller) all the values are added...except the value in the NSTextField with the "computed value". I can type in that field manually, and it works. Have looked on this site, apple documentation, and general google searches, but I'm not sure why I cannot add this data to the array controller. More details (code)...
NSTextField: Name **Gets added**
SliderValue: Grade **Gets added**
NSTextField: gradebookName **Only adds if manually typed in**
Code:
var txtGradeBookName: String
let sliderValueString = String(sender.integerValue)
txtGradeBookName = txtName.stringValue + "GradeBook" + sliderValueString
gradebookName.stringValue = txtGradeBookName
The ArrayController is bound to a Core Data model. Again, txtName and the Slider value gets added no problem...but gradebookName never gets added (unless I manually type it in)...and it's binding is set up identical to the the other two.
It took me forever to figure out how to set up editing on a custom cell view for an NSTableView. Thanks to StackOverflow I figured that much out. P.S. I was doing all of this in Interface Builder.
I have a single column table in which the cell is a custom multi-control NSTableCellView, with:
name (in bold)
description
detail
It's all text. Set up editability on the name only. The table is sorted by the name.
When I edit the name, it has the effect on the bound model that I expect. The table even re-sorts correctly. However, it's displaying incorrectly. The description and detail (not editable) still show up correctly, but the name (which was edited) is a blank. When I inspect the model, it has the correct updated value. But the cell view itself is incorrect.
This doesn't happen all the time--it typically happens if the cell is re-sorted to the top or bottom of the table, but that may be a red herring and may instead have to do with NSTableView cell caching or something.
I hacked up a workaround in which I assign a delegate to the NSTextField (automatically generated for the NSTableCellView) and intercept the textShouldEndEditing event. For some reason this event is getting triggered twice for a given edit (after I press "enter" in the text field)--once for the actual edit where fieldEditor.string is different from the model name, followed by another event where fieldEditor.string is the same as the model name. If I return false for my textShouldEndEditing handler in the latter case, then the cell contents end up being drawn correctly. That's the hack.
I feel like I'm doing something wrong here though, and that shouldn't be necessary.
Is the textShouldEndEditing event supposed to be fired twice?
My environment:
Mac OS X v 10.10.4
Version 6.4 (6E35b)
My Project:
Mac app using Swift 1.2 with storyboard
A bit of background: I got an NSTableView with multiple columns all hooked into an NSArrayController, which in turn, is hooked up to core data (say entity "Car"). Everything works well - I can load and edit the column values, and save changes to sqlite. All of this is accomplished with bindings via Interface Builder. I now want to add a new "color" column to this table, representing a relationship to another entity, say entity "Color". Each row will have an NSPopUpButton for this new column; the pop-up button should have its values populated from a second NSArrayController linked to the "Color" entity. Thus, "color" is a many-to-one relationship between Car and Color (many Cars can reference a given Color), and I'd like the values in the pop-up button to correspond to the "name" property from Color.
What I've done:
In the storyboard (under the controller scene containing the Car table), I've added a second NSArrayController, "Colors Array Controller":
1) under "Attributes Inspector" -> Mode = Entity Name, Entity Name = Color, "Prepares Content" checkbox selected
2) under "Bindings Inspector" -> Parameters -> Managed Object Context -> "Bind To" checked -> selected "Cars Controller" -> Model Key Path = context
In the Cars table (under NSTableCellView), added an NSPopUpButton.
At this point, everything builds and runs properly, except that all the columns in the table show the "Item 1" default value from the pop-up button (I can also see the other default values when I expand the pop-up).
Now, I've tried the following in a futile attempt to load the pop-up with the correct values:
Strategy 1:
using Interface Builder, selected the NSPopUpButton. Under Bindings Inspector (Value Selection), checked "Bind to" and specified the Colors Array Controller from above; Controller Key -> arrangedObjects; Model Key Path -> name
Strategy 2:
created an IBOutlet, "colorsArray", for "Colors Array Controller" in Cars Controller;
using Interface Builder, selected the NSPopUpButton. Under Bindings Inspector (Value Selection), checked "Bind to" and specified Cars Controller; Model Key Path -> colorsArray.arrangedObjects
For both of the strategies above, whenever I try to run (or just build) the project, Xcode hangs at "Compiling 1 of 1 Storyboard files". Activity Monitor shows that the "ibtoold" process steadily consumes all memory available (as soon as I kill it, Xcode reports my build as failed).
I would really appreciate if somebody could shed some light into what I'm doing wrong, or suggest alternatives to achieve the desired results.
I just ran into the same issue: As soon as I bind a NSPopupButton's content binding to an ArrayController's arrangedObjects Xcode will compile the storyboard forever. When I remove the binding it will compile as usual :(
Since my NSPopupButton is inside a table column, I've removed the array controller and I'm now binding its content directly to a property of the table column's object value.
I'm a very newbie in the obj-c programming and have some troubles trying to change values between two views. I'm using Xcode 4.5 and storyboards and I've some problems with passing a changed value from the second view to the first one.
Here's my 2 very simple views (posting the link as I'm a new user and can't post images):
https://www.dropbox.com/s/q4o2bblu1p57zod/img.png
These views are assigned to the same class (ViewController) and the code I'm using to change the 2 labels is:
-(IBAction)setLabel:(id)sender
{
if (myTextField.text.length != 0) {
myLabel1.text = myTextField.text;
myLabel2.text = myTextField.text;
}
}
The problem is that Label1 changes correctly its text, but there's nothing to do with Label2! It doesn't want to change...
I think I'm trying to do something that can be made in others ways...Can you please tell me if it's correct?
You need to use Protocol-Delegate approach to update content in First view.
I suggest you to visit this sample link.
Your two view controllers may be of the same class but they are going to be different objects at runtime. You have a segue between them and when that executes a new instance will be created. Since the 'label2' of the second instance is not displayed on its screen, your assignment doesn't produce a visible change.