序言
本文为入门教程:主要针对无任何编程基础或是想了解IOS/Swfit编程开发的小伙伴。
若本文让你感到任何不适,头晕想吐等症状,嘿嘿嘿···本人概不负责!!!
传送门
由于本教程是连载类型,为了各位看客老爷跟加直观的欣赏。
第一课:http://www.jianshu.com/p/8e8ff60121c4
第二课:http://www.jianshu.com/p/8cdabd470f6f
第四课: http://www.jianshu.com/p/55ca9d54a610
概述
经过上一周最基本的Swift基础语法讲解和练习之后,本周我们学习的是更为复杂和实用的语法和内容。
内容
1.字典和集合
//字典(存放键值对组合的容器)
//字典中的每个元素都是由两部分构成,冒号前面的是键,冒号后面的是值
var dict:[String:String] = ["abacus":"算盘","abnormal":"异常的","hello":"你好","good":"好的"]
//print 前面的键 就会输出后面的值
//但是print 后面的值 不会输出前面的键
print(dict["hello"]!)
print(dict["abcxyz"])
print(dict["你好"])
// 添加元素
dict["shit"] = "狗屎"
dict["delicious"] = "好吃的"
print(dict)
// 删除元素
dict.removeValueForKey("hello") //第一种
dict["hello"] = nil //第二种
print(dict)
print(dict["hello"])
// 修改元素
dict["shit"] = "牛粪"
print(dict)
// 遍历字典中所有的值
for value in dict.values {
print(value)
}
// 遍历字典中所有的键
for key in dict.keys {
print("\(key) ---> \(dict[key])")
}
// 直接通过一个元组获得字典中的键和值(原始类型)
for (key, value) in dict {
print("\(key) ---> \(value)")
}
下面介绍集合
var a: Set<Int> = [1, 2, 3, 1, 2, 5]
a.insert(100) // 添加元素
a.remove(2) // 删除元素
print(a)
var b: Set<Int> = [3, 5, 7, 9, 11]
print(b)
print(a.intersect(b)) // 交集(a和b都有的元素)
print(a.union(b)) // 并集(a和b的所有元素)
print(a.subtract(b)) // 差集(a有b没有的元素)
print(a == b)
print(b.isSubsetOf(a))
let c: Set<Int> = [1, 3]
print(c.isSubsetOf(a)) // 判断c是不是a的子集
print(a.isSupersetOf(c)) // 判断a是不是c的超集
let d: Set<Int> = [2, 1000, 10000]
print(a.isDisjointWith(d)) // 判断两个集合是否相交
集合中两个值相同的元素,会合并到一起。
2.函数
函数我认为是swift语言中最重要的章节之一。
下面是函数的定义和一些基础的运用
定义函数的关键词为func
// 函数的参数名
// 函数名(外部参数名 内部参数名: 类型, 外部参数名 内部参数名: 类型)
// 如果不写外部参数名那么内部参数名也是外部参数名
// 可以使用_来作为外部参数名表示省略外部参数名
func myMin(a x: Int, b y: Int) -> Int {
return x < y ? x : y
}
// 调用函数的时候要写函数的外部参数名
print(myMin(a: 3, b: 5))
// 定义函数
// func 函数名(参数列表) -> 返回类型 { 函数的执行体 }
// Swift中函数的参数可以设定默认值
// 如果调用函数的时候没有给该参数赋值就直接使用默认值
func sayHello(personName: String, alreadyGreeted: Bool = false) -> String {
// let greeting = "Hello, " + personName + "!"
// 如果函数的返回类型不是Void 那么函数中一定有return语句
// return greeting
// personName = "王小锤" // 编译错误
if alreadyGreeted {
return "怎么又是你, " + personName + "!"
}
else {
return "你好, " + personName + "!"
}
}
// 调用函数
// 函数名(参数值)
// 调用Swift的函数时, 在默认情况下从第二个参数开始需要写参数名
print(sayHello("王大锤", alreadyGreeted: true))
// 如果没有给第二个参数赋值那么就直接使用默认值false
let str = sayHello("Jack")
print(str)
// Swift中函数的参数列表可以是可变参数列表(参数的个数是任意多个)
func sum(nums: Int...) -> Int {
var total = 0
for num in nums {
total += num
}
return total
}
print(sum())
print(sum(999))
print(sum(1, 2, 3))
print(sum(90, 82, 37, 68, 55, 11, 99))
// 可以使用元组(tuple)让函数一次返回多条数据
func minMax(array: [Int]) -> (min: Int, max: Int)? {
if array.count == 0 {
return nil
}
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
}
else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let b = minMax([23, 45, 99, 68, 72, 12, 55]) {
print(b.min) // print(b.0)
print(b.max) // print(b.1)
}
else {
print("数组中没有元素!!!")
}
func swap(inout a: Int, inout _ b: Int) -> Void {
(a, b) = (b, a)
// let temp = a
// a = b
// b = temp
}
var a = 300, b = 500
swap(&a, &b)
print("a = \(a)")
print("b = \(b)")
// inout - 输入输出参数(不仅将数据传入函数还要从函数中取出数据)
func createX(inout x: Int) {
x = 1000
}
var x = 1
// inout类型的参数前要加上&符号
createX(&x)
print(x)
函数的两个小例子
// 设计一个函数根据系统时间返回不同的问候语
func sayHello(name: String) -> String {
let date = NSDate()
let cal = NSCalendar.currentCalendar()
let hour = cal.component(.Hour, fromDate: date)
//这三句代码的意思为:第一句 获取当前系统时间
//第二句是 当前历法
//第三句是 当前小时
var greeting: String
switch hour {
case 0...6: // 不同的分支可以有重叠的部分
greeting = "滚去碎觉了"
// fallthrough // 继续执行下一个case
case 4...10: // 匹配了一个分支之后不再匹配其他的分支
greeting = "早起的鸟儿有虫吃"
case 11...13:
greeting = "中午好"
case 14...18:
greeting = "下午好"
default:
greeting = "晚上好"
}
return name + ", " + greeting + "!"
}
print(sayHello("小刚"))
// 设计一个函数传入两个正整数m和n, 计算从m加到n的和
func sum(m: Int, _ n: Int) -> Int {
let (a, b) = m > n ? (n, m) : (m, n)
var value = 0
for i in a...b {
value += i
}
return value
}
print(sum(1, 100))
print(sum(5, -4))
print(sum(-1, -5))
调用苹果自身的Api,进行程序应用开发
调用苹果的指纹识别,开发一个带有指纹识别的支付功能的app。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let errPointer = NSErrorPointer()
let ctx = LAContext()
// 判断设备是否支持指纹识别
if ctx.canEvaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, error: errPointer) {
// z = f(x, g(y))
// Swift中允许将一个函数作为另一个函数的参数
// evalutePolicy方法的第三个参数是一个函数
// 该函数有两个参数没有返回值
// 给该参数传参时可以在花括号中写一个匿名函数传进去
// 该匿名函数通常也称之为闭包(closure)
ctx.evaluatePolicy(.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "请输入指纹进行支付", reply: { (isOK, err) -> Void in
if isOK {
print("支付成功!!!")
}
else {
print("指纹验证失败, 请输入支付密码")
}
})
}
else {
print("你的设备不支持指纹识别")
}
}
}
3.闭包
闭包也称:匿名函数 意思是没有名字的函数
闭包由来:
在swift中函数也是一种类型
这也就意味着函数可以作为变量或常量的类型
同理函数也可以作为另一个函数和参数或返回值
func sum(a: Int, _ b: Int) -> Int {
return a + b
}
func mul(a: Int, _ b: Int) -> Int {
return a * b
}
func foo(array: [Int], fn: (Int, Int) -> Int) -> Int {
var sum = array[0]
for x in array[1..<array.count] {
sum = fn(sum, x)
}
return sum
}
由于在swift中能省则省的原则和传统就将调用函数做了以下几步写法省略
let a = [1, 2, 3, 4, 5]
// 当调用foo函数时第二个参数可以传什么?
// 1. 所有自定义的(Int, Int) -> Int类型的函数
print(foo(a, fn: sum))
// 2. 传入已有的二元运算符: +-*/%(因为运算符也是函数)
print(foo(a, fn: +))
// 3. 传入匿名函数(闭包)
// 3.1 完整的闭包写法
print(foo(a, fn: { (a, b) -> Int in
return a + b
}))
// 3.2 省略掉类型和不必要的括号
print(foo(a, fn: { a, b in a + b }))
// 3.3 省略参数名
print(foo(a, fn: { $0 + $1 }))
// 3.4 尾随闭包
print(foo(a) { (a, b) -> Int in
return a + b
})
print(foo(a) { $0 + $1 })
需要注意的是:
如果函数的最后一个参数是闭包可以写成尾随闭包的形式
也就是将闭包放到函数参数的圆括号外面写在一对花括号中
如果函数后面有尾随闭包且函数的圆括号中没有参数
那么函数的圆括号也可以省略(仅限于有尾随闭包的场景)
例如
var array = ["game", "abacus", "hello", "cat", "good", "internationalization", "chaos", "dislike", "zealot", "young"]
// array.sortInPlace(>)
array.sortInPlace({ $0 > $1 })
array.sortInPlace() { $0 > $1 }
array.sortInPlace { $0 > $1 } //这就是尾随闭包的最简写法
4.数组最重要的三个功能
1.过滤 2.映射 3.缩减
let array = [23, 37, 96, 55, 40, 92, 68, 88]
// 1. 过滤
let newArray1 = array.filter { $0 > 50 } //找到数组中比50大的数输出出来
print(newArray1)
let newArray2 = array.filter { $0 % 2 == 0 } //找到数组中得偶数
print(newArray2)
// 2. 映射
let newArray3 = array.map { $0 * $0 } //将数组中的每个数平方
print(newArray3)
let newArray4 = array.map { sqrt(Double($0)) } //将数组中得每个数开根号
print(newArray4)
// 3. 缩减
let result1 = array.reduce(0, combine: +)// 将数组中的每个数想加
print(result1)
let result2 = array.reduce(1, combine: *)//将数组中的每个数相乘
print(result2)
let result3 = array.reduce(array[0]) { //取数组中最大的数
$1 > $0 ? $1 : $0
}
print(result3)
let strArray = ["I", "love", "you"]
let result4 = strArray.reduce("") { $0 + " " + $1 }//将数组中的三个元素合为一个
print(result4)
5.类
类和上文提到的函数 紧密相关
类是一类事物 而对象是这类事物中具体的实例
步骤1: 定义类(如果你要用的类苹果已经提供了就直接进入第2步)
定义类就可以创建出新的类型
学生类
class Student {
// 变量定义到类的外面就叫变量 - variable
// 变量定义到类的里面就叫属性 - property
// 数据抽象 - 找到和学生相关的属性(找名词)
var name: String
var age: Int
// 初始化方法(构造方法/构造器) - constructor
init(name: String, age: Int) {
self.name = name
self.age = age
}
// 函数写到类的外面就叫函数 - function
// 函数写到类的里面就叫方法 - method
// 行为抽象 - 找到和学生相关的方法(找动词)
func eat() {
print("\(name)正在吃饭.")
}
func study(courseName: String) {
print("\(name)正在学习\(courseName).")
}
func watchJapaneseAV() {
if age >= 18 {
print("\(name)正在动作片.")
}
else {
print("亲爱的\(name), 我们推荐你观看《熊出没》")
}
}
}
// 步骤2: 创建对象(调用初始化方法)
let stu1 = Student(name: "小刚", age: 35)
// 步骤3: 给对象发消息(通过给对象发消息来解决问题)
stu1.eat()
stu1.study("Swift程序设计")
stu1.watchJapaneseAV()
let stu2 = Student(name: "王大锤", age: 15)
stu2.eat()
stu2.study("中国近代史")
stu2.watchJapaneseAV()
下面定义一个圆的类
类里面有求圆的面积和周长的方法(函数)
eg:
// 0. 发现类
// - 在对问题的描述中找名词和动词
// - 名词会成为类或者类中的属性 动词会成为类中的方法
// 1. 定义类
// - 数据抽象(属性)
// - 行为抽象(方法)
// - 初始化方法
// 访问修饰符
// - public (公开)
// - internal (内部的) - 默认
// - private (私有)
class Circle {
// stored property
// 存储属性(保存和圆相关的数据的属性)
var center: Point
var radius: Double
init(center: Point, radius: Double) {
self.center = center
self.radius = radius
}
// 通常获得某个计算出的值的方法都可以设计成计算属性
// computational property
// 计算属性(通过对存储属性做运算得到的属性)
var perimeter: Double {
// 圆的周长是一个只读属性
// 所以此处只有get{}没有set{}
get { return 2 * M_PI * radius }
}
var area: Double {
get { return M_PI * radius * radius }
}
}
注意:运算符重载
```swift
//运算符重载(为自定义的类型定义运算符)
func +(one: Fraction, two: Fraction) -> Fraction {
return one.add(two)
}
func -(one: Fraction, two: Fraction) -> Fraction {
return one.sub(two)
}
func *(one: Fraction, two: Fraction) -> Fraction {
return one.mul(two)
}
func /(one: Fraction, two: Fraction) -> Fraction {
return one.div(two)
}
6.继承
// 继承: 从已有的类创建新类的过程
// 提供继承信息的称为父类(超类/基类)
// 得到继承信息的称为子类(派生类/衍生类)
// 通常子类除了得到父类的继承信息还会增加一些自己特有的东西
// 所以子类的能力一定比父类更强大
// 继承的意义在于子类可以复用父类的代码并且增强系统现有的功能
class Teacher: Person {
var title: String
init(name: String, age: Int, gender: Gender, title: String) {
self.title = title
super.init(name: name, age: age, gender: gender)
}
func teach(courseName: String) {
print("\(name)\(title)正在教\(courseName).")
}
}
//父类和子类关系
let p1 = Person(name: "王大锤", age: 25, gender: .Male)
p1.eat()
// 可以将子类型的对象赋值给父类型的变量(因为子类跟父类之间是IS-A关系)
// 学生是人, 老师是人, 所以学生和老师的对象可以赋值给人类型的变量
let p2: Person = Student(name: "张尼玛", age: 18, gender: .Female, major: "计算机科学与技术")
p2.eat()
// 如果要将父类型的变量转换成子类型需要用as运算符进行类型转换
// 如果能够确认父类型的变量中就是某种子类型的对象可以用as!进行转换
// 如果不确定父类型的变量中是哪种子类型可以用as?尝试转换
(p2 as! Student).study("Swift程序设计")
if let temp = p2 as? Teacher {
temp.teach("Java")
}
else {
print("\(p2.name)不是老师!!!")
}
let p3: Person = Teacher(name: "骆昊", age: 35, gender: .Male, title: "叫兽")
p3.eat()
7.多态
同样的对象类型(pet类型)接受了相同的消息(调用了相同的方法)
但是做了不同的事情 这就是多态(polymorphism)
例如:猫(cat)继承它的父类动物(pet)
// Cat和Pet之间是IS-A关系(继承)
class Cat: Pet {
var hairColor: String?
// 父类有的方法子类可以重新实现 这个过程叫方法重写
// 需要在方法前添加override关键字
// 重写有时也被称为置换/覆盖/覆写
override func play() {
super.play()
print("\(nickname)正在玩毛线球.")
}
override func shout() {
print("\(nickname): 喵喵喵……")
}
func catchTheMouse() {
print("\(nickname)正在抓老鼠.")
}
}
对父类的方法可以重新实现, 这个过程叫方法重写
这是实现多态的重要步骤之一!
下面是实现多态的第二个步骤:
let petsArray = [
Cat(nickname:"加菲",gender: .Male,age:2),
Dog(nickname: "吉娃娃", gender: .Male, age: 3, isLarge: false),
Dog(nickname: "大黄", gender: .FeMale, age: 2, isLarge: true),
Mistress(nickname: "小花",gender: .FeMale,age:16)
]
for pet in petsArray{
pet.eat()
// 同样的对象类型(pet类型)接受了相同的消息(调用了相同的方法)
// 但是做了不同的事情 这就是多态(polymorphism)
// 实现多态的关键步骤:
// 1.方法的重写(子类在继承父类的过程中对父类已有的方法进行重写,而且不同的子类给出各自不同的实现版本)
// 2.对象造型(将子类对象当成父类型来使用)
pet.play()
pet.shout()
// 如果dog是属于pet中 如果dog是Dog类型就可以调用keepTheDoor这个特有的方法
if let dog = pet as? Dog{
dog.keepTheDoor()
}
else if let cat = pet as? Cat{
cat.catchTheMouse()
}
else if let mistress = pet as? Mistress{
mistress.makeTrouble()
}
}
//枚举
enum Gender{
case Male
case FeMale
}
总结
本周主要讲的就是类和函数的定义和使用,在类的使用中又遇见各种问题 例如:重要的继承和多态还有类的扩展,运算符重载,枚举····主要是掌握它们之间的关系,如何定义还有使用的方法。