4学习 swift_swift 4 升级swift4.2 工具 - CSDN
  • 通过博客的方式来记录自己的学习Swift过程,同时把学习的内容分享给大家,希望能为你提供一点帮助

    转载请注明出处:http://blog.csdn.net/xiaojimanman/article/details/53396266

    http://www.llwjy.com/blogdetail/6a852f4e708d8d4b8a18a1115f345443.html

    个人博客站已经上线了,网址 www.llwjy.com ~欢迎各位吐槽~

    -------------------------------------------------------------------------------------------------

          在开始之前先打一个小小的广告,自己创建一个QQ群:321903218,点击链接加入群【Lucene案例开发】,主要用于交流如何使用Lucene来创建站内搜索后台,同时还会不定期的在群内开相关的公开课,感兴趣的童鞋可以加入交流。


          最近人生遇到一些变故,打算学习一门新的编程语言来充实自己的生活,自己会通过博客的方式来记录自己的学习过程,同时把学习的内容分享给大家,万一某一天你也想学习swift的时候,可以给你提供一些帮助。


    编程环境

          学习苹果的开发语言,当然需要有一个Mac系统的苹果电脑,相信如果你真的想学习相关的开发,这个对你不是什么难事。
          据我初步的了解,苹果的相关开发使用的IDE都是Xcode这个软件,我们通过App Store下载相关的Xcode软件(软件大小4G多,下载速度完全看自己的网速),我使用的是8.1这个版本。


    Hello World
          程序员的第一个程序就是Hello World,下面就来介绍下如何来创建一个简单的Hello World程序。
          为了以后学习的方便,先创建一个工作空间(Workspace),打开Xcode软件,如下图

    img

          我们通过File--New--Workspace(control + command + n)创建一个工作空间,命名为swift,路径选择自己的文件夹。

    img

          然后新建一个项目 File--New--Project(shift + command + n)新建一个项目,第一个项目我们先创建一个控制台程序。

    img

          点击Next

    img

          这里项目名喔命名为Swift001,语言选择Swift。点击Next--Create。我们从左侧目录找到main.swift文件,这里又两行代码:

    img

          我们点击左上角的运行按钮

    img

    img


          一个简单的环境就这样完成了,学习还在继续。。。。。


    -------------------------------------------------------------------------------------------------
    小福利
    -------------------------------------------------------------------------------------------------
          个人在极客学院上《Lucene案例开发》课程已经上线了,欢迎大家吐槽~

    第一课:Lucene概述

    第二课:Lucene 常用功能介绍

    第三课:网络爬虫

    第四课:数据库连接池

    第五课:小说网站的采集

    第六课:小说网站数据库操作

    第七课:小说网站分布式爬虫的实现

    第八课:Lucene实时搜索

    第九课:索引的基础操作


    展开全文
  • Swift学习网址收集

    2016-02-15 09:42:09
    swift 学习网址,学习资源,有在线编译网站,还有源码,及swift学习的中文网,还有教程,非常不错的资源

    swift 学习网址

    展开全文
  • Swift 4.0 学习笔记

    示例代码来源于 《iOS 11 Programming Fundamentals with Swift》

    概览

    语句分隔符

    Swift的语句是可以通过分析断句的,如果一个语句结束后换行就开始下一个语句,如果写了分号也表示结束这个语句,但是有了换行就不需要分号了,写上也没有问题。如果一个语句没有结束,换行没有实际效果。下边的代码都是合法的:

    print("hello")
    print("world")
    
    print("hello"); print("world")
    
    print("hello");
    print("world");
    
    print(
        "world")

    注释

    依旧是://和//,其中/* … */可以嵌套

    对象的类型

    Swift中一切都是对象。按照类型划分,有6种:

    • struct, Bool,Int, Double, String, Array,Dictionary等
    • enum, Optional类型
    • class, 用户自定义类型。这篇文章提到了Swift中有3个预定义的class类型,但是没有指出是哪个。

    • protocol,ExpressibleByIntegerLiteral

    • tuple,函数返回多值时使用。
    • function,print,自定义函数。

    举个例子:

    字面变量是对象:

    let s = 1.description

    #### 值类型和引用类型

    按照内存管理来划分,Swift对象有值类型和引用类型,值类型在赋值的时候是copy的(不考虑Swift优化),引用类型是共享内存的。

    官方文档对值类型和引用类型的解释:

    Types in Swift fall into one of two categories: first, “value types”, where each instance keeps a unique copy of its data, usually defined as a struct, enum, or tuple. The second, “reference types”, where instances share a single copy of the data, and the type is usually defined as a class.

    在Swift中,class和function是引用类型,struct,enum,tuple都是值类型。protocol本身不允许有实例,但是采用protocol的可以是struct, enum或者class。

    数据类型

    变量与常量

    let one = 1
    var two = 2

    使用let声明的是常量,使用var声明的是变量

    类型推断

    从上面例子可以看出,如果在声明变量的时候就赋值,有时候是可以不写类型的,让编译器推断。上文中one和two都是Int类型。

    那么什么时候需要些类型呢?

    • 只声明,不初始化。
    var x : Int
    • 想要的类型和推断的类型不符合
    let separator : CGFloat = 2.0
    • 不能推断出类型
    let opts : UIViewAnimationOptions = [.autoreverse, .repeat]
    • 还有一种情况是提醒自己这个变量是啥类型
    let duration : CMTime = track.timeRange.duration

    基本类型用法

    Bool

    • Bool是一个struct类型
    • 只有true和false两个值,不能做它解释。

    Int

    • Int是struct类型
    • Int的取值在Int.max和Int.min之间,平台相关

    Double

    • Double是struct类型
    • 64位架构处理器上,Double的精度是15位
    • Double的边界是Double.infinity,还有Double.pi等
    • 使用isZero来判断Double是否为0

    数字类型转换

    只有字面变量可以被隐式转换!

    let d : Double = 10

    将字面变量10转换成了Double类型,但是变量就不可以,下列的代码不能通过编译:

    let i = 10
    let d : Double = i // compile error

    正确的写法是:

    let i = 10
    let d : Double = Double(i)

    String

    let str = "Hello World" //欧耶,终于不用写@了

    多行字面变量的写法:

    func f() {    
        let s = """    
        Line 1        
            Line 2    
        Line 3    
        """    
        // ...
    }
    
    func f() {    
        let s = """
        Line "1"        
            Line 2 \    
        and this is still Line 2    
        """    
        // ...
    }

    在String字面变量中使用(…)来计算表达式

    let n = 5
    let s = "You have \(n) widgets."

    String支持+号和+=号

    let s = "hello"
    let s2 = " world"
    let greeting = s + s2

    String的utf8编码:

    let s = "\u{BF}Qui\u{E9}n?"for i in s.utf8 {   
        print(i) // 194, 191, 81, 117, 105, 195, 169, 110, 63
    
    }

    String和数值的转化:

    let i = 7
    let s = String(i) // "7"
    
    let i = 31
    let s = String(i, radix:16) // "1f"

    Range

    Range是一个struct。 字面变量: a…b表示区间[a, b] a..< b表示区间[a, b)

    最常见的就是在for循环中使用:

    for ix in 1...3 {    
        print(ix) // 1, then 2, then 3
    }

    Range 有实例方法:

    let ix = // ... an Int ...
    if (1...3).contains(ix) { // ...
    
    let s = "hello"
    let ix2 = s.index(before: s.endIndex)
    let s2 = s[..<ix2] // "hell"

    Tuple

    tuple是一个有序的轻量级的collection。

    tuple的声明:

    var pair : (Int, String)

    初始化:

    var pair : (Int, String) = (1, "Two")
    var pair = (1, "Two")

    tuple可以同时给多个变量赋值:

    let ix: Int
    let s: String
    (ix, s) = (1, "Two")

    tuple在for-in中的应用:

    let s = "hello"
    for (ix,c) in s.enumerated() {
        print("character \(ix) is \(c)")
    
    }

    对Tuple中值的引用:

    let pair = (1, "Two")
    let ix = pair.0 // now ix is 1

    如果在声明的时候给值一个label,可以通过label引用:

    let pair : (first:Int, second:String) = (1, "Two")
    //or: let pair = (first:1, second:"Two")
    
    var pair = (first:1, second:"Two")
    let x = pair.first // 1
    pair.first = 2
    let y = pair.0 // 2

    还可以给Tuple起一个别名

    typealias Point = (x:Int, y:Int)
    
    func piece(at p:Point) -> Piece? {    
        let (i,j) = p    
        // ... error-checking goes here ...    
        return self.grid[i][j]
    
    }

    可选类型

    Swift中变量如果不初始化是不能使用的。这点和OC不同,OC中值类型会有一个默认值,引用类型默认为nil。Swift中如何表示nil呢?答案就是Optional(可选类型)

    Optional类型的底层是enum类型,可以包装一个其他类型,具体内部实现这里不讨论。
    比如:

    var stringMaybe = Optional("howdy")

    就定义了一个包装了String的Optional类型。包装不同类型的Opational也是不同的类型,不能互相赋值。Optional(String)类型可以简写为String?

    如果没有给Optional的变量装箱一个值,那么它就是空的,空的Optional变量可以和nil比较:

    var stringMaybe : String? = "Howdy"
    print(stringMaybe) // Optional("Howdy")
    if stringMaybe == nil {    
        print("it is empty") // does not print
    }
    stringMaybe = nilprint(stringMaybe) // nil
    if stringMaybe == nil {    
        print("it is empty") // prints
    }

    在Swift中nil是一个关键字,不是一个值,可以将nil赋值给Optional的类型。

    自动装箱,将一个值直接值给包装它的Optional类型。

    var stringMaybe: String? = "farewell

    根据自动装箱机制,可以在任何需要Optional类型的地方传入原始类型,但是反过来不行。

    let stringMaybe : String? = "howdy"
    let upper = stringMaybe.uppercased() // compile error

    不能给Optional类型直接发送消息,需要拆箱得到原始数据。

    拆箱

    let stringMaybe : String? = "howdy"
    let upper = stringMaybe!.uppercased()

    在变量后边加上叹号,就拆箱得到原始类型。

    自动拆箱,在定义变量的时候使用!而不是?就定义了一个自动拆箱的Opational变量,在需要使用原始类型的地方,直接传入自动解包的Opational变量即可。

    func realStringExpecter(_ s:String) {}
    var stringMaybe : String! = "howdy"
    realStringExpecter(stringMaybe) // no problem

    注意,如果自动解包的Optional是nil,会引起Crash。不能给一个是nil的Optional类型解压,这是Swift最重要的规则之一。 所以,如果不是必须,最好不要使用这个特性,因为这样就失去了Swift中可选类型的安全特性。

    !定义的Optional和?定义的Optional是同一个类型,比如self.view是一个UIView!,但是如下代码却产生编译错误。

    var stringMaybe : String! = "howdy"
    var anotherStr = stringMaybe //ok
    var pureStr: String = stringMaybe //ok
    var errStr: String = anotherStr // compile error

    stringMaybe是自动拆箱的String?,所以赋值给String类型是可以的;但是anotherStr却没有自动拆箱的标志,仅仅是一个String?,所以不能赋值给String类型。

    Optianal Chain是Swift中很重要的一个概念。

    拆箱nil会引起Crash,那么如果每次拆箱都得判断是否为nil,代码就会很难看。于是Swift提供了语法糖:

    var stringMaybe : String?
    // ... stringMaybe might be assigned a real value here ...
    let upper = stringMaybe?.uppercased()

    在拆箱的时候,不用!而是用?,这叫做选择性拆箱。英文很有意思:unwarp the Optional optionally。

    选择性拆箱实际上替你做了判断工作,就是如果stringMaybe是nil,那么什么也不做,如果不是nil,拆箱得到String,然后发送uppercased消息。

    这很好,但是如果“什么也不做”返回值upper是啥?答案是nil。那么nil是不能赋值给String类型的,于是又引入一个规则:

    如果一个Optional Chain上有一个可能的Optional的类型(选择性拆包才有),那么返回值就是Optional的

    也就是说虽然uppercased方法返回的是String类型,但是因为它在一个Optional Chain中,所以返回值自动被装箱,成为String?类型。一个Optional Chain返回一个Optional的类型也合情合理。

    因为自动装箱,给一个Opational Chain赋值会比较简单。

    // self is a UIViewController
    self.navigationController?.hidesBarsOnTap = true

    同样,如果navigationController是nil,什么也不会发。那么如何知道赋值成功了呢?

    let ok : Void? = self.navigationController?.hidesBarsOnTap = true

    如果ok不是nil,就是赋值成功。

    Optional类型是可以和原始类型直接比较的。下边的代码没有问题。

    let s : String? = "Howdy"
    if s == "Howdy" { // ... they _are_ equal!

    如果s是nil,返回false,如果s不是nil,拆箱之后再和”Howdy”比较。

    但是不能比较不等关系,下边的代码是不能通过编译的:

    let i : Int? = 2
    if i < 3 { // compile error

    因为Swift不能确定如果是nil,结果是什么。

    函数

    函数的定义

    func sum (_ x:Int, _ y:Int) -> Int {
        let result = x + y
        return result
    }
    • func 是keyword,sum是函数名。
    • 括号内部是参数,参数标签,变量名,冒号后是类型。和OC结构一样。
    • -> Int表示返回值是Int类型。如果函数返回Void,可以写成->()
    • 函数体在大括号内部。
    • 参数前边的”_”符号表示忽略参数的标签。

    参数标签

    func echoString(_ s:String, times:Int) -> String {
        var result = ""
        for _ in 1...times { result += s }
        return result
    }

    times就是参数的外部名字(external name),也可以叫参数标签。这是和OC语言的参数名字和变量名字分开是一致的。

    调用的代码应该是这样:

    let s = echoString("hi", times:3)
    • 默认的,参数的变量名(internal name)就是参数标签(external name)。
    • 如果使用了_,表示没有标签,调用方也不能使用标签调用了。
    • 具有相同的函数签名,但是参数标签不同的函数,是两个不同的函数。

    函数参数默认是不可变的。意思是,不能在函数中给函数参数再次赋值。对于引用类型,是可以改变内部属性的。

    func say(_ s:String, times:Int, loudly:Bool) {
        loudly = true // compile error
    }

    如果想要重新给参数赋值需要满足以下几个条件:
    - 给函数参数添加intout关键字
    - 传入的变量应该是var而不是let的
    - 传入变量的地址。

    func removeCharacter(_ c:Character, from s: inout String) -> Int {
        var howMany = 0
        while let ix = s.index(of:c) {
            s.remove(at:ix)
            howMany += 1
        }
        return howMany
    }

    调用

    var s = "hello"
    let result = removeCharacter("l", from:&s)

    Swift中函数是first-class object,意思是函数可以赋值给变量,可以作为函数的参数和返回值。

    func doThis(_ f:() -> ()) {
        f()
    }
    
    func whatToDo() { 
        print("I did it")
    }
    
    doThis(whatToDo) 

    函数是first-class object这一特点可以衍生出很多编程模式,装饰器,偏函数,函数工厂等等。

    class, struct & enum

    概览

    enum,struct在Swift中和class很像,都可以定义方法,初始化函数等,但是有两个重大的区别:
    - enum,struct是值类型,class是引用类型
    - enum,struct不能继承

    在这3种类型中,可以有的结构是:
    - 初始化函数。
    - 属性,分为成员属性和类属性。对于struct和enum用static关键字,对于class用class关键字。
    - 方法,成员方法和类方法。
    - 下标(subscripts)
    - 嵌套定义(值类型的不能嵌套自己的类型)。

    在Swift中没有一个像NSObject那样的公共基类。

    class

    初始化方法

    由于Swift中不允许使用未经初始化的变量,并且想在编译阶段强制的保证这一点。于是对于class类型的初始化,引入了很多规则。虽然规则条数很多,但都是围绕这一个原则:从初始化函数中返回的对象的所有属性也是初始化的,并且在初始化完成之前不能使用这个对象

    • 初始化函数必须初始化所有未初始化的属性
    class Dog {
        let name : String
        let license : Int
        init(name:String = "", license:Int = 0) {
            self.name = name
            self.license = license
        }
    }

    如果删除self.license = license,将会产生编译错误,因为license没有初始化。

    • 在初始化所有属性之前,不能使用self
    class Cat {    
        var name : String    
        var license : Int    
        init(name:String, license:Int) {        
            self.name = name        
            meow() // too soon - compile error        
            self.license = license    
        }    
    
        func meow() {        
            print("meow")    
        }
    
    }

    meow()实际上隐式的使用了self,即self.meow()。应该将meow()的调用放到最后。

    如果初始化函数之间发生调用关系,初始化函数就分成了两类:designated initializer 和convenience initializer。

    designated initializer就是能独立完成对象的初始化的初始化函数,而convenience initializer必须直接或者间接的调用designated initializer来完成初始化工作。

    class Dog{
        var name: String
        var age: Int
    
        init(){
            self.name = "test"
            self.age = 10
        }
    
        convenience init(name:String){
            self.init(name: name, age: 10)
        }
    
        init(name: String, age: Int){
            self.name = name
            self.age = age
        }
    }

    在class中designated initializer不需要特别指明,但是convenience initializer必须使用convenience关键字。(这一条只是对class来讲,如果把class换成struct就不需要使用convenience,这和class是能继承有关系,稍后会介绍到继承)

    这又有一条规则: convenience initializer在使用self之前,必须调用designated initializer

    举个例子:

    class Dog{
        var name: String
        var age: Int
    
        init(){
            self.name = "test"
            self.age = 10
        }
    
        convenience init(name:String){
            self.age = 11 
            self.name = "haha"
            self.init(name: name, age: 10)
        }
    
        init(name: String, age: Int){
            self.name = name
            self.age = age
        }
    }

    上边的代码会发生编译错误,因为convenience初始化函数中在self被designated initializer初始化之前就使用了self。从这一点上看,convenience initializer并不是一个真正的初始化函数,只是能提供初始化功能的一般函数。

    在高级篇介绍的继承体系中,会有更复杂的初始化规则。不过如果你违反了这些规则,编译器都会提示的很清楚。只要理解这些规则的目的都是确保对象被完全初始化即可。

    属性(对struct和class都适用)

    在类的属性全部被初始化完毕之前,不能使用self。

    class Moi {
        let first = "Matt"
        let last = "Neuburg"
        let whole = self.first + " " + self.last // compile error
    
    }

    对于静态属性的使用,在非静态函数中应该使用类名.属性,在静态函数中可以使用self.属性或者类名.属性

    class Greeting {
        static let friendly = "hello there"
        static let hostile = "go away"
    
        static var ambivalent : String {
            return self.friendly + " but " + self.hostile
        }
    }

    下标(对struct和class都适用)

    下标是一种调用实例方法的方式。一般在通过整数参数或者String类型的key获取元素的时候使用下标。

    struct Digit {    
        var number : Int    
    
        init(_ n:Int) {
            self.number = n    
        }   
    
        subscript(ix:Int) -> Int {
            get {             
                let s = String(self.number)  
                return Int(String(s[s.index(s.startIndex, offsetBy:ix)]))!        
            }   
        }
    
    }

    上述代码定义了一个通过位数取数字的下标方法,只读。

    var d = Digit(1234)
    let aDigit = d[1] // 2

    嵌套定义

    class Dog {   
        struct Noise {        
            static var noise = "woof"    
        }    
    
        func bark() {        
            print(Dog.Noise.noise)  
        }
    }
    

    注意:struct不能直接或者间接嵌套自己的类型。

    Struct

    struct大部分特性都和class一致,可以看做是没有继承特性的值类型的class。

    一些不同:
    - 改变struct属性的方法需要标记为mutating,在enum章节中会有例子。
    - 默认的初始化函数可以提供逐一赋值功能(memberwise),只要能保证所有属性都初始化。

    struct Digit {
        var number = 42
        var number2
    }
    
    var d = Digit(number: 3, number2: 34)
    var f = Digit() //compile error
    
    • struct 和enum的类方法或者类属性使用static关键字,class可以使用static或者class,static = final class。

    enum

    enum Filter {    
        case albums    
        case playlists    
        case podcasts    
        case books
    }
    
    let type = Filter.albums

    在能根据上下文推断出enum的类型的时候,可以简写成:

    let type : Filter = .albums

    RawValue

    可以给enum指定一个存储类型,存储类型只能是数字或者String

    enum PepBoy : Int { 
        case manny    
        case moe    
        case jack
    }
    
    enum Filter : String {
        case albums
        case playlists
        case podcasts
        case books
    }

    PepBoy中默认从0开始,Filter中默认值就是case的名字。

    要获取enum中相应case的值,使用rawValue属性

    let type = Filter.albums
    print(type.rawValue) // albums

    可以通过rawValue初始化enum

    let type = Filter(rawValue:"Albums")

    Swift中的enum可以有初始化方法

    enum Filter : String {
        case albums = "Albums"
        case playlists = "Playlists"
        case podcasts = "Podcasts"
        case books = "Audiobooks"
        static var cases : [Filter] = [.albums, .playlists, .podcasts, .books]
        init(_ ix:Int) {
            self = Filter.cases[ix]
        }
    }

    上边的代码就可以通过一个Int来初始化一个存储类型是String的enum。

    enum可以有实例方法和类方法

    enum Shape {
        case rectangle
        case ellipse
        case diamond
        func addShape (to p: CGMutablePath, in r: CGRect) -> () {
            switch self {
            case .rectangle:
                p.addRect(r)
            case .ellipse:
                p.addEllipse(in:r)
            case .diamond:
                p.move(to: CGPoint(x:r.minX, y:r.midY))
                p.addLine(to: CGPoint(x: r.midX, y: r.minY))
                p.addLine(to: CGPoint(x: r.maxX, y: r.midY))
                p.addLine(to: CGPoint(x: r.midX, y: r.maxY))
                p.closeSubpath()
            }
        }
    }

    上边的代码能根据这个enum实际的值,来创建一个图形。

    如果一个enum的实例方法能够修改这个enum的值,那需要将方法声明为mutating

    enum Filter : String {
        case albums = "Albums"
        case playlists = "Playlists"
        case podcasts = "Podcasts"
        case books = "Audiobooks"
        static var cases : [Filter] = [.albums, .playlists, .podcasts, .books]
        mutating func advance() {
            var ix = Filter.cases.index(of:self)!
            ix = (ix + 1) % 4
            self = Filter.cases[ix]
        }
    }

    原理是这样的,enum是一个值类型,值类型是不可变的,要改变enum的值,只有再创建一个enum。这个动作在Swift中是需要开发人员显示指定的。这一条也适用于struct。

    Associated Value

    在Swift中enum还可以作为C语言中的Union使用。

    enum MyError {
        case number(Int)
        case message(String)
        case fatal
    }
    • 在MyError中不声明任何存储类型
    • 在每个case后边用tuple定义类型

    MyErrorj就是一个可能保存Int或者String的数据类型。

    let num = 4
    let err : MyError = .number(num)

    因为Associated Value是动态赋值的,所以Associated Value类型的enum不能使用enum比较。

    if err == MyError.fatal { // compile error

    因为Swift不知道如何比较,两个实例的fatal可能关联了不同的值,那么到底是相同还是不相同?

    集合数据类型

    Array

    • Array只能保存一种数据类型,是指声明为同一种的数据类型,不是实际类型。
    • 如果想保存混合类型的数据,使用[Any],Any是为了和OC交互定义的数据类型。
    • 保存不同类型的Array属于不同的数据类型。
    • Array是值类型,是struct。

    保存Int类型的Array有两种写法:

    let arr1 = Array<Int>()
    let arr2 = [Int]()

    可以使用Range:

    let arr3 = Array(1...3)

    Array有很多初始化函数,比如还可以接受一个集合类型,创建出一个Array

    let arr4 = Array("hey".characters)

    有一个初始化函数需要注意:init(repeating:count),如果参数是引用类型,那么Array中的所有元素将指向同一个元素。

    class Person {
        var name = "123"
    }
    
    var p = Person()
    let arr5 = Array(repeatElement(p, count: 3)) 
    //[{name "123"}, {name "123"}, {name "123"}]
    
    arr5[1].name = "555"  
    //[{name "555"}, {name "555"}, {name "555"}]
    

    Array作为一个整体可以类型转换:

    let dog1 : Dog = NoisyDog()
    let dog2 : Dog = NoisyDog()
    let arr = [dog1, dog2]
    let arr2 = arr as! [NoisyDog]

    NoisyDog 是 Dog的子类, arr是[Dog]类型,可以时间用as!或者as?转换为[NoisyDog]类型。

    两个Array相等的条件是Array中的每一个元素相等(注意并没有要求两个Array的类型是一样的)。和其他语言类似,可以自己提供比较函数。

    let nd1 = NoisyDog()
    let d1 = nd1 as Dog
    let nd2 = NoisyDog()
    let d2 = nd2 as Dog
    if [d1,d2] == [nd1,nd2] { // they are equal!

    Array的下标是支持切片的(slicing),切片仅仅是原来Array的一个映像,底层还是引用的是原来的Array

    let arr = ["manny", "moe", "jack"]
    let slice = arr[1...2] // ["moe", "jack"]
    print(slice[1]) // moe

    slice是arr的从1到2闭区间的切片,下标也是从1开始,到2结束。==如果引用了下标0,则会产生运行时错误==。如果改变了切片中的元素(前提是可以改变),则原来的数组也会受到影响。

    但是,Array不支持负数下标。

    Array有一些常用的属性:

    let arr = ["manny", "moe", "jack"]
    
    arr.count
    arr.isEmpty
    arr.first
    arr.last
    arr.startIndex
    arr.endIndex
    //...

    判断元素是否存在:

    let arr = [1,2,3]
    let ok = arr.contains(2) // true
    let ok2 = arr.contains {$0 > 3} // false
    let arr = [1,2,3]
    let ok = arr.starts(with:[1,2]) // true
    let ok2 = arr.starts(with:[1,-2]) {abs($0) == abs($1)} // true

    改变Array元素:

    var arr = [1,2,3]
    arr.append(4)
    arr.append(contentsOf:[5,6])
    arr.append(contentsOf:7...8) // arr is now [1,2,3,4,5,6,7,8]
    var arr = ["manny", "moe", "jack"]
    arr.insert("333", at: 1) //["manny", "333", "moe", "jack"]
    arr.remove(at: 1) //arr is ["manny", "moe", "jack"]
    let arr = [[1,2], [3,4], [5,6]]
    let joined = Array(arr.joined(separator:[10,11]))
    // [1, 2, 10, 11, 3, 4, 10, 11, 5, 6]
    let arr = [1,2,3,4,5,6]
    let arr2 = arr.split {$0 % 2 == 0} // split at evens: [[1], [3], [5]]

    遍历Array元素

    let pepboys = ["Manny", "Moe", "Jack"]
    for pepboy in pepboys {
        print(pepboy) // prints Manny, then Moe, then Jack
    }
    let pepboys = ["Manny", "Moe", "Jack"]
    pepboys.forEach {print($0)} // prints Manny, then Moe, then Jack
    let pepboys = ["Manny", "Moe", "Jack"]
    for (ix,pepboy) in pepboys.enumerated() {
        print("Pep boy \(ix) is \(pepboy)") // Pep boy 0 is Manny, etc.
    }
    // or:
    pepboys.enumerated().forEach {print("Pep boy \($0.0) is \($0.1)")}
    let pepboys = ["Manny", "Jack", "Moe"]
    let arr1 = pepboys.filter{$0.hasPrefix("M")} // ["Manny", "Moe"]
    let arr2 = pepboys.prefix{$0.hasPrefix("M")} // ["Manny"]
    let arr3 = pepboys.drop{$0.hasPrefix("M")} // ["Jack", "Moe"]

    Array和OC的关系

    如果一个NSArray没有任何额外信息则转化为[Any],NSArray中的对象都是class类型。把一个Array转化为NSArray没有额外的工作要做。

    let arr = [UIBarButtonItem(), UIBarButtonItem()]
    self.navigationItem.leftBarButtonItems = arr

    在Array上调用NSArray的方法需要转换:

    let arr = ["Manny", "Moe", "Jack"]
    let s = (arr as NSArray).componentsJoined(by:", ")
    // s is "Manny, Moe, Jack"

    不能把一个Array转化成一个NSMutableArray。如果需要调用NSMutabelArray的方法,使用NSMutableArray的构造函数创建一个。

    var arr = ["Manny", "Moe", "Jack"]
    let arr2 = NSMutableArray(array:arr)
    arr2.remove("Moe")
    arr = arr2 as! [String]

    在Xcode7以后,有些OC的API提供了额外的类型信息,比如:

    + (NSArray<NSString *> *)fontNamesForFamilyName:(NSString *)familyName;

    这时候返回的值就能直接转换为String。

    Dictionary

    Dictionary的语法:

    var d : [String:String] = [:]
    var d = [String:String]()
    var d = ["CA": "California", "NY": "New York"]

    两个Array,一个保存Key,一个保存Value,初始化一个Dictionary

    let abbrevs = ["CA", "NY"] 
    let names = ["California", "New York"]
    
    let tuples = zip(abbrevs, names) 
    let d = Dictionary(uniqueKeysWithValues: tuples)

    如果两个Array长度不同,zip自动忽略额外的部分,保证成对。

    从Dictionary中取出来的值是Opational的,因为如果不存在的话会返回nil。可以使用有默认值的方式获取

    let d = ["CA": "California", "NY": "New York"] 
    let state = d["MD", default:"N/A"] // state is a String (not an Optional)

    使用了default关键字返回的就是String而不是String?

    Dictionary的遍历:

    遍历key:

    var d = ["CA": "California", "NY": "New York"] 
    
    for s in d.keys { 
        print(s) // NY, then CA 
    
    }

    遍历key和value:

    var d = ["CA": "California", "NY": "New York"] 
    
    for (abbrev, state) in d { 
        print("\(abbrev) stands for \(state)") 
    
    }

    可以将Dictionary变成一个Tuple的Array:

    var d = ["CA": "California", "NY": "New York"] 
    let arr = Array(d) 
    // [(key: "NY", value: "New York"), (key: "CA", value: "California")]
    

    和NSDictionary的关系:

    NSDictionary对应[AnyHashable: Any],NSDictionary向Swift转换:

    let prog = n.userInfo?["progress"] as? Double 
    
    if prog != nil { 
        self.progress = prog!
    
    }

    Swift中使用Cocoa接口:

    UINavigationBar.appearance().titleTextAttributes = [
        .font: UIFont(name: "ChalkboardSE-Bold", size: 20)!, 
        .foregroundColor: UIColor.darkText, 
        .shadow.: {
            let shad = NSShadow()
            shad.shadowOffset = CGSize(width:1.5,height:1.5)
            return shad 
    
        }()
    ]

    Set

    let set : Set<Int> = [1, 2, 3, 4, 5]

    在Swift中Set没有字面变量,但是可以用Array构建。

    在Array中去重:

    let arr = [1,2,1,3,2,4,3,5] 
    let set = Set(arr) 
    let arr2 = Array(set) // [5, 2, 3, 1, 4], perhaps
    

    insert 和 update,假设Dog的比较函数是name相等。

    var set : Set = [Dog(name:"Fido", license:1)] 
    let d = Dog(name:"Fido", license:2) 
    set.insert(d) // [Dog(name: "Fido", license: 1)] 
    set.update(with:d) // [Dog(name: "Fido", license: 2)]
    

    当已经存在的时候,insert不会改变set,update更新set。

    两个set可以使用==比较,相等的条件是每一个元素相等。

    求两个Set的交集:

    intersection(_:)formIntersection(_:)

    求两个Set的并集:

    union(_:)formUnion(_:)

    求两个Set的异或:

    symmetricDierence(_:), formSymmetricDierence(_:)

    求两个Set的差集:

    subtracting(_:), subtract(_:)

    还有几个集合的函数,判断是不是子集,判断有没有相交等。

    Optional Set

    Optional Set是和NS_OPTIONS对应的。

    typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
    
        UIViewAnimationOptionLayoutSubviews = 1 << 0,
        UIViewAnimationOptionAllowUserInteraction = 1 << 1, 
        UIViewAnimationOptionBeginFromCurrentState = 1 << 2, 
        UIViewAnimationOptionRepeat = 1 << 3, 
        UIViewAnimationOptionAutoreverse = 1 << 4, 
        // ...
    
    };

    对应Swift中:

    UIViewAnimationOptions.layoutSubviews 
    UIViewAnimationOptions.allowUserInteraction 
    UIViewAnimationOptions.beginFromCurrentState 
    UIViewAnimationOptions.repeat 
    UIViewAnimationOptions.autoreverse
    

    UIViewAnimationOptions被定义为一个Set,这样就可以模拟bitmask了。

    var opts = UIViewAnimationOptions.autoreverse 
    opts.insert(.repeat)

    也可以使用运算符操作:

    let val = UIViewAnimationOptions.autoreverse.rawValue | UIViewAnimationOptions.repeat.rawValue 
    let opts = UIViewAnimationOptions(rawValue: val)

    控制结构

    if 语句

    if condition {
        statements
    } else if condition {
        statements
    } else {
        statements
    }

    条件语句不需要用括号括起来。

    条件绑定(conditional binding),这个在Optional变量的使用中非常常见

    if let prog = n.userInfo?["progress"] as? Double {
        self.progress = prog
    }

    等号后边是一个Optional Chain,可能返回nil,或者一个Double?,如果Optional Chain返回的是nil,则条件不成立,不会执行大括号内内容。如果Optional Chain不是nil,则==自动拆箱==,然后把拆箱后的值赋给prog,注意,==prog是Double而不是Double?==,prog的作用域在条件语句内部

    Switch 语句

    不用写break,自动break

    switch i {
    case 1:
        print("You have 1 thingy!")
    case 2:
        print("You have 2 thingies!")
    default:
        print("You have \(i) thingies!")
    }

    但是Switch的case语句必须覆盖所有情况,否则会发生编译错误。case语句也不能为空,至少要写一句break

    可以在case中定义变量

    switch i {
    case 1:
        print("You have 1 thingy!")
    case let n:
        print("You have \(n) thingies!")
    }

    如果i不是1,就将i赋值给n(好像并没有什么卵用)

    可以使用Range 匹配:

    switch i {
    case 1:
        print("You have 1 thingy!")
    case 2...10:
        print("You have \(i) thingies!")
    default:
        print("You have more thingies than I can count!")
    }

    Switch的另外一种用法:

    func position(for bar: UIBarPositioning) -> UIBarPosition {
        switch true {
        case bar === self.navbar:  return .topAttached
        case bar === self.toolbar: return .bottom
        default:                   return .any
        }
    }

    在switch中先指定结果(只能是true或者false),然后在case中判断表达式的结果是否和switch中相同。

    case语句中还可以加filter:

    switch i {
    case let j where j < 0:
        print("i is negative")
    case let j where j > 0:
        print("i is positive")
    case 0:
        print("i is 0")
    default:break
    }

    上述代码等价于:

    switch i {
    case ..<0:
        print("i is negative")
    case 1...:
        print("i is positive")
    case 0:
        print("i is 0")
    default:break
    }

    还可以判断对象类型:

    switch d {
    case is NoisyDog:
        print("You have a noisy dog!")
    case _:
        print("You have a dog.")
    }
    switch d {
    case let nd as NoisyDog:
        nd.beQuiet()
    case let d:
        d.bark()
    }

    注意:第二段代码中是as而不是as?,如果d是NoisyDog,nd才会被赋值,如果不是就不走这一个分支了。

    Switch还可以比较tuple:

    switch (d["size"], d["desc"]) {
    case let (size as Int, desc as String):
        print("You have size \(size) and it is \(desc)")
    default:break
    }

    如果switch的type是enum,那么还可以有很多花样:

    enum MyError {
        case number(Int)
        case message(String)
        case fatal
    }
    switch err {
    case .number(let theNumber):
        print("It is a number: \(theNumber)")
    case let .message(theMessage):
        print("It is a message: \(theMessage)")
    case .fatal:
        print("It is fatal")
    }
    switch err {
    case .number(1...):
        print("It's a positive error number")
    case .number(..<0):
        print("It's a negative error number")
    case .number(0):
        print("It's a zero error number")
    default:break
    }

    因为Optional本身是一个enum,所以可以这样写:

    switch i {
    case .none: break
    case .some(1):
        print("You have 1 thingy!")
    case .some(let n):
        print("You have \(n) thingies!")
    }

    fallthrough关键字:

    switch pep {
    case "Manny": fallthrough
    case "Moe": fallthrough
    case "Jack":
        print("\(pep) is a Pep boy")
    default:
        print("I don't know who \(pep) is")
    }

    if case

    if case let .number(n) = err {
        print("The error number is \(n)")
    }

    这是一个switch语句的简写,直接将err enum的Associated value取出来。

    条件赋值:

    let title : String = {
        switch type {
        case .albums:
            return "Albums"
        case .playlists:
            return "Playlists"
        case .podcasts:
            return "Podcasts"
        case .books:
            return "Books"
        }
    }()

    ??

    func tableView(_ tv: UITableView, numberOfRowsInSection sec: Int) -> Int {
        return self.titles?.count ?? 0
    }

    self.titles是[String]?类型,如果不是nil,拆箱,获取count属性;否则,返回0

    这段代码是什么意思?

    let someNumber = i1 as? Int ?? i2 as? Int ?? 0

    while

    两种方式:

    while condition {
        statements
    }
    
    repeat {
        statements
    } while condition
    

    for循环

    for…in

    for i in 1...5 {
        print(i) // 1, 2, 3, 4, 5
    }

    可以加filter:

    for i in 0...10 where i % 2 == 0 {
        print(i) // 0, 2, 4, 6, 8, 10
    }

    可以使用case简写:

    let arr : [MyError] = [
        .message("ouch"), .message("yipes"), .number(10), .number(-1), .fatal
    ]
    
    for case let .number(i) in arr {
        print(i) // 10, -1
    }

    stride

    for i in stride(from: 10, through: 0, by: -2) {
        print(i) // 10, 8, 6, 4, 2, 0
    }

    从10开始到0,步幅为-2,迭代。

    sequence

    sequence是一个函数,有两个参数,一个是初始值,一个是生成函数。sequence返回的是一个生成器,只有用的时候才会计算并返回下一个值。

    sequence用法:

    let seq = sequence(first:1) {$0 >= 10 ? nil : $0 + 1}
    for i in seq {
        print(i) // 1,2,3,4,5,6,7,8,9,10
    }

    或者:

    let seq = sequence(first:1) {$0 + 1}
    for i in seq.prefix(5) {
        print(i) // 1,2,3,4,5
    }

    jumping

    几个跳转的关键字:
    fallthrough,是switch case中执行下一个case的意思。
    continue,循环中,结束当前循环,从判断条件开始进行下一个循环。
    break,在循环中,跳出当前循环,在switch…case中,跳出switch语句。

    Swift中的循环可以带label,这样嵌套循环中的break和continue可以指定跳出哪一个循环。

    outer: for i in 1...5 {
        for j in 1...5 {
            print("\(i), \(j);")
            break outer
        }
    }
    // 1, 1;

    Error

    Swift采用throw…catch的方式来管理错误。

    error定义:

    enum MyFirstError : Error {
        case firstMinorMistake
        case firstMajorMistake
        case firstFatalMistake
    }
    enum MySecondError : Error {
        case secondMinorMistake(i:Int)
        case secondMajorMistake(s:String)
        case secondFatalMistake
    }

    使用:

    do {
        // throw can happen here
    } catch MyFirstError.firstMinorMistake {
        // catches MyFirstError.firstMinorMistake
    } catch let err as MyFirstError {
        // catches all other cases of MyFirstError
    } catch MySecondError.secondMinorMistake(let i) where i < 0 {
        // catches e.g. MySecondError.secondMinorMistake(i:-3)
    } catch {
        // catches everything else
    }

    抛出错误的函数需要在参数后边上throws关键字

    enum NotLongEnough : Error {
        case iSaidLongIMeantLong
    }
    func giveMeALongString(_ s:String) throws {
        if s.characters.count < 5 {
            throw NotLongEnough.iSaidLongIMeantLong
        }
        print("thanks for the string")
    }

    throws也是函数签名的一部分,giveMeALongString的函数签名就是(String) throws -> ()

    含有throws的函数必须使用try调用,try语句必须在do…catch中,或者是另外一个throws的函数中。

    try!,这个try!的意思是这个函数虽然被标记为throws,但是我知道它肯定不会throw错误,try!是不需要do…catch或者throws函数中使用的。但是如果真的throw的错误,程序就会Crash。

    同样有一个try?的作用在try和try!之间。try?可以在任何地方调用,但是会吞掉error。如果函数返回一个Optional,则返回nil。

    rethrows关键字

    一个参数中有接受throws函数的函数,如果自己本身不会throw error,则可以标记为rethrows。标记了rethrows关键字的函数,可以接受throw函数或者非throw的函数,如果调用者传入的参数是非throw的函数,那么可以不使用try来调用这个函数。擦!

    func receiveThrower(_ f:(String) throws -> ()) rethrows {
        try f("ok?")
    }
    func callReceiveThrower() { // no throws needed
        receiveThrower { s in // no try needed
            print("thanks for the string!")
        }
    }

    Swift和OC的错误处理转换:

    在OC中NSString有一个初始化函数:

    - (instancetype)initWithContentsOfFile:(NSString *)path
                                  encoding:(NSStringEncoding)enc
                                     error:(NSError **)error;

    需要传入一个NSError的地址,如果初始化失败,则返回nil,错误信息在NSError中。

    在Swift中这个初始化函数变成了throw的:

    init(contentsOfFile path: String, encoding enc: String.Encoding) throws

    所以OC中的传入NSError地址的函数,全都被Swift中的throw函数替代。

    do {
        let f = // path to some file, maybe
        let s = try String(contentsOfFile: f)
        // ... if successful, do something with s ...
    } catch CocoaError.fileReadNoSuchFile {
        print("no such file")
    } catch {
        print(error)
    }

    由Swift的Error转换陈NSError的时候,domain属性不变,code是enum的case的index

    do … break

    给do语句块加一个label,在语句块内部使用break label的时候就能跳出语句块。

    out: do {
        // ...
        if somethingBadHappened {
            break out
        }
        // we won't get here if somethingBadHappened
    }

    defer

    defer的语句在离开当前的大括号之前一定会执行。比如一个释放资源的代码,在函数的任何一个退出分支都需要写,很容易遗忘。使用defer语句可以避免这个麻烦。

    func doSomethingTimeConsuming() {
        defer {
            UIApplication.shared.endIgnoringInteractionEvents()
        }
        UIApplication.shared.beginIgnoringInteractionEvents()
        // ... do stuff ...
        if somethingHappened {
            return
        }
        // ... do more stuff ...
    }

    defer语句要写在尽可能靠前的位置,如果在return之后,那么defer语句是不会执行的。

    abort

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    就是直接让程序挂掉,应该是一种调试手段。

    assert还是可以使用的。

    guard

    guard是为了解决if false return 这样的嵌套问题的。是一个简写。

    guard let s = optionalString else {return}
    // s is now a String (not an Optional)

    相当于

    let s = optionalString
    if s == nil {
        return
    }

    guard可以和try?合起来使用:

    let f = // path to some file, maybe
    guard let s = try? String(contentsOfFile: f) else {return}
    // s is now a String (not an Optional

    和case合起来使用:

    guard case let .number(n) = err else {return}
    // n is now the extracted number

    和表达式一起使用:

    guard howMany() > 10 else {return}
    展开全文
  • 之前Swift一直不稳定,看过书,读过blog,今天开始,我以对比(OC:Swift)的形式将swift中常见的语法,以及注意事项,欢迎大家跟我一起学习Swift。// 1.导入框架 // OC导入框架 #import &lt;UIKit/UIKit.h&....

    Swift,苹果于2014年在苹果开发者大会发布的新开发语音,可与OC共同运行于Mac OS 和ios平台,用于搭建基于苹果平台的应用程序。之前Swift一直不稳定,看过书,读过blog,今天开始,我以对比(OC:Swift)的形式将swift中常见的语法,以及注意事项,欢迎大家跟我一起学习Swift。

    // 1.导入框架
    // OC导入框架   #import <UIKit/UIKit.h>
    // Swift 导入框架   import UIKit
    
    // 2.定义变量
    // OC 定义变量int a = 10; a = 5;
    // Swift 定义变量  var a:Int = 10
    
    // 3.定义常量
    // OC:  const int a = 5;
    // Swift:   let a:Int = 5;
    
    // 4.创建对象
    // OC:  UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    //      [view setBackgroundColor:[UIColor redColor]];
    // Swift:  let view:UIView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    //      view.backgroundColor = UIColor.red;
    
    // 5.控制台输出
    // OC:   int const a = 10; NSLog(@"a=%zd",a);
    // Swift:   let a:Int = 10; print("a=\(a)");


        


    展开全文
  • 目前随着公司开发模式的变更,swift也显得越发重要,相对来说...好了,废话不多说了,直接把我对swift的语法的一些理解奉献给大家,希望能对学习swift语法的朋友有所帮助,如有不足之处,还请多多包涵,如果有错误之处,欢迎指正
  • 无论是手机,台式机,服务器还是其他运行代码的软件,Swift都是一种非常好的编写软件的方法。它是一种安全,快速和互动的编程语言,结合了最好的现代语言思维与更广泛的苹果工程文化的智慧和来自开源社区的多样化...
  • 总结 加上写博文的时间,用了前前后后一周左右的时间,每晚2小时左右,完成了这个改造,由于我是第...期间还简单学习了一下swift基本语法和部分用法。下面主要说一下我对swift语言的看法以及这次改造中对swift的理解。
  • Swift4 学习笔记——高级篇
  • 本书 精通 Swift 4 (Mastering Swift 4.0)是 非扫描版PDF 作者是 Jon Hoffman
  • Swift 学习

    2018-01-28 22:55:56
    周末闲来无事,接触一下swift, 在Xcode的playground上玩儿swift还很好玩儿的,会一边编写代码一边检查一遍即使显示 基础 基本类型 Int Double Float String Bool let c = 1_000_000_000 let d:Int = 1 let...
  • 使用最新swift 4编写练习项目,帮助快速掌握学习swift语言
  • Swift4 快速体验

    2017-12-26 19:19:28
    前言本章内容完全是描写苹果新语言的基础练习,对于初学者来说是非常好用,好学、升级了编辑器Xcode9快速体验Swift4语法 print("Hello, world!")就是这么简单的打印 该内容基于语法教程,更多内容可以去Develpoer去...
  • 本人最近开始学习有关Swift这个新东东,由于没有项目支撑,只能通过官方文档进行自学,精简的看了Swift官方文档,感觉理解起来还是比较简单,于是突发奇想,想把官方object-c的sample进行改造,使用Swift完成重点...
  • 本人正在学习ios开发,本来是打算学object-c 的,但发现 apple发布了新的开发语言swift。就打算从这个 swift入手吧!做开发5年了,用的c/c++,一直给别人打工。从做开发起就一直想整一些自个的的东东,最好再能赚点钱...
  • 原文:http://www.coolketang.com/staticCoding/5a9923b4ac502e5d51cb3dc6.html1. Playground是苹果推出的一款用来学习、演示Swift语言的实用工具,本节课将为您演示它的使用方法。首先点击欢迎面板中的[以...
  • swift入门教程面向单位实际需求,资深讲师,提供实用swift课程,swift案例教学,从swift基础到项目实战,解决工作中实际问题,ios开发入门必选课程,全面学习Swift编程语言的技术体系,通过大量案例掌握Swift在项目开发中的...
  • 适用人群:适用于学习swift语言的人们 ~第1章 欢迎来到Swift语言的世界 1.1 起源 1.2 什么是Swift语言 1.3 特点 1.3.1 高级 1.3.2 易上手 1.2.3 兼容性 1.3.4 运行效率 1.3.5 运行
  • Swift学习总结

    2018-11-06 09:59:41
    Swift学习 ##1、常量、变量 var / let ####注意一: 在开发中优先使用常量let,只有发现需要修改的情况,才使用变量。 目的: 防止不小心修改的值情况。 ####注意二: 常量的本质: 指向内存地址,不可修改,但是...
  • 本系列只是一个Swift快速入门的教程,并没有详尽的介绍Swift,Swift也并不是一个简单的编程语言,所以要想详尽的系统的学习Swift,本系列并不适合你,此系列只是让开发者可以快速的用Swift来进行开发。另外学习本...
1 2 3 4 5 ... 20
收藏数 20,414
精华内容 8,165
关键字:

4学习 swift