www.weide1946.com关东升出品,从0开始学Swift笔记整理

2019-09-17 07:45 来源:未知

之前很多同学私信小编,想要一些IOS开发相关的学习内容,推荐一下关东升老师的Swift学习笔记(另外各位同学,今天早晨你们的闹铃都响了吗?):

最近瞄上了Swift,随着3.0版本的发布,1.x,2.x的部分API发生了一些算是较大的变化,语法越来越简便,实质内容还是保持不变,断断续续的接触了Swift几个月,总算是基本掌握了这门语言。Swift 采用安全的编程模式并添加了很多新特性,这将使编程更简单,更灵活,也更有趣。Swift 是基于Cocoa 和 Cocoa Touch 框架演变而来。

这是跟在上一篇博文后续内容:

——我的第一行Swift代码

Swift给我的感觉就像一个天资聪慧的灵童,彷佛什么都懂,既有现有语言优良的传统(面向对象),又继承了其兄OC另辟蹊径的的方式(扩展,代理,面向协议),而苹果为了更快的推广这门语言,不惜放弃专制,居然开源了,虽然这很不苹果,但谁都能看得出来这都是OC留下的祸根啊。Swift可以跨平台运行,未来能不能在windows上玩一把就不得而知了。这里就不扯OC和Swift到底谁好谁坏,如:PHP是世界上最好的语言。

——Core Foundation框架

Core Foundation框架是苹果公司提供一套概念来源于Foundation框架,编程接口面向C语言风格的API。虽然在Swift中调用这种C语言风格的API比较麻烦,但是在OS X和iOS开发过程中,有时候使用Core Foundation框架的API是非常方便的,例如在与C语言混合编码的时候。
Core Foundation框架与Foundation框架紧密相关,他们具有与相同的接口,但是不同。Core Foundation框架是基于C语言风格的,而Foundation框架是基于Objective-C语言风格的。在OS X和iOS程序代码中经常会有多种语言风格的代码混合在一起的情况,这使得我们开发变得更加麻烦。
数据类型映射
Core Foundation框架提供了一些不透明的数据类型,这些数据类型封装了一些数据和操作,他们也可以称为“类”,他们都继承于CFType类,CFType是所用Core Foundation框架类型的根类。这些数据类型在Foundation框架中都有相应的数据类型与之对应,这些数据类型也有一些与Swift原生数据类型有对应关系。

看看Swift原生类型与Core Foundation类型之间的转换示例:

import CoreFoundation

import Foundation

var cfstr1: CFString = "Hello,World"    //创建CFString字符串

var str: String = cfstr1 as String     //将CFString字符串转换为Swift原生字符串Stringvar cfstr2: CFString = str            //将Swift原生字符串String转换为CFString字符串

这个转换过程中Core Foundation类型转换为Swift原生类型是需要强制类型转换的。

——使用Web网站编写Swift代码

PS:在学习的过程中,收获颇丰,借助老关的帮助,对比OC和Swift同步进阶。不得不说老关的书作为初级,进阶和工具书都是极好的,在此推荐一下:传送门:Swift(关东升著)

——Core Foundation框架之内存管理

在Swift原生数据类型、Foundation框架数据类型和Core Foundation框架数据类型之间转换过程中,虽然是大部分是可以零开销桥接,零开销并不意味着内存什么都不用管。Swift类型内存管理是采用ARC,Foundation类型和Core Foundation类型内存管理都是采用MRC或ARC,Core Foundation类型内存管理是基于C语言风格的,它有一个对象所有权的概念。
Objective-C的MRC内存管理
Core Foundation的内存管理与Objective-C的MRC内存管理密不可分,先介绍一下Objective-C的MRC内存管理。
所有Objective-C类都继承NSObject类,每个NSObject对象都有一个内部计数器,这个计数器跟踪对象的引用次数,被称为“引用计数”(Reference Count,简称RC)。当对象被创建时候,引用计数为1。为了保证对象的存在,可以调用retain方法保持对象,retain方法会使其引用计数加1,如果不需要这个对象可以调用release或autorelease方法,release或autorelease方法使其引用计数减1。当对象的引用计数为0的时候,系统运行环境才会释放对象内存。
引用计数示例如图所示,首先在第①步调用者A中创建了一个NSObject对象,这时该对象引用计数为1。在第②步调用者B中想使用这个NSObject对象,于是使用NSObject对象引用,但是为了防止使用过程中NSObject对象被释放,可以调用retain方法使引用计数加1,这时引用计数为2。在第③步调用者A中调用release或autorelease方法,使引用计数减1,这时引用计数为1。在第④步调用者C中调用release或autorelease方法,只是获得NSObject对象引用,并没有调用retain、release或autorelease方法,因此没有引起引用计数的变化。在第⑤步调用者B中调用release或autorelease方法使引用计数减1,这时引用计数为0。这个时候NSObject对象就内存就可以释放了。

来总结一下:

  1. 谁创建或拷贝对象,他也一定要负责调用NSObject对象release或autorelease方法,使引用计数减1,如图中调用者A在第①步,负责创建了NSObject对象,那么调用者A也必须是负责使引用计数减1,见第④步。
  2. 谁调用retain方法使引用计数加1,它也一定要负责调用NSObject对象release或autorelease方法,使引用计数减1,如图中调用者B在第②步,调用者B调用NSObject对象retain方法使引用计数加1,那么调用者B也必须是负责使引用计数减1,见第⑤步。
    对象所有权
    一个对象可以有一个或多个所有者,从所有者的角度看是对这个对象具有了“所有权”,从上图中看,调用者A和调用者B是所有者,他们可能是一段程序,可能是一个对象。他们对NSObject对象具有所有权,不再使用时候他们应该负责放弃对象所有权,当对象没有所有者时,引用计数为0,它才可以被释放。
    如上图如果按照对象所有权解释:调用者A创建或拷贝NSObject对象,这时调用者A就具有了NSObject对象的所有权,见第①步。调用者B调用NSObject对象retain方法,就获得了也NSObject对象的所有权,见第②步。调用者A调用NSObject对象release方法,放弃NSObject对象的所有权,见第③步。调用者C只是使用NSObject对象没有获得NSObject对象的所有权,见第④步。调用者B调用NSObject对象release方法,放弃NSObject对象的所有权,见第⑤步,但是调用者B使用这个NSObject对象过程中,由于其他调用者放弃所有权,导致NSObject对象被释放,那么调用者B中程序就会发生运行期错误。

——Swift 2.0之后增加的关键字

一、基础篇

.......................................

类型 Swift Object-C 备注
整型 Int8 Int32 UInt8 UInt64 NSInteger 32位平台上 Int = Int32 (64 Int = Int64)
浮点型 Float Double NSFloat,NSDouble 32位浮点数,64位浮点数
布尔型 True, False YES,NO 严格true为真,false为假
字符型 Character NSString -
字符串 String NSString -
元组 Tuple () - (“1001”,“张三”,"18岁")
集合 Array,Dictionary,Set NSArray,NSDictionary,NSSet -
枚举 Enum Enum -
结构体 Struct Struct -

——Core Foundation框架之内存托管对象与非托管对象

Swift中调用Core Foundation函数获得对象时候,对象分为:内存托管对象和内存非托管对象。

