对照网站,从基础学起,这里记录一下有一些其他语言没遇到过的知识
教程地址 https://www.hackingwithswift.com/100
基本上代码都来自教程,为了适合我复习改了少少。
此文对应教程中 day1-day12,day13-day15没有新内容,也算在这里啦
一、变量(Variable)
1、声明多行字符串
var burns = """
The best laid schemes
o'nice an ' men
gang aft agley
"""
2、整型和双精度数字
因为“类型安全”,整型和双精度不能进行数字操作
var a = 1
var b = 1.1
var c = a + b //这里会报错
var d = 1 + 1.1 // 这里不会报错 为什么??
3、字符插值
var forecast = "Today's weather will be \(weather)"
二,复杂数据类型
1、数组、集、元组、字典(Array,Set,Tuples,Dictionary)
var arr = [1,2,3,4]
var set = Set([1,2,3,4])
var name = (first:"Taylor",last:"Swift")
var heights = ["taylor":1.72,"Ed":1.73]
//读取字典时,可以传个default,以确保不会返回nil
heights["google"]//nil
heights["google",default:1.70]//1.70
创建一个新的对象
//新字典
var teams = [String:String]()
teams["paul"] = "Red"]
//或
var teams = Dictionary<String,String>()
teams["paul"] = "Red"]
//新数组
var results = [Int]()
results[0] = 0
//或
var results = Array<Int>()
result[0] = 0
//而集合没有简化写法,只能用Set
var words = Set<String>()
- 数组/字典长度是可变的
- 集合会忽略重复的值
- 元组定义之后不可以添加新的类型,只能修改值, 对吗?
2、枚举(Enum)
enum Result {
case success
case failure
}
let res = Result.failure
枚举关联值 , 好像一个方法
enum Activity{
case hored
case running(destination:String)
case taking(topic:String)
case singing(volume:Int)
}
let talking = Activity.talking(topic:"football")
三、运算符 和 条件 (Operators,Condition)
- 运算符 加减乘除余 += -= *= /=
- 条件 if else 和 switch 和其他语言一样用法
范围运算符 ..< 和 ...
let score = 85
switch score {
case 0..<50:
print (" you failed badly.")
case 50..<80:
print (" you did OK.")
default:
print("You did great!")
}
数组也可以用+和+=
var songs = ["Shake it Off", "You Belong with Me", "Love Story"]
var songs2 = ["Today was a Fairytale", "Welcome to New York", "Fifteen"]
var both = songs + songs2
both += ["Everything has Changed"]
四、循环(Loop)
- for循环
for循环中的号 ,当循环的变体不被引用的时候,会要求声明为
for _ in 1...5 {
print("do for loop")
}
- while repeate ... while 和其他语言用法一样
五、函数(Function)
- 函数每个参数可以使用两个标签,第一个给外部使用,如果想省略就写成_,第二个标签给函数做内部引用
func great(_ person:String,nicely:Bool=true){
if nicely == true {
print("hello, \(person)!")
}else{
print ("oh no, it's \(person)")
}
}
可变参数 要求在声明的类型后加三个点
func square(numbers:Int...){
for num in numbers{
print ("squared is \(num*num)")
}
}
抛出错误 要求在do语句块中调用,且调用前要加关键字try
//先定义一个Error枚举
enum PasswordError:Error{
case obvious
}
//
func checkPassword(_ password:String) throws -> Bool {
if password == "" || password == "password" {
throw PasswordError.obvious
}
return true
}
do{
try checkPassword(password:"password")
print ("pw is good")
}catch{
print("can't use pw")
}
- 输入参数inout,调用输入参数时,要在变量前加“&”
func doubleInplace(number: inout Int){
num *= 2
}
var num = 10
doubleInPlace(number:&num)
六、闭包 (closure syntax) D6D7
- 基本闭包
- 闭包的函数体直接跟在=号之后,没有func关键字
- 包含参数的括号放在大括号内,并且要带一个in 关键字. in关键字分隔参数和函数主体
- 返回值类型声明也需要放在in之前
let payment = {(user:String,amount:Int)->String in
return "user : \(user) , amount: \(amount)"
}
- 尾随闭包? Trailing closure syntax
如果一个函数的最后一个参数是闭包,可以不用像传入参数一样传递闭包
func travel (action:()->void) {
print ("I'm getting ready to go.")
action()
print("I arrived")
}
//以下两种写法打印是一样的
let driving = {
print ("driving ...")
}
travel(action:driving)
//直接尾随闭包 ()也是可以省略的,这里为了可以看到参数应该在哪
travel(){
print("driving 2 ....")
}
闭包速记语法
func travel (action:(String)->String) {
print ("I'm getting ready to go.")
let desc = action()
print(desc)
print("I arrived")
}
//尾随闭包写法
travel { (place:String)->String in
return "I'm going to \(place) in my car"
}
//简化写法
travel { place in
return "I'm going to \(place) in my car"
}
//用速记$0替换参数
travel {
return "I'm going to \($0) in my car"
}
闭包捕获参数
func travel() -> (String)->Void {
var counter = 1
return {
print(" \(counter) , I'm going to \($0)")
counter += 1
}
}
let target= travel()
target("Beijing")
result("Shanghai")
result("Guangzhou")
//可以看到打印,counter是一直变化的
1.I'm going to Beijing
2.I'm going to Shanghai
3.I'm going to Guangzhou
七、结构体(Struct) D8D9
结构体是值类型
- 结构体和元组有什么区别?元组就是一个匿名结构体?
- 结构体和类有什么区别?结构体是常量?
- 计算属性
- 观察者 willSet didSet
struct Progress {
var task:String
var state:Bool {
return task == ""
}
var amount:Int {
didSet{
print("now \(amount)% complete")
}
}
//结构体内还可以有方法
func getState()->Int{
return amount>=100?1:0
}
}
var pro = Progress(task:"Loading Data",amount:0)
pro.amount = 30
pro.amount = 60
pro.amount = 100
- 变异方法
结构体创建的时候是常量不能改变属性,任何结构体的方法试图改变任何属性,都必标记成mutating
未标记mutating的方法不能调用已标记mutating的方法
struct Person {
var name
mutating func makeAnonymous(){
name = "Anonymous"
}
}
var person = Person(name:"Ed")
person.makeAnonymous()
字符串/整数/数组/字典等swift的核心类都是结构体
结构体未定义init()方法的时候,可以用成员初始化器,定义了之后,只能用init的参数
// 这种可以用成员初始化器
struct Employee {
var name: String
var yearsActive = 0
}
let roslin = Employee(name: "Laura Roslin")
let adama = Employee(name: "William Adama", yearsActive: 45)
// 但是有init方法之后,只能用init的参数
struct Employee {
var name: String
var yearsActive = 0
init(str:String) {
self.name = "Anonymous"
print("Creating an anonymous employee…")
}
}
let anon = Employee(str:"unknow");
//init方法放在Extension中时,又可以用成员初始化器
struct Employee {
var name: String
var yearsActive = 0
}
extension Employee {
init() {
self.name = "Anonymous"
print("Creating an anonymous employee…")
}
}
let roslin = Employee(name: "Laura Roslin")
let anon = Employee()
- lazy 在调用的时候执行初始化,并在初始化完成后保存这个值
- 静态属性和访问控制和其他语言一样
八、类(Class) D10
类和结构有五个重要区别:
- 类不带有合成的成员初始化器。
- 一个类可以继承另一个类,获得它的属性和方法。
- 结构的副本总是唯一的,而类的副本实际上指向相同的共享数据。
- 类有析构器(deinit),它们是在类的实例被销毁时调用的方法,但结构没有。
- 常量类中的变量属性可以自由修改,但是常量结构体中的变量属性不能。
变量类可以改变变量属性
常量类可以改变变量属性
变量结构可以改变变量属性
常量结构不能改变变量属性
类、继承 和其他语言一样,略了
九、协议和扩展 (Protocol,Extension)
协议和Java系的“接口(interface)”一样 略
- 扩展允许您向现有类型添加方法,使它们执行最初设计时不打算执行的操作
不允许在扩展中添加存储属性,因此您必须改用计算属性
extension Int {
func squared() -> Int {
return self * self
}
}
- 协议扩展可以使所有符合协议的类都得到您的更改
extension Collection {
func summarize() {
print("There are \(count) of us:")
for name in self {
print(name)
}
}
}
//数组和集合都遵循Collection协议
let pythons = ["Eric", "Graham", "John", "Michael", "Terry", "Terry"]
let beatles = Set(["John", "Paul", "George", "Ringo"])
pythons.summarize()
beatles.summarize()
十、可选项(Optionals)
可选项允许我们表示某些数据的缺失。
- 展开可选项
可选项的一个最重要的特性是 Swift 不会让我们在没有展开它们的情况下使用它们。
这为我们的应用程序提供了大量的保护,因为它消除了不确定性:当你处理一个字符串时,你知道它是一个有效的字符串,当你调用一个返回整数的函数时,你知道它立即是安全的采用。当你的代码中确实有可选项时,Swift 将始终确保你正确处理它们——检查和解包它们,而不是仅仅将不安全的值与已知的安全数据混合在一起。
if let ... 展开可选项
func getUsername() -> String? {
return "Taylor"
}
if let username = getUsername() {
print("Username is \(username)")
} else {
print("No username")
}
guard let 展开可选项
func greet(_ name: String?) {
guard let unwrapped = name else {
print("You didn't provide a name!")
return
}
print("Hello, \(unwrapped)!")
}
强制展开
Optionals 表示可能存在也可能不存在的数据,但有时您可以确定某个值不为零。
在这些情况下,Swift 允许您强制解包可选类型:将其从可选类型转换为非可选类型。
let str = "5"
let num = Int(str)!
隐式解包
let num:Int! = nil
nil 合并 , 给可能为nil的表达式添加一个默认值,从而展开可选项
func username(for id: Int) -> String? {
if id == 1 {
return "Taylor Swift"
} else {
return nil
}
}
let user = username(for: 15) ?? "Anonymous"
可选链
let names = ["Vincent": "van Gogh", "Pablo": "Picasso", "Claude": "Monet"]
//当names.first为nil时,不会进行后面的操作
let beatle = names.first?.uppercased()
let surnameLetter = names["Vincent"]?.first?.uppercased() ?? "?"
可选try
enum PasswordError: Error {
case obvious
}
func checkPassword(_ password: String) throws -> Bool {
if password == "password" {
throw PasswordError.obvious
}
return true
}
//常规do...try...catch
do {
try checkPassword("password")
print("That password is good!")
} catch {
print("You can't use that password.")
}
//try?
if let result = try? checkPassword("password") {
print("Result was \(result)")
} else {
print("D'oh.")
}
//确认不会报错时可以,try!
try! checkPassword("sekrit")
print("OK!")
可以失败的初始化?
struct Employee {
var username: String
var password: String
init?(username: String, password: String) {
guard password.count >= 8 else { return nil }
guard password.lowercased() != "password" else { return nil }
self.username = username
self.password = password
}
}
let tim = Employee(username: "TimC", password: "app1e")
let craig = Employee(username: "CraigF", password: "ha1rf0rce0ne")
类型转换 as?
class Person {
var name = "Anonymous"
}
class Customer: Person {
var id = 12345
}
class Employee: Person {
var salary = 50_000
}
let customer = Customer()
let employee = Employee()
let people = [customer, employee]
for person in people {
if let customer = person as? Customer {
print("I'm a customer, with id \(customer.id)")
} else if let employee = person as? Employee {
print("I'm an employee, earning $\(employee.salary)")
}
}
思考
- swift 的基类是NSObject吗,如Java的Object ?
swift 没有像Java Object一样的唯一基类,有多个协议可以看成根类