#IOS/Swift入门开发从"白吃"到大神,全球最易懂,最全面,最前沿,最详细,一看就会教程之二!

f2da63e17923fd0a18be1c90b948eb43.jpg

序言

本文为入门教程:主要针对无任何编程基础或是想了解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
    
}

总结

本周主要讲的就是类和函数的定义和使用,在类的使用中又遇见各种问题 例如:重要的继承和多态还有类的扩展,运算符重载,枚举····主要是掌握它们之间的关系,如何定义还有使用的方法。

本次教程到处就要结束了,如果你有什么更好的建议和想法,可以联系我,让我们一同进步。

未完待续····每周日更新新的教程,敬请期待!88····

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容