·内存托管对象 内存托管对象就是由编译器帮助管理内存,我们不需要调用CFRetain函数获得对象所有权,也不需要调用CFRelease函数放弃对象所有权。
获得这些内存托管对象的方法,是采用了CF_RETURNS_RETAINED或CF_RETURNS_NOT_RETAINED注释声明

func CFStringCreateWithCString(_ alloc: CFAllocator!, 

_ cStr: UnsafePointer<Int8>,

_ encoding: CFStringEncoding) -> CFString!    //内存托管对象

func CFHostCreateCopy(_ alloc: CFAllocator?,

_ host: CFHost) -> Unmanaged<CFHost>        //内存非托管对象

·内存非托管对象
内存非托管对象就是内存需要程序员自己管理。这是由于在获得对象的方法中没有使用CF_RETURNS_RETAINED或CF_RETURNS_NOT_RETAINED注释声明,编译器无法帮助管理内存。在具体使用时候我们可以上一节的方法判断是否为非内存托管对象。
内存非托管对象使用起来有些麻烦,要根据获得所有权方法,进行相应的处理。

  1. 如果一个函数名中包含Create或Copy,则调用者获得这个对象的同时也获得对象所有权,返回值Unmanaged<T>需要调用takeRetainedValue()方法获得对象。调用者不再使用对象时候,Swift代码中需要调用CFRelease函数放弃对象所有权,这是因为Swift是ARC内存管理的。
  2. 如果一个函数名中包含Get,则调用者获得这个对象的同时不会获得对象所有权,返回值Unmanaged<T>需要调用takeUnretainedValue()方法获得对象。

——用Playground工具编写Swift

1.可选类型

swift要求所有的数据类型声明的变量或常量都是不能为nil的,所以必须对其进行初始化,初始化如果不确定其值的时候,可以采用可选类型(俗称的(?)和(!)), 在不能保证可选类型值是否为空之前最好不要拆包,否则可能编译报错。他们两个区别主要是在可选类型的拆包,拆包是将可选类型转变成普通类型。拆包分为显示拆包和隐性拆包。
例如 var n1 : Int? = 10 输出内容为:Optional(10) 说明变量n1不是普通类型

  • 显示拆包
    使用问号(?)声明的可选类型在拆包的时候需要使用感叹号(!)
var n1 : Int? = 10
print(n1!   10)
  • 隐性拆包
    使用感叹号(!)声明的可选类型在拆包时不需要使用感叹号(!)
var n2 : Int! = 10
print(n1   10)

——Cocoa Touch设计模式及应用之单例模式

什么是设计模式。设计模式是在特定场景下对特定问题的解决方案,这些解决方案是经过反复论证和测试总结出来的。实际上,除了软件设计,设计模式也被广泛应用于其他领域,比如UI设计和建筑设计等。
下面来介绍Cocoa Touch框架中的设计模式中的单例模式。
单例模式
单例模式的作用是解决“应用中只有一个实例”的一类问题。在Cocoa Touch框架中,有UIApplication、NSUserDefaults和NSNotificationCenter等单例类。另外,NSFileManager和NSBundle类虽然属于Cocoa框架的内容,但也可以在Cocoa Touch框架中使用(Cocoa框架中的单例类有NSFileManager、NSWorkspace和NSApplication等)。
问题提出
在一个应用程序的生命周期中,有时候只需要某个类的一个实例。例如:当iOS应用程序启动时,应用的状态由UIApplication类的一个实例维护,这个实例代表了整个“应用程序对象”,它只能是一个实例,其作用是共享应用程序中的一些资源、控制应用程序的访问,以及保持应用程序的状态等。
解决方案
单例模式的实现有很多方案,苹果公司在《Using Swift with Cocoa and Objective-C》官方文档中给出了一种单例模式的实现。最简单形式代码如下:

class Singleton {

    static let sharedInstance = Singleton()

}

上述代码采用static的类属性实现单例模式,这种类属性只被延迟加载执行一次,即便是在多线程情况下也只是执行一次,并且保证是线程安全的。
如果需要进行一些初始化,可以使用如下带有闭包形式代码:

class Singleton {

    static let sharedInstance: Singleton = {

        let instance = Singleton()

        // 初始化处理

        return instance

    }()

}

——我所知道的标识符和关键字

2.Swift3.0字符串用法改动

  • swift3.0关于字符串string的部分API改动较大,这里列举了一下:
import Foundation

//---------字符串定义-----------

//字符串变量
var str1 = "hello"

//字符串常量
let str2 = "swift3.0"

//声明为nil,
var str3:String?  //可选类型

//空字符串
let str4 = String()
let str5 = ""     //提倡用这样的字面量语法声明,类型可不指定,swift自动识别

//字符
var char1:Character = "m"
var p_str1 = ""

//字符串拼接
p_str1 = str1   str2
print(p_str1)
p_str1 = String(format:"%@~%@",str1,str2)
print(p_str1 as String);//hello~swift3.0
p_str1 = String(format:"%@~%@-%d",str1,str2,456)

print(p_str1);

//这种拼接方式方便地组合多种类型
p_str1 = "(str1)(str2)(456)"
print(p_str1);//helloswift3.0456
p_str1 = "(str1)(str2)(char1)"

print(p_str1);

//在字符串后面添加
p_str1.append(char1)
print(p_str1);
p_str1  = str2

print(p_str1);

//与数组通过指定字符拼接
var strArray = ["hello", "swift", "3.0"]
p_str1 = strArray.joined(separator: "-")//数组通过指定字符拼接

print("数组通过指定字符拼接(p_str1)");


//拆分为指定的字符
strArray = p_str1.components(separatedBy: "-")
print("拆分为数组(strArray)");

print("p_str1字符串为:(p_str1)");


//枚举字符
for ch in p_str1.characters{

    print(ch)

    switch ch {
    case "0":
        print("有该字符")
    default:
        break
    }
}


print(p_str1)

//字符串长度
print("p_str1长度为:(p_str1.characters.count)");

//首字母
char1 = p_str1[p_str1.startIndex]
print("首字母(char1)");

//末字母
char1 = p_str1[p_str1.index(before: p_str1.endIndex)]
print("末字母(char1)")

//第二个字母
char1 = p_str1[p_str1.index(after: p_str1.startIndex)]
print("第二个字母(char1)")

//索引4的字母
char1 = p_str1[p_str1.index(p_str1.startIndex, offsetBy: 4)]
print("索引4的字母(char1)")


//字符串截取
let i = p_str1.index(p_str1.startIndex, offsetBy: 4)
let j = p_str1.index(p_str1.startIndex, offsetBy: 8)

print(i,j);

var subStr = p_str1.substring(to: i)
print("截取到4(subStr)")

subStr = p_str1.substring(from: i)
print("从索引4开始截取(subStr)")

subStr = p_str1.substring(with: i..<j)
print("从索引4开始到8(不截取索引为8的字符)结束截取(subStr)")

//通过扩展来简化一下

extension String{

    subscript (range: Range <Int>) -> String{

        get{

            let startIndex = self.index(self.startIndex, offsetBy:range.lowerBound)
            let endIndex = self.index(self.startIndex,offsetBy:range.upperBound)
            return self[Range(startIndex..<endIndex)]

        }

        set{

            let startIndex = self.index(self.startIndex,offsetBy:range.lowerBound)
            let endIndex = self.index(self.startIndex,offsetBy:range.upperBound)
            let strRange = Range(startIndex..<endIndex)

            self.replaceSubrange(strRange, with: newValue)

        }

    }

}

