Text value of Text Field is Empty Swift - uitextfield

I got a textfield where you need to enter your name in.
But when i try to store the value of the textfield in my array, the value of the text field is always empty.
I declared these IBOutlets
#IBOutlet var input: UITextField
#IBOutlet var error: UILabel
error is a label where I store a error message.
My IBAction when the button is clicked:
#IBAction func btnSave() {
println("Clicked on Save")
println("\(input.text)")
if input.text.isEmpty {
error.text = "Enter a name"
} else {
clNaam.addName(input.text)
self.view.endEditing(true)
error.text = ""
}
}
Everything is hooked up correctly.
This is my class for adding a name.
var clNaam: addNaam = addNaam()
struct naam {
var naam = "Nil"
}
class addNaam: NSObject {
var aNaam = naam[]()
func addName(name: String) {
aNaam.append(naam(naam: name))
}
}
There probably is a problem in my code but I can't find it, I searched on the web and the apple developer site but I can't find what I'm doing wrong.

Related

How to use an array to fill the title text

I've created a customized keyboard using UIView. I'm trying to auto-fill the letters using a for loop but with no success.
func initializeSubviews() {
let xibFileName = "keyboardView" // xib extension not included b
let view = Bundle.main.loadNibNamed(xibFileName, owner: self, options: nil)![0] as! UIView
self.addSubview(view)
view.frame = self.bounds
setKeyboardText()
}
#IBOutlet var keyboardLetters: [myKeyboardBtn]!
func setKeyboardText() {
let str = "abcdefghijklmnopqrstuvwxyz"
let characterArray = Array(str)
for (Index, key) in keyboardLetters.enumerated() {
key.titleLabel?.text = String(characterArray[Index])
}
// [a,b,c,d,...]
}
what am I doing wrong?
According to Apple
"To set the actual text of the label, use setTitle(_:for:)
(button.titleLabel.text does not let you set the text)."

Can't unwrap optional without forced unwrapping/nil error

I'm working on a text editor and am having trouble with string optionals. I want to use a textView's string method; since it's an optional, Xcode insists that I unwrap it. When I use forced unwrapping (which is what Xcode recommends) I get runtime errors; I'd prefer to use optional chaining so that nil values don't cause a crash. But I can't get optional chaining to work.
To get open and save working, I'm trying to use self.textViewOne.string = self.text in windowControllerDidLoadNib and self.text = self.textViewOne.string in dataOfType. But I get crashes of "unexpectedly found nil while unwrapping an Optional value". Documentation tells me I should use if-let or even if-var to do this properly, but I can't; when I try to add if-let or if-var, I get an "Expected pattern" error, probably because the self.text variable already exists - but I don't know how else to unwrap properly.
In dataOfType I even tried to unwrap it with a kludgey regular if-then statement:
if ((self.textViewOne.string) != nil)
{
self.text = self.textViewOne.string
}
else
{
self.text = ""
}
but even that doesn't work: Xcode still insists on a ! after self.textViewOne.string, and with or without the ! I still get a "fatal error: unexpectedly found nil while unwrapping an Optional value".
EDIT: Here's the complete code for the Document class as it currently stands (including a bit of tinkering after the original post, but still getting the error):
import Cocoa
class Document: NSDocument {
#IBOutlet var textViewOne: NSTextView!
#IBOutlet var textViewTwo: NSTextView!
var text = ""
override init() {
super.init()
// Add your subclass-specific initialization here.
}
override func windowControllerDidLoadNib(aController: NSWindowController) {
// The window has loaded, and is ready to display.
// Take the text that we loaded earlier and display it in the text field
super.windowControllerDidLoadNib(aController)
self.textViewOne.string = self.text
}
override class func autosavesInPlace() -> Bool {
return true
}
override var windowNibName: String? {
// Returns the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this property and override -makeWindowControllers instead.
return "Document"
}
override func dataOfType(typeName: String?, error outError: NSErrorPointer) -> NSData? {
// Convert the contents of the text field into data, and return it
if (self.textViewOne == nil)
{
println ("self.textViewOne is nil.")
}
if let someText = self.textViewOne.string {
self.text = someText
} else {
self.text = ""
}
return self.text.dataUsingEncoding( NSUTF8StringEncoding, allowLossyConversion: false)
}
override func readFromData(data: NSData, ofType typeName: String?, error outError: NSErrorPointer) -> Bool {
// Attempt to load a string from the data; if it works, store it in self.text
if data.length > 0
{
let string = NSString( data: data, encoding: NSUTF8StringEncoding)
self.text = string!
}
else
{ self.text = "" }
return true
}
}
What about using an if let to unwrap a non-nil value from self.textViewOne?
if let someText = self.textViewOne.string {
self.text = someText
} else {
self.text = ""
}

