learning swift by GuidedTour - swift-playground

in this example of GuidedTour of Swift by
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/
var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \( name)"
}
I can not do this experiment, because of error
Change optionalName to nil. What greeting do you get? Add an else clause that sets a different greeting if optionalName is nil.

When I create new playground and enter exactly the same code you posted, it works. Can you post complete code ?
// Playground - noun: a place where people can play
import Foundation
var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \( name)"
}
Only thing which is different, seems that you forgot to import Foundation framework:
import Foundation

var optionalString: String? = "Hello"
print(optionalString == nil)
var optionalName: String? = nil
var greeting = "Hello!"
if let name = optionalName {
greeting = "Hello, \(name)"
}else{
greeting = "Hello Max"
}
greeting

Related

Insert call a method and insert values

I have this working in another programming language, creating a url to reverse geocode a location. I am new to Go and I am slowly working building up the script.
I have the method Geofunction(x,y) with the two variables x & y
From another method I call the above method and supply the values to the variables.
I just can't get it to work as expected.
Could someone point me to where to help me find the answer give me some help on this please.
I have a working coy in Python, as I learn Go I am translating scripts understand.
I have made changes to allow certain variable to accessible to the other functions. I need to understand if the method called with be able to access the variable values.
package main
import "fmt"
var Location1x, Location1y string
var Location1 string
var rev_geo string
func Geofunction(x, y) {
var str1 string = "https://eu1.locationiq.com/v1/reverse.php?key="
var str2 string = "**********************" //API Key
var str3 string = x // '48.853106'
var str4 string = "&lon="
var str5 string = y // '2.384202'
var str6 string = "&format=json"
var rev_geo string = str1 + str2 + str3 + str4 + str5 + str6
return rev_geo
}
func Locator() {
Location1x, Location1y = "48.853106", "2.384202"
Location1 = Geofunction(Location1x, Location1y)
}
func main() {
Locator()
fmt.Println(Location1)
}```
Expected:
A string of a URL is printed.
The three errors are:
main.go:9:18: undefined: x
main.go:9:21: undefined: y
Geofunction(Location1x, Location1y) used as value
Once I get the above sorted, I will then reuse the method to produce multiple strings in an API test that confirms specific data in the json files returned from the server
You are missing a few pieces.
The types for x and y in the function definition are missing. Since the are both strings, the type can be defined simultaneously.
The function GeoFunction is missing a return type, which should be string
Go is quite strict about syntax and structure, unlike Python - I would strongly suggest completing the the Go Tour before transpiling any code, it will make things a lot smoother for you.
Try something like:
package main
import (
"fmt"
)
var Location1x, Location1y string
var Location1 string
var rev_geo string
func Geofunction(x, y string) string {
var str1 string = "https://eu1.locationiq.com/v1/reverse.php?key="
var str2 string = "**********************" //API Key
var str3 string = x // '48.853106'
var str4 string = "&lon="
var str5 string = y // '2.384202'
var str6 string = "&format=json"
var rev_geo string = str1 + str2 + str3 + str4 + str5 + str6
return rev_geo
}
func Locator() {
Location1x, Location1y = "48.853106", "2.384202"
Location1 = Geofunction(Location1x, Location1y)
}
func main() {
Locator()
fmt.Println(Location1)
}
Your method definition is wrong overe here, given go is a statically typed language your function definitions should have the type of the parameters which it takes alongside the parameter names
package main
import "fmt"
var Location1x, Location1y string
var Location1 string
var rev_geo string
func Geofunction(x string, y string) {
var str1 string = "https://eu1.locationiq.com/v1/reverse.php?key="
var str2 string = "**********************" //API Key
var str3 string = x // '48.853106'
var str4 string = "&lon="
var str5 string = y // '2.384202'
var str6 string = "&format=json"
var rev_geo string = str1 + str2 + str3 + str4 + str5 + str6
return rev_geo
}
func Locator() {
Location1x, Location1y = "48.853106", "2.384202"
Location1 = Geofunction(Location1x, Location1y)
}
func main() {
Locator()
fmt.Println(Location1)
}
This should basically work, but a better approach to this would be to use a string builder instead of appending strings. That’s more efficient

Instance member cannot be use on type

#IBAction func saveDetails(sender: AnyObject) {
Person.firstName = firstNameTF.text
Person.lastName = lastNameTF.text
}
Above is the function I am trying to implement and below is the class I am trying to create an instance of and store the data from my text fields in... I am getting the error "Instance member "firstName" cannot be used on type Person". I was almost positive that my class was setup and initialised properly so I can't see what the problem could be?
class Person {
var firstName : String = ""
var middleName : String? = nil
var lastName : String = ""
var yearOfBirth : Int? = nil
var age : Int! {
get {
guard let _ = yearOfBirth else {
return nil
}
return currentYear - yearOfBirth!
}
set {
yearOfBirth = currentYear - newValue
}
}
init(firstName: String, lastName: String, yearOfBirth: Int? = nil, middleName: String? = nil){
self.firstName = firstName
self.lastName = lastName
self.yearOfBirth = yearOfBirth
self.middleName = middleName
}
convenience init(firstName: String, lastName: String, age: Int, middleName: String? = nil) {
self.init(firstName: firstName, lastName: lastName, yearOfBirth: nil, middleName: middleName)
self.age = age
}
}
The error message says you cannot call the properties on the class (type) Person.
Create a Person instance using the given initializer
#IBAction func saveDetails(sender: AnyObject) {
let person = Person(firstName:firstNameTF.text, lastName:lastNameTF.text)
// do something with person
}
You should create an instance of Person in order to set its properties:
either do this:
#IBAction func saveDetails(sender: AnyObject) {
let p = Person(firstName: firstNameTF.text!, lastName: lastNameTF.text!)
}
or add an init method that doesn't take arguments to your Person class
#IBAction func saveDetails(sender: AnyObject) {
let p = Person()
p.firstName = firstNameTF.text!
p.lastName = lastNameTF.text!
}
"Instance member "firstName" cannot be used on type Person" is perfect explanation.
class C {
var s: String = ""
static var s1: String = ""
}
C.s1 = "alfa"
//C.s = "alfa" // error: instance member 's' cannot be used on type 'C'
let c0 = C()
c0.s = "beta"
//c0.s1 = "beta" // error: static member 's1' cannot be used on instance of type 'C'

Digest function equivalent in Swift

I am attempting to write an authenticator app where I use SHA512 and 256 to encrypt some data and then display a number from the processed hashes. I have basically everything figured out and working except for the .digest function. I know how to do it in ruby, given below, but I can't figure out how to get it in iOS.
ruby:
def reset_secret
d = OpenSSL::Digest::SHA512.new
d << reset_sysid
d << 'AAaaAAAaaaAAA'
end
def reset_input(t)
[reset_sysid, email, t].join('|')
end
def reset_hmac(t)
hmac = OpenSSL::Digest::SHA256.new
hmac << reset_secret.digest
hmac << reset_input(t)
hmac.digest
OpenSSL::Digest::SHA256.new(hmac.digest).digest
end
Swift as of now:
func reset_secret()->String {
return (sysid+"AAaaAAAaaaAAA").sha512()
}
func reset_input(t:Int)->String{
var time:String = String(t)
var input:[String] = [sysid, email, time]
var stringrep:String = "|".join(input)
return stringrep
}
func reset_hmac(t:Int)->String{
var firstTime:String = (reset_secret() + reset_input(t)).sha256()
return firstTime
}
extension String {
func sha256() -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
var digest = [UInt8](count:Int(CC_SHA512_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA512(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return "".join(hexBytes)
}
func sha512() -> String {
let data = self.dataUsingEncoding(NSUTF8StringEncoding)!
var digest = [UInt8](count:Int(CC_SHA512_DIGEST_LENGTH), repeatedValue: 0)
CC_SHA512(data.bytes, CC_LONG(data.length), &digest)
let hexBytes = digest.map { String(format: "%02hhx", $0) }
return "".join(hexBytes)
}
To start, I need to get a .digest of the reset_secret() in reset_hmac(), but I haven't seemed to find an equivalent to this in swift

How to remove multiple spaces in Strings with Swift 2

Until Swift 2 I used this extension to remove multiple whitespaces:
func condenseWhitespace() -> String {
let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()).filter({!Swift.isEmpty($0)})
return " ".join(components)
}
but with Swift 2 now I get the error
Cannot invoke 'isEmpty' with an argument list of type '(String)'
How could I now remove multiple spaces with Swift 2?
Thnx!
In Swift 2, join has become joinWithSeparator and you call it on the array.
In filter, isEmpty should be called on the current iteration item $0.
To replace whitespaces and newline characters with unique space characters as in your question:
extension String {
func condenseWhitespace() -> String {
let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
return components.filter { !$0.isEmpty }.joinWithSeparator(" ")
}
}
let result = "Hello World.\nHello!".condenseWhitespace() // "Hello World. Hello!"
Because your function does not take any parameter you could make it a property instead:
extension String {
var condensedWhitespace: String {
let components = self.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
return components.filter { !$0.isEmpty }.joinWithSeparator(" ")
}
}
let result = "Hello World.\nHello!".condensedWhitespace // "Hello World. Hello!"
In Swift 3 there's even more changes.
Function:
extension String {
func condenseWhitespace() -> String {
let components = self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
let result = "Hello World.\nHello!".condenseWhitespace()
Property:
extension String {
var condensedWhitespace: String {
let components = self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
let result = "Hello World.\nHello!".condensedWhitespace
In Swift 4.2 NSCharacterSet is now CharacterSet, and you can omit and use dot syntax:
extension String {
func condenseWhitespace() -> String {
let components = self.components(separatedBy: .whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
let result = "Hello World.\nHello!".condenseWhitespace() // "Hello World. Hello!"
Split string to array and then join again in not memory efficient. Its Takes lot of memory. The best way in this case is to scan the given string and perform operations on that. Regular Expression is the advance way to scan a text. For the above conclusion the the solution is given below:
Swift 4.x
extension String {
func removeExtraSpaces() -> String {
return self.replacingOccurrences(of: "[\\s\n]+", with: " ", options: .regularExpression, range: nil)
}
}
Usages
let startingString = "hello world! \n\n I am here!"
let processedString = startingString.removeExtraSpaces()
print(processedString)
Output:
processedString => "hello world! I am here!"
You can Do more according to your own requirements but thing I am pointing out here is to use regular expressions with string rather then create arrays which will consume lot of memory.
Cleanest version. Documented, memory efficient, extremely easy to use.
extension String {
/// Returns a condensed string, with no extra whitespaces and no new lines.
var condensed: String {
return replacingOccurrences(of: "[\\s\n]+", with: " ", options: .regularExpression, range: nil)
}
/// Returns a condensed string, with no whitespaces at all and no new lines.
var extraCondensed: String {
return replacingOccurrences(of: "[\\s\n]+", with: "", options: .regularExpression, range: nil)
}
}
Usage:
let a = " Hello\n I am a string ".condensed
let b = " Hello\n I am a string ".extraCondensed
Output:
a: "Hello I am a string"
b: "HelloIamastring"
SWIFT 3: Cleaner version
extension String {
var condensedWhitespace: String {
let components = self.components(separatedBy: .whitespacesAndNewlines)
return components.filter { !$0.isEmpty }.joined(separator: " ")
}
}
Here is mine: How it's actually worked.
extension String {
func removeExtraSpaces() -> String {
var data = ""
var numberOfSpace = 0
let items = self.getComponents(separatedBy: " ")
for item in items{
if item == " "{
numberOfSpace = numberOfSpace + 1
}else{
numberOfSpace = 0
}
if numberOfSpace == 1 || numberOfSpace == 0 {
data = data + item
//data.append(item)
}
}
return data
}
}
Usages
var message = "What is the purpose of life?"
message = message.removeExtraSpaces()
print(message)
Output:
What is the purpose of life?
var str = "Hello World.\nHello!"
if let regex = try? NSRegularExpression(pattern: "\\s+", options:NSRegularExpression.Options.caseInsensitive)
{
str = regex.stringByReplacingMatches(in: str, options: [], range: NSMakeRange(0, str.count), withTemplate: " ")
}

How to search for the name and surname using Swift for OS X and avoid duplicate results

I am trying to create a code in Swift for OS X and one of its function is to searches for Address Book entries.
The code bellow finds the entries and works fine with one search term, lets say person's name John. However, if second search term used: i.e. name and surname "John Doe" (space separated) it returns all the matches for the name "John" and all the matches for the surname "Doe".
How to force the code to search for the rest of the string i.e. surname only in the Address Book entries that already matched first part of the sting entered i.e. name?
Searching for John Dow I would like to get John Doe's Address Book entry only and not a list of "John Doe, John Roe, John Moe, Andrew Doe" etc?
Sorry for my English
let addressBook = ABAddressBook.sharedAddressBook()
var dataArray:[NSDictionary] = [["personCell": "", "emailCell": ""]]
var foundPeople = 0
var personNo = 0
var searchString = "John Doe"
func searchAB() -> NSArray {
var mySearchWord = searchString.componentsSeparatedByString(" ")
for word in mySearchWord {
var searchWord = mySearchWord.removeAtIndex(mySearchWord.endIndex.predecessor())
let comparison: ABSearchConjunction = CFIndex(kABContainsSubStringCaseInsensitive.value)
let firstNameSearch = ABPerson.searchElementForProperty(kABFirstNameProperty,
label: nil,
key: nil,
value: searchWord,
comparison: comparison)
let middleNameSearch = ABPerson.searchElementForProperty(kABMiddleNameProperty,
label: nil,
key: nil,
value: searchWord,
comparison: comparison)
let lastNameSearch = ABPerson.searchElementForProperty(kABLastNameProperty,
label: nil,
key: nil,
value: searchWord,
comparison: comparison)
let comparisons = [firstNameSearch, middleNameSearch, lastNameSearch]
let orComparison = ABSearchElement(forConjunction: CFIndex(kABSearchOr.value), children: comparisons)
let found = addressBook.recordsMatchingSearchElement(orComparison) as! [ABRecord]
for person in found {
let firstName = person.valueForProperty(kABFirstNameProperty) as! String? ?? ""
let middleName = person.valueForProperty(kABMiddleNameProperty) as! String? ?? ""
let lastName = person.valueForProperty(kABLastNameProperty) as! String? ?? ""
let emailsProperty = person.valueForProperty(kABEmailProperty) as! ABMultiValue?
foundPeople++
var tmpFirstName = firstName
var booleanFName = tmpFirstName.isEqualToString(firstName)
if let emails = emailsProperty {
for i in 0..<emails.count() {
let email = emails.valueAtIndex(i) as! String
var emailType = ABLocalizedPropertyOrLabel(emails.labelAtIndex(i)) //telefono numerio tipas
if (booleanFName) {
personNo++
if (personNo == 1) { // first person
dataArray = [["personCell": "\(firstName) \(middleName) \(lastName)", "emailCell": "\(email) (\(emailType))"]]
} else {
dataArray += [["personCell": "\(firstName) \(middleName) \(lastName)", "emailCell": "\(email) (\(emailType))"]]
} // end if personNo
println("\n• \(personNo) \(firstName) \(middleName) \(lastName)")
println("\t\t\(email) (\(emailType))")
booleanFName = false
} else {
dataArray += [["emailCell": "\(email) (\(emailType))"]]
println("\t\t\(email) (\(emailType))")
} // end booleanFName
} // end for i
} // end if let emails
} // end for person in found
} // end for word
return dataArray;
} // end func

Resources