//通过扩展截取字符串
subStr = p_str1[0..<5]



print(p_str1)
//通过指定字符串截取子串
let range1 = p_str1.range(of: "o-")
let range2 = p_str1.range(of: ".")

subStr = p_str1.substring(from: (range1?.upperBound)!)
print("从o-开始截取字符串:(subStr)")

subStr = p_str1.substring(with: (range1?.upperBound)!..<(range2?.lowerBound)!)
print("从o-开始到.结束截取字符串:(subStr)")


print(subStr)
//插入指定字符串
subStr.insert("!", at: subStr.startIndex)
print(subStr);

subStr.insert("!", at: subStr.endIndex)
print(subStr);

subStr.insert(contentsOf:"YY".characters, at: subStr.index(after: subStr.startIndex))
print(subStr);

subStr.insert(contentsOf:"MM".characters, at: subStr.index(before: subStr.endIndex))
print(subStr)

//打印字符串的索引
let x = p_str1.index(p_str1.startIndex, offsetBy: 4)
print(x)

print(subStr)
//删除指定字符串
subStr.remove(at: x)
print("删除索引为4的字符后得到的字符串(subStr)")

subStr.remove(at: subStr.startIndex)
print("删除索引为0的字符后得到的字符串(subStr)")

subStr.remove(at: subStr.index(after: subStr.startIndex))
print("删除索引为0的字符后得到的字符串(subStr)")

subStr.remove(at: subStr.index(before: subStr.endIndex))
print("删除最后一个索引的字符后得到的字符串(subStr)")


//删除范围字符串
let ran1 = subStr.index(subStr.endIndex, offsetBy: -3)..<subStr.endIndex
subStr.removeSubrange(ran1)
print("删除从索引为倒数第3之后所有的字符串后得到的字符串(subStr)")

let ran2 = subStr.index(subStr.startIndex, offsetBy: 4)..<subStr.endIndex
subStr.removeSubrange(ran2)
print("删除从索引为4之后所有的字符串后得到的字符串(subStr)")


subStr = "http://baidu.com"
let ran3 = subStr.range(of: ":")
let ran4 = subStr.range(of: ".")

subStr.removeSubrange((ran3?.upperBound)!..<(ran4?.lowerBound)!)
print("删除从:开始到.之间的字符串后得到的字符串(subStr)");

//字符串替换
subStr.replaceSubrange(ran3!, with: "wert")
print("ran3被wert替换之后的字符串(subStr)");


//全部返回为布尔类型  Bool类型
//判断字符串是否有前、后缀
p_str1.hasPrefix("3.0")
p_str1.hasSuffix("3.0")

//判断字符串是否为空
p_str1.isEmpty
str3?.isEmpty
str4.isEmpty
str5.isEmpty


//--- 大小写转换 -----------
subStr = "ashdfasdjf"

print("subStr.capitalized(首字母大写)方法:(subStr.capitalized)")
print("subStr.uppercased()大写方法:(subStr.uppercased())")
print("subStr.lowercased()小写方法:(subStr.lowercased())")

//--- 字符串比较 -----------
subStr = "2.6.2"
p_str1 = "2.6.1"
str1 = "2.7"
str3 = "2.7.0"
subStr > p_str1
subStr > str1
str1 == str3
str1 > str3!
str1 < str3!

//--- 字符串转换 -----------
Int(str1)
Double(str1)
Double(str3!)
Bool(str1)
str1 = "true"
Bool(str1)

——Cocoa Touch设计模式及应用之目标与动作

目标(Target)与动作(Action)是iOS和OS X应用开发的中事件处理机制。

要实现目标与动作的连接有两种方式:Interface Builder连线实现和编程实现。

  1. Interface Builder连线实现
    Interface Builder连线实现就是故事板或Xib文件中,通过连线而现实。
  2. 编程实现
    编程实现是通过UIControl类addTarget(_:action:forControlEvents:)方法实现的,主要代码如下:

class ViewController: UIViewController {

 

    override func viewDidLoad() {

    super.viewDidLoad()

 

    self.view.backgroundColor = UIColor.whiteColor()

 

    let screen = UIScreen.mainScreen().bounds;

    let labelWidth:CGFloat = 90

    let labelHeight:CGFloat = 20

    let labelTopView:CGFloat = 150

    let label = UILabel(frame: CGRectMake((screen.size.width

             -labelWidth)/2 , labelTopView, labelWidth, labelHeight))

 

    label.text = "Label"

    //字体左右剧中

    label.textAlignment = .Center

    self.view.addSubview(label)

 

    let button = UIButton(type: UIButtonType.System)// 创建UIButton对象

    button.setTitle("OK", forState: UIControlState.Normal)   

 

    let buttonWidth:CGFloat = 60

    let buttonHeight:CGFloat = 20

    let buttonTopView:CGFloat = 240

 

    button.frame = CGRectMake((screen.size.width

         - buttonWidth)/2 , buttonTopView, buttonWidth, buttonHeight)

 

    button.addTarget(self, action: "onClick:",

                     forControlEvents: UIControlEvents.TouchUpInside)

 

    self.view.addSubview(button)   

        }

 

    func onClick(sender: AnyObject) {   

        NSLog("OK Button onClick.")

    }   

        ...

}

上述代码中创建并设置UIButton对象,其中创建UIButton对象,参数type是设置按钮的样式,UIButton样式:

  • Custom。自定义类型。如果不喜欢圆角按钮,可以使用该类型。
  • System。系统默认属性,表示该按钮没有边框,在iOS 7之前按钮默认为圆角矩形。
  • Detail Disclosure。细节展示按钮,主要用于表视图中的细节展示。
  • Info Light和Info Dark。这两个是信息按钮,样式上与细节展示按钮一样,表示有一些信息需要展示,或有可以设置的内容。
  • Add Contact。添加联系人按钮
  • 代码调用addTarget(_:action:forControlEvents:)方法,方法第一个参数是target,即事件处理对象,本例中是self;方法第二个参数是action,即事件处理对象中的方法,
    代码中是"onClick:",方法第三个参数是事件,TouchUpInside事件是按钮的触摸点击事件。
    如果调用如下无参数方法:

func onClick() {
}

调用代码如下:

button.addTarget(self, action: "onClick",

                Ê    forControlEvents: UIControlEvents.TouchUpInside)

区别在于action参数"onClick"方法名不同,action参数方法名的冒号暗示了方法名应该具有几个参数。如果要调用的方法是如下3个参数形式:

func onClick(sender: AnyObject, forEvent event: UIEvent) {

}

那么调用代码如下:

button.addTarget(self, action: "onClick:forEvent:",

                Ê    forControlEvents: UIControlEvents.TouchUpInside)

其中"onClick:forEvent:"是调用方法名,onClick表示方法名也是,forEvent表示第二个参数的外部参数名。

——哎呀常量和变量都该什么时候用啊?

3.控制语句

  • 分支语句 : if,switch和guard(新增)
    if后面的语句必须为bool类型,可以不加括号
    switch 可以支持Int,Float,Double,String,Tuple等AnyObject,无需break
    guard 是Swift2.x新增关键字,必须配合else使用,解决if-else多层嵌套问题,判断一个条件为true下执行某语句,否则终止或跳转执行其他语句

  • 循环语句 : while, repeat-while,for(改动),for-in
    for循环 摒弃掉了c的style,一律以...来替代,不得不说很赞。