Swift2 access component with string-name

Im more familiar with ActionScript3 and see many similarities in Swift2, kind of why i am trying out basic coding in Swift2 and Xcode.
Here's my example:
#IBOutlet weak var b1CurrSpeed: NSTextField!
I want to store b1CurrSpeed as a string so i could access the actual textfield component to set its default value when application is loaded.
I'm aiming for Swift2 for osx apps.
Here is a fictional example, not related to any actual code:
var tf:NSTextField = this.getItem("b1CurrSpeed");
tf.stringValue = "Hello world";
Reason to this approach is following...
I would like to store textfield value in NSUserDefaults, the key for defaults would be name of that textfield. So when looping thru the defaults, i would like to get key as string and when ive got that i'd have access to actual component to set its stringvalue property.
Tho, is that good approach in Swift / xCode ?
If you want to create a function for it, do someting like this:
func getStringForKey(key: String) -> String {
guard let result = NSUserDefaults.standardUserDefaults().objectForKey(key) as! String else { return "" }
return result
}
You can set the TextFields value with myTextField.text
Swift's Mirror type can get you close to it but it is limited to NSObject subclasses, can only access stored properties and is read-only.
Yet, there are ways around these limitations if your requirements will allow.
For example, here's an extension that will save and restore defaults values for all UITextfields on a view controller using the name you gave to each IBOutlet.
extension UIViewController
{
func loadDefaults(userDefaults: NSUserDefaults)
{
for prop in Mirror(reflecting:self).children
{
// add variants for each type/property you want to support
if let field = prop.value as? UITextField,
let name = prop.label
{
if let defaultValue = userDefaults.objectForKey(name) as? String
{ field.text = defaultValue }
}
}
}
func saveDefaults(userDefaults: NSUserDefaults)
{
for prop in Mirror(reflecting:self).children
{
if let field = prop.value as? UITextField,
let name = prop.label
{
if let currentValue = field.text
{ userDefaults.setObject(currentValue, forKey: name) }
}
}
}
}

Edit data in the model according to the user's input in view-based NSTableView

I have a view-based NSTableView where all the cells are editable. I need to refresh the data from the model every time the user modifies a textField from the view.
All the doc I find is related to the cell-based NSTableView.
Does anyone have a clue about this?
EDIT:
I'm using data source to populate this NSTableView.
This is the code of the Controller of the NSTableView
class ViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
#IBOutlet var globalView: NSView!
#IBOutlet var songsTableView: NSTableView!
var tableContents = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
for (song) in songManager.songs {
var obj = Dictionary<String,String>()
obj["title"] = song.title
obj["artist"] = song.artist
tableContents.addObject(obj)
}
songsTableView.reloadData()
}
func numberOfRowsInTableView(tableView: NSTableView) -> Int {
return tableContents.count
}
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView?{
var obj = tableContents[row] as Dictionary<String,String>
let column = tableColumn?.identifier
var cellView = tableView.makeViewWithIdentifier(column!, owner: self) as NSTableCellView
if column == "title" {
cellView.textField?.stringValue = obj["title"]!
}
if column == "artist" {
cellView.textField?.stringValue = obj["artist"]!
}
cellView.textField?.editable = true
return cellView
}
}
And this is the code of the class that manages the data.
var songManager = SongManager()
struct song {
var title = "No name"
var artist = "No artist"
}
class SongManager: NSObject {
var songs = [song]()
func addSong(title: String, artist: String) {
songs.append(song(title: title, artist: artist))
}
}
I have not touched the row that the storyboard creates by default, so I guess it contains a single NSTextField.
I get to display the data, but cannot detect when the user tried to modify a textfield.
Given how things are currently set up, the simplest approach is probably to connect the text field's action selector to an action method on a target, such as your controller. You can do that in IB or in your tableView(_:viewForTableColumn:row:) method.
In that action method, you can call songsTableView.rowForView(sender) to determine which row was edited. Each column's text field would have a different action method, such as changeTitle() or changeArtist(), so that you know which column was edited. (You could also use songsTableView.columnForView(sender), then get the table column by using the index in songsTableView.tableColumns[col], and checking the returned column's identifier. For that, you would assign specific identifiers to the columns rather than letting IB assign them automatically.)
Once you have the row, you look up your dictionary using var obj = tableContents[row] as Dictionary<String,String> and set the value for the key appropriate to the action method (or column identifier) to the sender's stringValue.

