I am writing a basic iOS app to test my Swift knowledge and keep on practicing. In my app the user types a name for a baby, then turns a switch either on or off to set the gender/sex and also change the system color.
After that, the name is used to fill in a UITextView, named "firstWords", in the following block of code:
// Save name entered into text field
#IBAction func saveSettings(_ sender: UIButton) {
nameLabel.text = nameTextField.text
if nameTextField.text == "" {
showMessage()
nameLabel.text = "Baby Name"
}
nameTextField.resignFirstResponder()
let nameHolder: String! = nameLabel.text
if boyGirlSwitch.isOn {
let sex = ("boy", "his", "he", "Boy", "His", "He")
} else {
let sex = ("girl", "her", "she", "Girl", "Her", "She")
}
firstWords.text = "Wow, " + nameHolder + " has so much to look forward to!" + (sex.5) + " will do so many great things!"
}
I keep getting an error at the tuple (sex.5) inside firstWords that says: "Use of unresolved identifier 'sex'"
As I understand it, the constant sex is declared within the if statement and the compiler does go through it either way, so it does get identified and declared.
QUESTION: Why am I getting the error?
Thanks in advance! Here's a screenshot of my code as well:
Screenshot of block of code as described above, including the compiler/build-error
This is a scope issue. sex is only available within the else clause.
You can fix it like this
// Save name entered into text field
#IBAction func saveSettings(_ sender: UIButton) {
nameLabel.text = nameTextField.text
if nameTextField.text == "" {
showMessage()
nameLabel.text = "Baby Name"
}
nameTextField.resignFirstResponder()
let nameHolder: String! = nameLabel.text
var sex : (String, String, String, String, String, String)
if boyGirlSwitch.isOn {
sex = ("boy", "his", "he", "Boy", "His", "He")
} else {
sex = ("girl", "her", "she", "Girl", "Her", "She")
}
firstWords.text = "Wow, " + nameHolder + " has so much to look forward to!" + (sex.5) + " will do so many great things!"
}
this way sex is defined within the scope of the whole IBAction and will be available in the end.
you could also skip one condition if you pre-declare it with a default:
// Save name entered into text field
#IBAction func saveSettings(_ sender: UIButton) {
nameLabel.text = nameTextField.text
if nameTextField.text == "" {
showMessage()
nameLabel.text = "Baby Name"
}
nameTextField.resignFirstResponder()
let nameHolder: String! = nameLabel.text
var sex = ("girl", "her", "she", "Girl", "Her", "She")
if boyGirlSwitch.isOn {
sex = ("boy", "his", "he", "Boy", "His", "He")
}
firstWords.text = "Wow, " + nameHolder + " has so much to look forward to!" + (sex.5) + " will do so many great things!"
}
There is actually a nice article about variable scope on Wikipedia: https://en.wikipedia.org/wiki/Scope_(computer_science)
Related
I have a function that takes in text and checks for the # symbol. The output is the same text, but any words following the # symbol will be coloured, similar to that of a social media mention. The problem is that it adds an extra empty space to the front of the original text. How do I modify the output to remove the empty space it adds to the front of the new text?
func textWithHashtags(_ text: String, color: Color) -> Text {
let words = text.split(separator: " ")
var output: Text = Text("")
for word in words {
if word.hasPrefix("#") { // Pick out hash in words
output = output + Text(" ") + Text(String(word))
.foregroundColor(color) // Add custom styling here
} else {
output = output + Text(" ") + Text(String(word))
}
}
return output
}
Just call the function in a view like
textWithHashtags("Hello #stackoverflow how is it going?", color: .red)
try something like this:
func textWithHashtags(_ text: String, color: Color) -> Text {
let words = text.split(separator: " ")
var output: Text = Text("")
var firstWord = true // <-- here
for word in words {
let spacer = Text(firstWord ? "" : " ") // <-- here
if word.hasPrefix("#") { // Pick out hash in words
output = output + spacer + Text(String(word))
.foregroundColor(color) // Add custom styling here
} else {
output = output + spacer + Text(String(word))
}
firstWord = false
}
return output
}
I having this problem when I inserting data row and the result comes out 'SUCCESS'. But when I print out the table, something like below came out. I have been trying on this for days but couldn't figure out where whet wrong.
Logs:
Successfully inserted row. >> aaa sss ddd fff
Successfully inserted row. >> zzz xxx ccc vvv
Successfully inserted row. >> 9999999 00000000 aaaaaaa bbbbbbbbbbbbb
Successfully inserted row. >> ccccccccccccc ddddddddddd eeeeeeeeeeee fffffffffffffffff
Successfully inserted row. >> gggggggggggg hhhhhhhhhhhh iiiiiiiiiiiii jjjjjjjjjjjjjj
Successfully inserted row. >> kkkkkkkkkkk LLLLLLLLLL mmmmmmmm nnnnnnnnnnnnn
Query Result= id:1 msgID:fff loginID:fff conversationID:fff userID:fff
Query Result= id:2 msgID:vvv loginID:vvv conversationID:vvv userID:vvv
Query Result= id:3 msgID:bbbbbbb loginID:bbbbbbb conversationID:bbbbbbbb userID:bbbbbbbbbbbbb
Query Result= id:4 msgID:ddddddddddd loginID:ddddddddddd conversationID:ddddddddddd userID:fffffffffffffffff
Query Result= id:5 msgID:jjjjjjjjjjjjj loginID:jjjjjjjjjjjj conversationID:jjjjjjjjjjjj userID:jjjjjjjjjjjjjj
Query Result= id:6 msgID:nnnnnnnn loginID:nnnnnnnnnnn conversationID:nnnnnnnnnn userID:nnnnnnnnnnnnn
I'm sure the database connection is fine, but it just came out wrong. I even checked if my parameters are input correctly.
When I call my function:
DB_Handler.add_msgstatus(loginID: "aaa", conversationID: "sss", msgID: "ddd", userID: "fff")
DB_Handler.add_msgstatus(loginID: "zzz", conversationID: "xxx", msgID: "ccc", userID: "vvv")
DB_Handler.add_msgstatus(loginID: "9999999", conversationID: "00000000", msgID: "aaaaaaa", userID: "bbbbbbbbbbbbb")
DB_Handler.add_msgstatus(loginID: "ccccccccccccc", conversationID: "ddddddddddd", msgID: "eeeeeeeeeeee", userID: "fffffffffffffffff")
DB_Handler.add_msgstatus(loginID: "gggggggggggg", conversationID: "hhhhhhhhhhhh", msgID: "iiiiiiiiiiiii", userID: "jjjjjjjjjjjjjj")
DB_Handler.add_msgstatus(loginID: "kkkkkkkkkkk", conversationID: "LLLLLLLLLL", msgID: "mmmmmmmm", userID: "nnnnnnnnnnnnn")
DB_Handler.getAllMsgStatusInfo()
My insert row function:
static func add_msgstatus(loginID: String, conversationID: String, msgID: String, userID: String) {
let queryString = "INSERT INTO msgstatus_tbl (id, msg_id, login_id, conversation_id, user_id) VALUES (null, ?, ?, ?, ?);"
var preparedStmt: OpaquePointer? = nil
if sqlite3_prepare(db, queryString, -1, &preparedStmt, nil) == SQLITE_OK {
sqlite3_bind_text(preparedStmt, 1, msgID, -1, nil)
sqlite3_bind_text(preparedStmt, 2, loginID, -1, nil)
sqlite3_bind_text(preparedStmt, 3, conversationID, -1, nil)
sqlite3_bind_text(preparedStmt, 4, userID, -1, nil)
if sqlite3_step(preparedStmt) == SQLITE_DONE {
print("Successfully inserted row. >> \(loginID) \(conversationID) \(msgID) \(userID)")
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Fail to insert row. \(errorMessage)")
}
sqlite3_finalize(preparedStmt)
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Unable to prepare statement. \(errorMessage)")
}
}
My table:
static func create_msgstatus_tbl() {
let queryString = "CREATE TABLE IF NOT EXISTS msgstatus_tbl (id INTEGER PRIMARY KEY, msg_id VARCHAR(255), login_id VARCHAR(255), conversation_id VARCHAR(255), user_id VARCHAR(255));"
var preparedStmt: OpaquePointer? = nil
if sqlite3_prepare_v2(db, queryString, -1, &preparedStmt, nil) == SQLITE_OK {
if sqlite3_step(preparedStmt) == SQLITE_DONE {
print("Table (msgstatus_tbl) exists/ created.")
} else {
print("Table (msgstatus_tbl) could not be created.")
}
sqlite3_finalize(preparedStmt)
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Unable to prepare statement. \(errorMessage)")
}
}
My retrieve data function:
static func getAllMsgStatusInfo() {
let queryString = "SELECT * FROM msgstatus_tbl;"
var preparedStmt: OpaquePointer? = nil
if sqlite3_prepare_v2(db, queryString, -1, &preparedStmt, nil) == SQLITE_OK {
var msgID = ""
var loginID = ""
var conversationID = ""
var userID = ""
var id = ""
while (sqlite3_step(preparedStmt) == SQLITE_ROW) {
id = String(cString: sqlite3_column_text(preparedStmt, 0))
msgID = String(cString: sqlite3_column_text(preparedStmt, 1))
loginID = String(cString: sqlite3_column_text(preparedStmt, 2))
conversationID = String(cString: sqlite3_column_text(preparedStmt, 3))
userID = String(cString: sqlite3_column_text(preparedStmt, 4))
print("Query Result= id:\(id) msgID:\(msgID) loginID:\(loginID) conversationID:\(conversationID) userID:\(userID)")
}
sqlite3_finalize(preparedStmt)
} else {
let errorMessage = String.init(cString: sqlite3_errmsg(db))
print("Unable to prepare statement. \(errorMessage)")
}
}
You need to do one thing.
When you use sqlite3_bind_text(preparedStmt, 1, msgID, -1, nil) then just follow these following steps -:
let msgId = msgID as NSString
sqlite3_bind_text(preparedStmt, 1, msgId.utf8String, -1, nil)
Do these same things for all your next sqlite3_bind_text statement as mentioned in your code.
I also faced same problem like you. And it is working now for me. I hope it will work for you.
I want to receive some text that has been inputted by the user on an Apple Watch. This is what I have so far:
presentTextInputController(withSuggestions: ["Michael","David","John","Lisa","Mary","Susan","Matthew","James","Jessica","Jennifer","Amanda","Emily","Dylan","Ross","Rupert"], allowedInputMode: WKTextInputMode.plain) { (arr: [Any]?) in
playerNames.playerOne = String(describing: arr)
print(playerNames.playerOne)
}
This always returns a optional like Optional([Michael])
I want it to return Michael
I have looked around about optionals but can't seem to find an anwser.
You can try this code:
let suggestions = ["Michael", "David", "John", "Lisa", "Mary", "Susan", "Matthew", "James", "Jessica", "Jennifer", "Amanda", "Emily", "Dylan", "Ross", "Rupert"]
presentTextInputController(withSuggestions: suggestions, allowedInputMode: WKTextInputMode.plain) { (arr: [Any]?) in
guard let arr = arr, let firstElement = arr.first as? String else { return }
playerNames.playerOne = firstElement
print(playerNames.playerOne)
}
Here are some documents you can refer to: Optional Binding, Guard Statement.
I am learning to use predicates for filtering. I found a tutorial, but one aspect is not working for me in Swift 3. Here is some specific code:
let ageIs33Predicate01 = NSPredicate(format: "age = 33") //THIS WORKS
let ageIs33Predicate02 = NSPredicate(format: "%K = 33", "age") //THIS WORKS
let ageIs33Predicate03 = NSPredicate(format: "%K = %#", "age","33") //THIS DOESN'T WORK
let ageIs33Predicate04 = NSPredicate(format: "age = %#","33") //THIS DOESN'T WORK
All 4 compile, but the last 2 produce no results even though I have a case where age = 33. Here is the test complete test code from the tutorial:
import Foundation
class Person: NSObject {
let firstName: String
let lastName: String
let age: Int
init(firstName: String, lastName: String, age: Int) {
self.firstName = firstName
self.lastName = lastName
self.age = age
}
override var description: String {
return "\(firstName) \(lastName)"
}
}
let alice = Person(firstName: "Alice", lastName: "Smith", age: 24)
let bob = Person(firstName: "Bob", lastName: "Jones", age: 27)
let charlie = Person(firstName: "Charlie", lastName: "Smith", age: 33)
let quentin = Person(firstName: "Quentin", lastName: "Alberts", age: 31)
let people = [alice, bob, charlie, quentin]
let ageIs33Predicate01 = NSPredicate(format: "age = 33")
let ageIs33Predicate02 = NSPredicate(format: "%K = 33", "age")
let ageIs33Predicate03 = NSPredicate(format: "%K = %#", "age","33")
let ageIs33Predicate04 = NSPredicate(format: "age = %#","33")
(people as NSArray).filtered(using: ageIs33Predicate01)
// ["Charlie Smith"]
(people as NSArray).filtered(using: ageIs33Predicate02)
// ["Charlie Smith"]
(people as NSArray).filtered(using: ageIs33Predicate03)
// []
(people as NSArray).filtered(using: ageIs33Predicate04)
// []
What am I doing wrong? Thanks.
Why would the last two work? You are passing a String in for an Int property. You need to pass in an Int to compare against the Int property.
Change the last two to:
let ageIs33Predicate03 = NSPredicate(format: "%K = %d", "age", 33)
let ageIs33Predicate04 = NSPredicate(format: "age = %d", 33)
Note the change in the format specifier from %# to %d.
In Swift on OS X I am trying to chop up the string "abc1.23.456.7890xyz" into these strings:
"abc"
"1"
"23"
"456"
"7890"
"xyz"
but when I run the following code I get the following:
=> "abc1.23.456.7890xyz"
(0,3) -> "abc"
(3,1) -> "1"
(12,4) -> "7890"
(16,3) -> "xyz"
which means that the application correctly found "abc", the first token "1", but then the next token found is "7890" (missing out "23" and "456") followed by "xyz".
Can anyone see how the code can be changed to find ALL of the strings (including "23" and "456")?
Many thanks in advance.
import Foundation
import XCTest
public
class StackOverflowTest: XCTestCase {
public
func testRegex() {
do {
let patternString = "([^0-9]*)([0-9]+)(?:\\.([0-9]+))*([^0-9]*)"
let regex = try NSRegularExpression(pattern: patternString, options: [])
let string = "abc1.23.456.7890xyz"
print("=> \"\(string)\"")
let range = NSMakeRange(0, string.characters.count)
regex.enumerateMatchesInString(string, options: [], range: range) {
(textCheckingResult, _, _) in
if let textCheckingResult = textCheckingResult {
for nsRangeIndex in 1 ..< textCheckingResult.numberOfRanges {
let nsRange = textCheckingResult.rangeAtIndex(nsRangeIndex)
let location = nsRange.location
if location < Int.max {
let startIndex = string.startIndex.advancedBy(location)
let endIndex = startIndex.advancedBy(nsRange.length)
let value = string[startIndex ..< endIndex]
print("\(nsRange) -> \"\(value)\"")
}
}
}
}
} catch {
}
}
}
It's all about your regex pattern. You want to find a series of contiguous letters or digits. Try this pattern instead:
let patternString = "([a-zA-Z]+|\\d+)"
alternative 'Swifty' way
let str = "abc1.23.456.7890xyz"
let chars = str.characters.map{ $0 }
enum CharType {
case Number
case Alpha
init(c: Character) {
self = .Alpha
if isNumber(c) {
self = .Number
}
}
func isNumber(c: Character)->Bool {
return "1234567890".characters.map{ $0 }.contains(c)
}
}
var tmp = ""
tmp.append(chars[0])
var type = CharType(c: chars[0])
for i in 1..<chars.count {
let c = CharType(c: chars[i])
if c != type {
tmp.append(Character("."))
}
tmp.append(chars[i])
type = c
}
tmp.characters.split(".", maxSplit: Int.max, allowEmptySlices: false).map(String.init)
// ["abc", "1", "23", "456", "7890", "xyz"]