for i in 1...arr.count{
      //循环体
}

swift专门提供了遍历集合的方法for-in

let numbers = [1,2,3,4,5,6,7,8,9,10]
for (index,element) in numbers.enumerate(){
      print("Item (index) : (element)")     //index和item都有了
}

swift中的for循环提供了类似NSRange方式的跨步查找方式

for index in stride(from: 1, through: 5, by: 2) { print(index)}
  • 跳转语句 : break,continue,fallthrough(新增),return,throw(新增)
    fall through 是贯通语句,只能在switch中使用,如果一个case执行完毕,需要执行另一个case,则需要用fallthough跳转至下一个case
    throw 在oc中的NSError一定很熟悉了,在swift里,借助java的try..catch语句可以将程序中抛出(throw)的异常收集起来。

  • 值绑定 : 常用于if,guard,switch,where
    在控制语句中将表达式的值临时赋给一个常量或者变量,这些常量或者变量可以在该控制语句中使用,称为"值绑定"。
    where语句类似于sql中的where语句,非常好用。

//switch中使用元祖类型
var student = (id:"1002",name:"李四",age:32, ChineseScore:80, EnglishScore:89)
var desc: String
switch student {
case (_, _, _, 90...100, 90...100) where age > 20:  //where语句
    desc = "优"
case (_, _, _, 80...90, 80...90):
    desc = "良"
case (_, _, _, 60...80, 60...80):
    desc = "中"
case (_, _, _, 60...80, 90...100), (_,_, _, 90...100, 60...80):
    desc = "偏科"
case (_, _, _, 0...80, 90...100), (_,_, _, 90...100, 0...80):
    desc = "严重偏科"
default:
    desc = "无"
}
print("说明:(desc)")

——Cocoa Touch设计模式及应用之选择器

实现目标与动作关联使用UIControl类addTarget(_:action:forControlEvents:)方法,示例代码如下:

button.addTarget(self, action: "onClick:",

             forControlEvents: UIControlEvents.TouchUpInside)

其中的action参数"onClick:"事实上就是选择器(Selector)。

通过选择器调用方法,关键是方法名字,它有一定规律的。穷其根本是源自于Objective-C多重参数方法命名规律。方法名的冒号暗示了方法名应该具有几个参数,下面我们看几个示例:

    //选择器为"onClick:"

    func onClick(sender: AnyObject) {

         NSLog("onClick:")

    }

 

    //选择器为"onClick:forEvent:"

    func onClick(sender: AnyObject, forEvent event: UIEvent) {   

          NSLog("onClick:forEvent:")

    }

 

    //选择器为"onClickWithExtSender:forEvent:"

    func onClick(extSender sender: AnyObject, forEvent event: UIEvent) {

          NSLog("onClickWithExtSender:forEvent:")

    }

出于数据封装的需要,我们会在方法前面加private,使其变为私有方法,代码如下。

    private func onClick(sender: AnyObject) {

          NSLog("onClick:")

    }

但是这样方法在调用时候会出现如下错误:
unrecognized selector sent to instance 0x7f7f81499b10'

这个错误的意思是没有找到选择器所指定的方法,也就是没有找到onClick:方法。正确的做法是在方法前面添加@objc属性注释,这说明选择器是在objc runtime运行环境下调用的。

    //选择器为"onClick:"

    @objc private func onClick(sender: AnyObject) {

           NSLog("onClick:")

    }

——Swift 2.0中的print函数几种重载形式

4.集合,函数,闭包

  • 集合,函数,闭包都是oc中常用的,就不多做介绍。
//Array
//swift中没有提供二维数据,只有一维数组
var arr1 = [String]()
var arr2 = [Int]()
var arr3 = [AnyObject]()
var arr4 = ["1","2","3"]
arr1 = ["1","2","3"]
arr2 = [1,2,3]
arr3 = [1 as AnyObject,"2" as AnyObject,3 as AnyObject,4.4 as AnyObject]

arr1.first //第一个元素
arr1.last  //最后一个元素
arr1.contains("9")//是否存在该元素
arr2.contains(3)
arr1.count
let bool1 = arr1 == arr4 //两数组是否相等
//增删改查
arr1  = arr1
arr1.insert("9", at: 4)
arr1.append("10")
arr1.remove(at: 6)
arr1[0] = "123"
let bool2 = arr1 == arr4 //两数组是否相等

for item in arr1 {
    print(item)
}
for (i,item) in arr1.enumerated() {
    if item == "2" {
        print(item)
        break
    }
}

//Dictionary
var dic1 = [String:Any]()
var dic2 = [Int:Int]()
let dic3 = [1:"4",2:"5",3:"6"]
let dic4 = ["2":"相同key值在合并的时候会替换","w":"5","e":dic3] as [String : Any]
dic1 = ["1":"qw","2":45,"3":UIView(),"4":dic3]
dic2 = [1:4,2:5,3:6]
print(dic1)
//遍历
for value in dic1.values {
    if let val = value as? UIView {
        val.frame = CGRect(x: 10, y: 150, width: 250, height: 250)
    }
}
print(dic1)
for key in dic1.keys {
    print(key)
}
for (key,value) in dic1 {
    print("key:(key) -- value:(value)")
}
//增删改查
dic1["增加"] = "增加的内容"
print(dic1)
dic1.removeValue(forKey: "4")
print(dic1)
dic1["2"] = 678
print(dic1)
(dic1["3"] as! UIView).frame = CGRect(x: 100, y: 100, width: 200, height: 200)
print(dic1)
//查询
if let value = dic1["2"] {
    print("value =>(value)" )
}else{
    print("value => 没有" )
}
if let value = dic1["2"] as? String {
    print("value =>(value)" )
}else{
    print("value => 没有" )
}
if let value = dic1["22"] {
    print("value =>(value)" )
}else{
    print("value => 没有" )
}
if let value = dic1["22"] as? String {
    print("value =>(value)" )
}else{
    print("value => 没有" )
}
//----重载运算符 更方便实现两个字典合并为一个字典
func  = <key, value> ( left: inout Dictionary<key, value>, right: Dictionary<key, value>) {
    for (k, v) in right {
        left.updateValue(v, forKey: k)
    }
}
dic1  = dic4
print(dic1)
dic1 = dic4
print(dic1)
dic1.isEmpty
dic1.removeAll()
dic1.isEmpty

//函数
 func <#name#>(<#parameters#>) -> <#return type#> {
        <#function body#>
    }

——Cocoa Touch设计模式及应用之通知机制

通知(Notification)机制是基于观察者(Observer)模式也叫发布/订阅(Publish/Subscribe)模式,是 MVC( 模型-视图-控制器)模式的重要组成部分。

在软件系统中,一个对象状态改变也会连带影响其他很多对象的状态发生改变。能够实现这一需求的设计方案有很多,但能够做到复用性强且对象之间匿名通信的,观察者模式是其中最为适合的一个。