Why does this code in Swift produce an empty row on NSTableView?

I'm (obviously) new to Swift, and I'm new to Cocoa programming in general. When I build this code and run it, it automatically inserts an empty row on the NSTableView for peopleList[0], so when I go to add a new person, they show up in the second row, and the first remains empty. I'm at a loss as to why this is. I know I can probably remove the blank row programmatically before inserting the first row of data, but I'd like to know the root cause of this if possible.
Here is my code:
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate, NSTableViewDataSource, NSTableViewDelegate {
#IBOutlet var window: NSWindow
// Table View Outlet
#IBOutlet var tableViewData : NSTableView
// Text Field Cell Outlets
#IBOutlet var firstNameTextField : NSTextField
#IBOutlet var lastNameTextField : NSTextField
#IBOutlet var ageTextField : NSTextField
#IBOutlet var netWorthTextField : NSTextField
// declare an array of multiple dictionaries
var peopleList = [Dictionary <String, String>()]
func applicationDidFinishLaunching(aNotification: NSNotification?) {
// Insert code here to initialize your application
}
func applicationWillTerminate(aNotification: NSNotification?) {
// Insert code here to tear down your application
}
func numberOfRowsInTableView(aTableView: NSTableView!) -> Int
{
let numberOfRows:Int = getDataArray().count
return numberOfRows
}
func tableView(tableView: NSTableView!, objectValueForTableColumn tableColumn: NSTableColumn!, row: Int) -> AnyObject!
{
var newString = getDataArray().objectAtIndex(row).objectForKey(tableColumn.identifier)
return newString;
}
func getDataArray() -> NSArray {
return peopleList
}
// When button is hit, add NSTextField values to array and refresh the tableview
#IBAction func addFieldDataToArray(sender : AnyObject) {
peopleList.append(["FirstName": firstNameTextField.stringValue, "LastName": lastNameTextField.stringValue, "Age": ageTextField.stringValue, "NetWorth": netWorthTextField.stringValue])
println(peopleList)
tableViewData.reloadData()
}
}
This is happening because of the way you're initializing and appending to peopleList. Upon initialization, peopleList is an array of Dictionary<String, String> and contains a single empty dictionary:
> var peopleList = [Dictionary <String, String>()]
[[String : String]] = 1 value {
[0] = {}
}
After adding a person, it looks like this -- you've appended a new person's information, but that empty initial dictionary is still there.
[[String : String]] = 2 values {
[0] = {}
[1] = {
[0] = {
key = "NetWorth"
value = "About 10 bucks"
}
[1] = {
key = "LastName"
value = "Schmoe"
}
[2] = {
key = "Age"
value = "37"
}
[3] = {
key = "FirstName"
value = "Joe"
}
}
}
I'd recommend starting out with peopleList completely empty -- no empty row to worry about:
> var peopleList: [Dictionary<String, String>] = []
[[String : String]] = 0 values

Resources