通知机制可以实现“一对多”的对象之间的通信。如图所示,在通知机制中对某个通知感兴趣的所有对象都可以成为接收者。首先,这些对象需要向通知中心(NSNotificationCenter)发出addObserver消息进行注册通知,在投送对象通过postNotificationName消息投送通知给通知中心,通知中心就会把通知广播给注册过的接收者。所有的接收者都不知道通知是谁投送的,更不关心它的细节。投送对象与接收者是一对多的关系。接收者如果对通知不再关注,会给通知中心发出removeObserver消息注销通知,以后不再接收通知。

——小小常量、变量大作用

5.其他

  • 恒等于(===)
    ===用于比较两个引用是否为同一个实例

  • 不恒等于(!==)
    !== 只能用于引用类型,类的实例

  • 访问级别
    public:可以访问自己模块中的任何public实体
    internal:只能访问自己模块的任何internal实体
    private:只能在当前源文件中使用的实体

  • 关键字
    lazy: 延时加载
    static: 静态属性
    override: 重写
    final: final声明的类不能被继承,属性,方法,下标不能被重写
    //待补充

  • 构造与析构
    结构体和类创建实例需要进行一些初始化工作,init(),deinit()
    析构函数只适用于类,C 中析构函数用来释放不再需要的内存资源,但是在oc和swift中内存管理采用引用计数(ARC)不需要析构函数释放资源,但有一些资源清理的工作需要在deinit()中完成,例如关闭文件,关闭数据库等

  • 类构造函数横向代理
    在定义构造函数时可以通过其他构造函数来完成实例部分构造过程,叫做构造函数代理。
    由于类有继承关系,类构造函数代理比较复杂,分为横向代理和向上代理
    => 横向代理发生在同一类内部,称为便利构造函数(convenience initializer)
    => 向上代理发生在继承情况下,在子类构造过程中要先调用父类构造函数,初始化父类存储属性,称为制定构造函数(designated initializer)

class Rectangle{
  var width : Double
  var height: Double

  init(width: Double,height:Double){
    self.width = width
    self.height = height
  }

 convenience init(length: Double){
    self.init(W: length, H: height)
  }

}
  • 类继承
    安全检查1:指定构造函数必须保证其所在类的所有存储属性都初始化完成,之后才能向上调用父类构造函数代理
    安全检查2:指定构造函数必须先向上调用父类构造函数代理,然后再为继承的属性设置新值,否则指定构造函数赋予的新值将被父类的构造函数覆盖。
    安全检查3:便利构造函数必须先调用同一类中的其他构造函数代理,然后再为任意属性赋新值。
    安全检查4:构造函数在第一阶段构造完成之前不能调用实例方法,也不能读取实例属性,因为不能保证要访问的实例属性已被初始化。

  • 类型检查
    is 操作符可以判断一个实例是否是某个类的类型
    as 操作符仅用于向上转型,也可以用于oc和swift底层类型相互转换
    as! 和 as? 可选类型与非可选类型进行转换
    any 和 anyObject any表示任何类型,anyObject 表示任何类的类型

  • 泛型
    泛型在代码中可以定义一些可变的部分,在运行的时候指定,使用泛型可以最大限度的重用代码和保护类型的安全,提高整体性能。swift中array,dictionary,set都是泛型集合。
    例如要定义一个函数来判断两个参数是否相等,int,string,double,float各定义一次,如果使用泛型函数来改造,就有

//单参数类型
func isEquals <T> (a : T ,b : T) -> Bool{
    return (a == b)
}

//多参数类型
func isEquals <T , U> (a : T ,b: U) -> Bool{
   return (a == b)
}

——Cocoa Touch设计模式及应用之MVC模式

MVC(Model-View-Controller,模型-视图-控制器)模式是相当古老的设计模式之一,它最早出现在Smalltalk语言中。现在,很多计算机语言和架构都采用了MVC模式。

MVC模式概述
MVC模式是一种复合设计模式,由 “观察者”(Observer)模式、“策略”(Strategy)模式和“合成”(Composite)模式等组成。MVC模式由3个部分组成,如图所示,这3个部分的作用如下所示。
· 模型。保存应用数据的状态,回应视图对状态的查询,处理应用业务逻辑,完成应用的功能,将状态的变化通知视图。
· 视图。为用户展示信息并提供接口。用户通过视图向控制器发出动作请求,然后再向模型发出查询状态的申请,而模型状态的变化会通知给视图。
· 控制器。接收用户请求,根据请求更新模型。另外,控制器还会更新所选择的视图作为对用户请求的回应。控制器是视图和模型的媒介,可以降低视图与模型的耦合度,使视图和模型的权责更加清晰,从而提高开发效率。

 

对应于哲学中的“内容”与“形式”, 在MVC模型中,模式是“内容”,它存储了视图所需要的数据,视图是“形式”,是外部表现方式,而控制器是它们的媒介。
Cocoa Touch中的MVC模式
上面我们讨论的是通用的MVC模式,而Cocoa和Cocoa Touch框架中的MVC模式与传统的MVC模式略有不同,前者的模型与视图不能进行任何通信,所有的通信都是通过控制器完成的,如图所示。

 

在Cocoa Touch框架的UIKit框架中,UIViewController是所有控制器的根类,如UITableViewController、UITabBarController和UINavigationController。UIView是视图和控件的根类。

——离开表达式你试试!

二、进阶篇

.......................................

——Cocoa Touch设计模式及应用之响应者链与触摸事件

应用与用户进行交互,依赖于各种各样的事件。事件响应者对象是可以响应事件并对其进行处理的对象,响应者链是由一系列链接在一起的响应者组成的。响应者链在事件处理中是非常重要的,响应者链可以把用
户事件路由给正确的对象。

响应者对象与响应链
UIResponder是所有响应者对象的基类,它不仅为事件处理,而且也为常见的响应者行为定义编程接口。UIApplication、UIView(及其子类,包括UIWindow)和UIViewController(及其子类)都直接或间接地继承自UIResponder类。

 

第一响应者是应用程序中当前负责接收触摸事件的响应者对象(通常是一个UIView对象)。UIWindow对象以消息的形式将事件发送给第一响应者,使其有机会首先处理事件。如果第一响应者没有进行处理,系统就将事件(通过消息)传递给响应者链中的下一个响应者,看看它是否可以进行处理。
响应者链是一系列链接在一起的响应者对象,它允许响应者对象将处理事件的责任传递给其他更高级别的对象。随着应用程序寻找能够处理事件的对象,事件就在响应者链中向上传递。响应者链由一系列“下一个响应者”组成。
1.第一响应者将事件传递给它的视图控制器(如果有的话),然后是它的父视图。
2.类似地,视图层次中的每个后续视图都首先传递给它的视图控制器(如果有的话),然后是它的父视图。
3.最上层的容器视图将事件传递给UIWindow对象。
4.UIWindow对象将事件传递给UIApplication单例对象。

触摸事件
触摸(UITouch)对象表示屏幕上的一个触摸事件,访问触摸是通过UIEvent对象传递给事件响应者对象的。触摸对象有时间和空间两方面。
1.时间方面
时间方面信息称为阶段(phase),表示触摸是否刚刚开始、是否正在移动或处于静止状态,以及何时结束,也就是手指何时从屏幕抬起。
在给定的触摸阶段中,如果发生新的触摸动作或已有的触摸动作发生变化,则应用程序就会发送这些消息。

  • 当一个或多个手指触碰屏幕时,发送touchesBegan:withEvent:消息。
  • 当一个或多个手指在屏幕上移动时,发送touchesMoved:withEvent:消息。
  • 当一个或多个手指离开屏幕时,发送touchesEnded:withEvent:消息。

2.空间方面
触摸点对象还包括当前在视图或窗口中的位置信息,以及之前的位置信息(如果有的话)。下面的方法是可以获得触摸点所在窗口或视图中的位置。

    func locationInView(_ view: UIView?) -> CGPoint

获得前一个触摸点所在窗口或视图中的位置信息:

func previousLocationInView(_ view: UIView?) -> CGPoint

——运算符是“ 、-、*、/ ”吗?

1.值类型/引用类型

  • swift中只有类是引用类型,其他类型全部是值类型。
  • 传递参数时要拷贝一份。例如常用的结构体和枚举都是值类型。

——Swift与Objective-C混合编程之语言

在Swift语言出现之前,开发iOS或OS X应用主要使用Objective-C语言,此外还可以使用C和C 语言,但是UI部分只能使用Objective-C语言。

选择语言
Swift语言出现后,苹果公司给程序员提供了更多的选择,让这两种语言并存。既然是并存,我们就有4种方式可以选择:

  • 采用纯Swift的改革派方式;
  • 采用纯Objective-C的保守派方式;
  • 采用Swift调用Objective-C的左倾改良派方式;
  • 采用Objective-C调用Swift的右倾改良派方式。

文件扩展名

在Xcode等工具开发iOS或OS X应用可以编写多种形式的源文件,原本就可以使用Objective-C、C和C 语言,Swift语言出现后源文件的形式更加多样。可能的文件扩展名说明:

 

——数据类型那些事儿?

2.属性和变量(propertry,variable)

  • 关于swift中属性和变量的描述,有一个兄弟总结的比较好,请到 传送门

在OC中使用属性一般都使用如下格式:

@property (strong,nonatomic) NSString *string;

而在Swift中的属性一般都使用如下格式:

class Shape { var name = "shape"}

在oc中可以直接与变量打交道,swift中则行不通,在Swift的世界里,我们只与property打交道。在Swift中,属性分为存储属性和计算属性。简单来说,就是存储属性能够保存值,而计算属性只提供getter与setter,利用存储属性来生成自己的值。计算属性更像方法,而不是传统意义的属性。但是这样一个特性存在,使得我们更容易组织我们的代码。

——Swift与Objective-C混合编程之Swift与Objective-C API映射

——说几个特殊运算符

构造变量
  • 在OC中,只能通过单例,或者static变量加类方法来构造类变量:
@interface Model

  (int) value;
  (void) setValue:(int)val;

@end

@implementation Modelstatic 

  int value;  
  (int) value{ 

@synchronized(self) { 
  return value; 
} 

  (void) setValue:(int)val{ 
  @synchronized(self) { 
    value = val; 
    } 
}
@end

// Foo.h@interface Foo {}
  (NSDictionary *) dictionary;
// Foo.m oc单例
  (NSDictionary *) dictionary{ 
  static NSDictionary* fooDict = nil; 
  static dispatch_once_t oncePredicate; 
  dispatch_once(&oncePredicate, ^{ 
  // create dict 
  }); 
  return fooDict;
}
  • 在swift中,可以通过清晰的语法便能定义类变量,通过static定义的类变量无法在子类重写,通过class定义的类变量则可在子类重写。
struct SomeStructure { 
  static var storedTypeProperty = "Some value." 
  static var computedTypeProperty: Int { 
    return 1 
  } 
  class var overrideableComputedTypeProperty: Int { 
    return 107 
  }
}

//swift单例
class singletonClass { 
  static let sharedInstance = singletonClass() 
  private init() {}
  // 这就阻止其他对象使用这个类的默认的'()'初始化方法
}

Swift与Objective-C API映射

在混合编程过程中Swift与Objective-C调用是双向的,由于不同语言对于相同API的表述是不同的,他们之间是有某种映射规律的,这种API映射规律主要体现在构造函数和方法两个方面。

1、构造函数映射
在Swift与Objective-C语言进行混合编程时,首先涉及到调用构造函数实例化对象问题,不同语言下构造函数表述形式不同,如图是苹果公司官方API文档,描述了NSString类的一个构造函数。

 

Swift构造函数除了第一个参数外,其它参数的外部名就是选择器对应部分名。规律的其它细节图中已经解释的很清楚了,这个规律反之亦然,这里不再赘述。
2、方法名映射

在Swift与Objective-C语言进行混合编程时,不同语言下方法名表述形式也是不同的,如图是苹果公司官方API文档,描述了NSString类的rangeOfString:options:range:方法。

选择器第一个部分rangeOfString作为方法名,一般情况下Swift方法第一个参数的外部参数名是要省略的,“_”符号表示省略。之后的选择器各部分名(如:options和range),作为外部参数名。除了参数名对应为,参数类型也要对应下来。

Swift 2.0之后方法可以声明抛出错误,这些能抛出错误的方法,不同语言下方法名表述形式如图下图所示,是writeToFile:atomically:encoding:error:苹果公司官方API文档。

比较两种不同语言,我们会发现error参数在Swift语言中不再使用,而是在方法后添加了throws关键字。
这种映射规律不仅仅只适用于苹果公司官方提供的Objective-C类,也适用于自己编写的Objective-C类。

——数据类型之整型和浮点型

计算属性
  • getter 访问器 取出属性值
  • setter 访问器 给属性赋值计算
    只读计算属性省略set()代码,只保留get()代码

——Swift与C/C 混合编程之数据类型映射

如果引入必要的头文件,在Objective-C语言中可以使用C数据类型。而在Swift语言中是不能直接使用C数据类型,苹果公司为Swift语言提供与C语言相对应数据类型。这些类型主要包括:C语言基本数据类型和指针类型。

如表所述是Swift数据类型与C语言基本数据类型对应关系表。

Swift语言中的这些数据类型与Swift原生的数据类型一样,本质上都是结构体类型。

如表所述是Swift数据类型与C语言指针数据类型对应关系表。

从表可见针对C语言多样的指针形式,Swift主要通过提供了三种不安全的泛型指针类型:UnsafePointer<T>、UnsafeMutablePointer<T>和AutoreleasingUnsafeMutablePointer<T>。T是泛型占位符,表示不同的数据类型。另外,还有COpaquePointer类型是Swift中无法表示的C指针类型。
下面我们分别介绍一下。

  1. UnsafePointer<T>
    UnsafePointer<T>是一个比较常用的常量指针类型,这种指针对象需要程序员自己手动管理内存,即需要自己申请和释放内存。它一般是由其他的指针创建。它的主要的构造函数有:
    · init( other: COpaquePointer)。通过COpaquePointer类型指针创建。
    · init<U>(
    from: UnsafeMutablePointer<U>)。通过 UnsafeMutablePointer类型指针创建。
    · init<U>(_ from: UnsafePointer<U>)。通过UnsafePointer类型指针创建。
    UnsafePointer<T>主要的属性:
    · memory。只读属性,它能够访问指针指向的内容。
    UnsafePointer<T>主要的方法:
    · successor() -> UnsafePointer<T>。获得指针指向的下一个内存地址的内容。
    · predecessor() -> UnsafePointer<T>。获得指针指向的上一个内存地址的内容。
  2. UnsafeMutablePointer<T>
    UnsafeMutablePointer<T>是一个比较常用的可变指针类型,这种指针对象需要程序员自己手动管理内存,自己负责申请和释放内存。可变指针可以由其他的指针创建,也可以可变指针通过alloc(:)方法申请内存空间,再调用initialize(:)方法初始化指针指向数值。当指针对象释放时候需要调用destroy()方法销毁指针指向对象,它是initialize(:)方法的反向操作,他们两个方法在代码中应该成对出现的。最后还要调用dealloc(:)方法释放指针指向的内存空间,它是alloc(_:)方法的反向操作,这两个方法在代码中也应该成对出现。
  3. AutoreleasingUnsafeMutablePointer<T>
    AutoreleasingUnsafeMutablePointer<T>被称为自动释放指针,在方法或函数中声明为该类型的参数,是输入输出类型的,在调用方法或函数过程中,参数先首先被拷贝到一个无所有权的缓冲区,在方法或函数内使用的这个缓冲区,当方法或函数返回时,缓冲区数据重新写回到参数。
这是我在学Swift整理的基础笔记,希望给更多刚学IOS开发者带来帮助,在这里博主非常感谢大家的支持!  
到这里就基本完成了Swift语言基础笔记整理了。
 如果大家觉得此博文对您有帮助,那就动动你的小手指点个赞!!  
哈哈,感谢各位博友的支持!!!

——字符串的插入、删除和替换

存储属性

待补充

——请注意数字类型之间的转换

属性观察者
  • 属性观察者 能够监听存储属性的变化,但不能监听延迟存储属性和常量属性,常常应用于后台处理,需要更新界面的业务需求。类似于OC中的KVO机制。
  • willSet 观察者在修改之前调用
  • didSet 观察者在修改之后立刻调用 默认newValue和oldValue
class Employee{
  var no : Int = 0
  var name : String = "test"{
    willSet(newName){
      print("员工name新值 : (newName)")
    }
    didSet(oldName){
      print("员工name旧值 : (oldName)")
    }
  }
}

——字典集合

3.扩展(Extension)/协议(Protocol)

  • 拓展
    在swift和oc中,可以使用一种扩展机制,在原始类型(类,结构体,枚举)的基础上添加新功能,是一种“轻量级”的继承机制。扩展类型可以是类,结构体,枚举,而继承只能是类。常用的扩展可以扩展基本类型,方法,构造函数等等。
extension 类型名{
    //添加新功能
}
  • 协议
    协议是swift和oc中的名称,在Java中称为接口,在C 中是纯虚类,协议是高度抽象的,规定一些方法名,参数列表,返回值等信息,但是不给出具体的实现,这种抽象方法由遵从该协议的遵从者自己内部实现,具体实现过程称为遵从协议或者实现协议。
    在结构体和枚举类型中可以定义变异方法,在类中没有该方法,因为结构体和枚举类型中的属性是不可以被修改的,在协议定义变异方法时候,前面要加关键字mutating
    swift和oc又被称为面向协议编程语言,在面向协议编程中(Java中称为面向接口编程)应用的定义与实现进行分离,协议作为数据类型暴露给使用者,不关心具体的实现细节,从而提供应用的可扩展性和可复用性。
protocol leader{
  mutating func method()  //定义抽象方法
}
class member : leader {
  func method()  // 实现具体实例方法
} 
struct member_str : leader{
  mutating func method()    //实现变异方法
}

在Objective-C中我们这么声明Protocol:

@protocol SampleProtocol <NSObject>
- (void)someMethod;
@end

而在Swift中:

protocol SampleProtocol { func someMethod() }

在Swift遵循协议:

class AnotherClass: SomeSuperClass, SampleProtocol{ func someMethod() { } }

——Swift中数组集合

4.内存管理

swift和oc的内存管理都是采用了自动引用计数(ARC),很早之前的oc还是采用比较古老的手动引用计数(MRC),swfit在这方面有着基因级别的优势。ARC就是程序员不关心对象释放的问题,编译器在编译时在合适的位置插入对象内存释放代码。引用计数具体细节这里就不详细说明了。
但是采用ARC会导致强引用循环,即当两个对象的存储属性互相引用对方的时候,一个对象释放的前提是对方先释放,另一个对象释放的前提也是对方先释放,就会导致死锁的状态,从而导致内存泄露,打破强引用循环一般采用弱引用或者无主引用,使用weak和unowned 或可选类型(Optional)

//Object-C
weak self

//swift
weak var dept: Department?

——有几个分支语句?

5.错误处理

  • Cocoa错误处理
    首先定义一个NSError变量,然后判断err变量是否为空
NSError *anyError;
BOOL success = [receivedData writeToURL:someLocalFileURL options:0 error:&anyError];
if (!success) {
NSLog(@”Write failed with error: %@”, anyError);
// present error to user
}
  • swift错误处理
    由于历史原因swift1.x中错误处理模式沿用了Cocoa框架的错误处理模式,swift2.x和swift3.x采用了do-try-catch错误处理模式,在使用try时候经常也会遇到try?和try!
    try?会将错误转换为可选值,当发生错误抛出异常时,程序不会崩溃,而是反馈一个nil,try!可以打破错误传播链条,终止错误传递。
try {
     //成功处理语句
}catch{
     //错误处理语句
}

——函数参数传递

6. Id和AnyObject 以及Optional

在Swift中,没有id类型,Swift用一个名字叫AnyObject的protocol来代表任意类型的对象。

id myObject = [[UITableViewCell alloc]init];
var myObject: AnyObject = UITableViewCell()

我们知道id的类型直到运行时才能被确定,如果我们向一个对象发送一条不能响应的消息,就会导致crash。我们可以利用Swift的语法特性来防止这样的错误:

myObject.method?()

如果myObject没有这个方法,就不会执行,类似检查delegate是否有实现代理方法。在Swift中,在AnyObject上获取的property都是optional的。

——函数中参数的传递引用

7.函数式编程/block闭包

  • 函数
    在OC中,方法有两种类型,类方法与实例方法。方法的组成由方法名,参数,返回值组成。
 (void)类方法
-(void)实例方法

 (UIColor*)blackColor    //类方法
-(void)addSubview:(UIView *)view   //实例方法 
class func blackColor() -> UIColor   //类方法
func addSubview(view: UIView)      //实例方法

//OC
NSArray *oldArray = @[@1,@2,@3,@4,@5,@6,@7,@8,@9,@10]; 
NSMutableArray *newArray; 
for (NSNumber* number in oldArray) { 
  if ([number compare:@4] == NSOrderedDescending ) { 
  [newArray addObject:number]; 
  } 
}

//swift函数式编程
let oldArray = [1,2,3,4,5,6,7,8,9,10]
let newArray = oldArray.filter({$0 > 4})

在Swift中,函数的最重要的改进就是函数作为一等公民(first-class),和对象一样可以作为参数进行传递,可以作为返回值,函数式编程也成为了Swift支持的编程范式。

  • block闭包
    OC中的block在Swift中无缝地转换为闭包。函数实际上也是一种特殊的闭包。
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success) { 
  NSLog(@"Error: %@", error.domain);
}

//do-try-catch
let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("/path/to/file")
do { 
  try fileManager.removeItemAtURL(URL)
} catch let error as NSError { 
  print("Error: (error.domain)")
}

——函数返回值

8.KVO

  • Swift支持KVO。但是KVO在Swift,个人觉得是不够优雅的,KVO在Swift只限支持继承NSObject的类,有其局限性,在这里就不介绍如何使用了。网上也出现了一些开源库来解决这样的问题。也可以使用前文讲述的属性观察者来做Swift的KVO机制。
  • KVO 在OS X中有Binding的能力,也就是我们能够将两个属性绑定在一起,一个属性变化,另外一个属性也会变化。对与UI和数据的同步更新很有帮助,也是MVVM架构的需求之一。之前已经眼馋这个特性很久了,虽然Swift没有原生带来支持,Swift支持的泛型编程给开源界带来许多新的想法。

——闭包那些事儿!

三、实战篇

很想写点什么实战类型的东西,但是坦诚来说,笔者并没有太多的实战经验,在这里仅总结一些前人的经验以供参考,后续可以继续补充。这里CSDN上的一篇写的很好了 可以参考一下 => 传送门

——尾随闭包

1.Swift与OC的常见区别
  • swift句尾不需要分号 ,除非你想在一行中写三行代码就加分号隔开。

  • swift不要写main函数 ,程序默认从上往下执行

  • swift不分.h和.m文件 ,一个类只有.swift一个文件

  • swift不在有地址的概念

  • swift数据类型都会自动判断 , 只区分变量var 和常量let

  • 强制转换格式反过来了 OC强转:(int)a Swift强转:int(a)

  • 整数的数据类型可以通过 .min和.max获得最大和最小值

  • 定义类型的别名语法改变

//OC:
typedef int MyInt 
//Swift:
typealias MyInt = int
  • swift的模除取余运算符支持小数了 。 如 5%1.5 = 0.5

  • 关于BOOL类型更加严格 ,Swift不再是OC的非0就是真,而是true才是真false才是假

  • swift的赋值运算符没有返回值 。防止误用“=”和“==”

  • swift可以多对多赋值,即元祖类型 。 let(x,y) = (1,2)

  • swift的 循环语句中必须加{} 就算只有一行代码也必须要加

  • swift的switch语句后面以前只能跟整数, 现在可以跟各种数据类型了 ,如浮点字符串都行,并且里面不用写break,如果不想要没break的效果 即后面的都想执行 那就写上关键字 fallthrough(注意:在fallthrough后面就不能再定义常量变量了)

——枚举

2.控件类
  • 初始化UIView的子类
    在iOS应用上实现UI就需要子类化UIView,也就是要重写UIView的init方法。注意:两种语言有所区别。 Objective-C只需在UIView子类中重写必要的init方法。要初始化一个UIView框架,就要重写initWithFrame:框架,如下所示:
@implementation SubUIView
- (id) initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self != nil) {
        // ...
    }
    return self;
}
@end
  • 然而Swift需要多一些步骤来重写同一个init方法。首先,重写使用CGRect框架作为其参数的init方法。根据UIView文档,用Swift语言构建时,须重写init( coder: ),但我们不需要这种方法,就用如下代码处理。类属性初始化所需的代码可以在init( frame: )中执行。
class SubUIView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        // ...
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
  • 初始化UIViewController的子类
    子类化UIViewController是iOS开发的重要步骤。使用Interface Builder的开发者需要重写initWithNibName:bundle:,但既然我们用代码来构建UI,就不需要执行这一方法了。只需重写init方法,在其中初始化类属性即可。
@implementation SubUIViewController
- (id) init
{
    self = [super init];
    if (self != nil) {
        // ...
    }
    return self;
}
@end
  • Swift也一样要重写init()方法。实现指定的初始化init(nibName:bundle: )来子类化UIViewController。重申:此过程不适用Interface Builder,所以无需定义nibName和bundle的值,而是调用比指定初始化更简单的convenience初始化,将指定初始化init(nibName:bundle: )设为零。现在调用init()来初始化类,用重写的(nibName:bundle: )执行类属性。
class SubUIViewController: UIViewController {
    convenience init() {
        self.init(nibName: nil, bundle: nil)
    }
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        // Initialize properties of class
    }  
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

//现在可以创建和调用UIViewController的子类
let viewController: SubUIViewController = SubUIViewController()
self.navigationController?.pushViewController(viewController, animated: false)

——类和结构体定义

3.Auto Layout
  • 有一个比较好的博客 : Auto Layout

——可选链

4.选择器

使用UIButton、NSNotificationCenter、NSTimer等时,使用选择器来分配要执行的方法。在Objective-C中,@selector指令代表使用选择器。

- (void)test
{
    // ...
    mTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerCallback:) userInfo:nil repeats:YES];
}

- (void)timerCallback:(NSTimer *)timer
{
    // ...
}

Swift中,不需要使用指令或字符串来分配方法。

        let button = UIButton(type: UIButtonType.system)
        button.setTitle("OK", for: UIControlState())

        let buttonWidth:CGFloat = 60
        let buttonHeight:CGFloat = 20
        let buttonTopView:CGFloat = 240

        button.frame = CGRect(x: (screen.size.width - buttonWidth)/2 , y: buttonTopView, width: buttonWidth, height: buttonHeight)

        button.addTarget(self, action: #selector(ViewController.onClick(_:)), for: UIControlEvents.touchUpInside)

        self.view.addSubview(button)

——可选类型

四、总结

.............................

事实上Swift的世界相比OC的世界还有很多新鲜的东西等待我们去发现和总结,Swift带来的多范式编程也将给我们编程的架构和代码的组织带来更来的思考。而Swift也是一个不断变化,不断革新的语言。相信未来的发展和稳定性会更让我们惊喜。

  • PS:谷歌酝酿将苹果Swift作为安卓APP主要开发语言

——总结使用问号

——访问级别

——选择类还是结构体呢?

——存储属性

——计算属性

——属性观察者

——静态属性是怎么回事?

——会使用下标吗?

——静态方法

——默认构造函数

——构造函数与存储属性初始化

——构造函数重载

——析构函数

——类的继承

——构造函数调用规则

——构造函数继承

——重写属性

——重写方法

——下标重写

——final关键字

——类型检查与转换

——扩展声明

——扩展计算属性、方法

——扩展构造函数

——Cocoa错误处理模式

——do-try-catch错误处理模式

——抛出错误

——使用try?和try!区别

—— Swift编码规范之命名规范

——Swift编码规范之注释规范:文件注释、文档注释、代码注释、使用地标注释

—— Swift编码规范之变量或常量声明规范

——代码排版

——Core Foundation框架

——Core Foundation框架之内存管理

——Core Foundation框架之内存托管对象与非托管对象

——Cocoa Touch设计模式及应用之单例模式

——Cocoa Touch设计模式及应用之目标与动作

——Cocoa Touch设计模式及应用之选择器

——Cocoa Touch设计模式及应用之通知机制

——Cocoa Touch设计模式及应用之MVC模式

——Cocoa Touch设计模式及应用之响应者链与触摸事件

——Swift与Objective-C混合编程之语言

——Swift与Objective-C混合编程之Swift与Objective-C API映射

——Swift与C/C 混合编程之数据类型映射

想要系统学习的同学,欢迎自己搜索关东升老师的《从零开始学Swift》:

www.weide1946.com 1

版权声明:本文由韦德娱乐1946_韦德娱乐1946网页版|韦德国际1946官网发布于网络编程,转载请注明出处:www.weide1946.com关东升出品,从0开始学Swift笔记整理