在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
[TOC] @(swift)[温故而知新]
一、Objective-C与Swift的异同 1.1、swift和OC的共同点: – OC出现过的绝大多数概念,比如引用计数、ARC(自动引用计数)、属性、协议、接口、初始化、扩展类、命名参数、匿名函数等,在Swift中继续有效(可能最多换个术语)。 – Swift和Objective-C共用一套运行时环境,Swift的类型可以桥接到Objective-C(下面我简称OC),反之亦然 1.2、swift的优点: – swift注重安全,OC注重灵活 – swift注重面向协议编程、函数式编程、面向对象编程,OC注重面向对象编程 – swift注重值类型,OC注重指针和引用 – swift是静态类型语言,OC是动态类型语言 – swift容易阅读,文件结构和大部分语法简易化,只有.swift文件,结尾不需要分号 – swift中的可选类型,是用于所有数据类型,而不仅仅局限于类。相比于OC中的nil更加安全和简明 – swift中的泛型类型更加方便和通用,而非OC中只能为集合类型添加泛型 – swift中各种方便快捷的高阶函数(函数式编程) (Swift的标准数组支持三个高阶函数:map,filter和reduce,以及map的扩展flatMap) – swift新增了两种权限,细化权限。open > public > internal(默认) > fileprivate > private – swift中独有的元组类型(tuples),把多个值组合成复合值。元组内的值可以是任何类型,并不要求是相同类型的。 1.3、swift的不足: – 版本不稳定 – 公司使用比例不高,使用人数比例偏低 – 有些语法其实可以只规定一种格式,不必这样也行,那样也行。像Go一样禁止一切(Go有点偏激)耍花枪的东西,同一个规范,方便团队合作和阅读他人代码。 Swift 跟 JavaScript 有什么相同和不同点? 从数据结构角度,Golang和Swift对比,有何优缺点? iOS——Objective-C与Swift优缺点对比 二、swift类(class)和结构体(struct)的区别 2.1 定义 class Class { // class definition goes here}struct Structure { // structure definition goes here} 2.2 值 VS 引用 1、结构体 struct 和枚举 enum 是值类型,类 class 是引用类型。 2、String, Array和 Dictionary都是结构体,因此赋值直接是拷贝,而NSString, NSArray 和NSDictionary则是类,所以是使用引用的方式。 3、struct 比 class 更“轻量级”,struct 分配在栈中,class 分配在堆中。 2.3 指针 如果你有 C,C++ 或者 Objective-C 语言的经验,那么你也许会知道这些语言使用指针来引用内存中的地址。一个 Swift 常量或者变量引用一个引用类型的实例与 C 语言中的指针类似,不同的是并不直接指向内存中的某个地址,而且也不要求你使用星号(*)来表明你在创建一个引用。Swift 中这些引用与其它的常量或变量的定义方式相同。 2.4 选择使用类和结构体
– 比如数据被多线程使用,而且数据没有使用class的必要性,就使用struct – 希望实例被拷贝时,不收拷贝后的新实例的影响 – 几何图形的大小,可以封装width和height属性,都是Double类型 – 指向连续序列范围的方法,可以封装start和length属性,都是Int类型 – 一个在3D坐标系统的点, 可以封装x, y和z属性,都是Double类型
– 需要继承 – 被递归调用的时候(参考链表的实现,node选用class而不是struct) – 属性数据复杂 – 希望引用而不是拷贝 参考链接1:类和结构体 参考链接2:官方文档 三、Objective-C中的protocol与Swift中的protocol的区别 相比于OC,Swift 可以做到protocol协议方法的具体默认实现(通过extension)相比多态更好的实现了代码复用,而 OC 则不行。 四、面向协议(面向接口)与面向对象的区别
总结:
3.1、协议和协议扩展比基类有三个明显的优点: 1、类型可以遵守多个协议但是只有一个基类。 这意味着类型可以随意遵守任何想要特性的协议,而不需要一个巨大的基类。 2、不需要知道源码就可以使用协议扩展添加功能。这意味着我们可以任意扩展协议,包括swift内置的协议,而不需要修改基类的源码。一般情况下我们会给特定的类而非类的层级(继承体系)添加扩展;但是如果必要,我们依然可以给基类添加扩展,使所有的子类继承添加的功能。使用协议,所有的属性、方法和构造函数都被定义在遵守协议的类型自身中。这让我们很容易地查看到所有东西是怎么被定义和初始化的。我们不需要在类的层级之间来回穿梭以查看所有东西是如何初始化的。忘记设置超类可能没有什么大问题,但是在更复杂的类型中,忘记合理地设置某个属性可能会导致意想不到的行为。 3、协议可以被类、结构体和枚举遵守,而类层级约束为类类型。 协议和协议扩展可以让我们在更合理的地方使用值类型。引用类型和值类型的一个主要的区别就是类型是如何传递的。当我们传递引用类型(class)的实例时,我们传递的对原实例的引用。这意味着所做的任何更改都会反射回原实例中。当我们传递值类型的实例时,我们传递的是对原实例的一份拷贝。这意味着所做的任何更改都不会反射回原实例中。使用值类型确保了我们总是得到一个唯一的实例因为我们传递了一份对原实例的拷贝而非对原实例的引用。因此,我们能相信没有代码中的其它部分会意外地修改我们的实例。这在多线程环境中尤其有用,其中不同的线程可以修改数据并创建意外地行为。 3.2、面向对象的特点 优点: – 封装
– 继承
– 多态
多态的不足: – 父类有部分public方法是子类不需要的,也不允许子类覆盖重写 – 父类有一些方法是必须要子类去覆盖重写的,在父类的方法其实也是一个空方法 – 父类的一些方法即便被子类覆盖重写,父类原方法还是要执行的 – 父类的一些方法是可选覆盖重写的,一旦被覆盖重写,则以子类为准 较好的抽象类型应该: – 更多地支持值类型,同时也支持引用类型 – 更多地支持静态类型关联(编译期),同时也支持动态派发(runtime) – 结构不庞大不复杂 – 模型可扩展 – 不给模型强制添加数据 – 不给模型增加初始化任务的负担 – 清楚哪些方法该实现哪些方法不需实现 3.3、OneV's Den提到的面向对象的三个困境: 1、动态派发的安全性(这应该是OC的困境,在Swift中Xcode是不可能让这种问题编译通过的)
NSObject *v1 = [NSObject new];NSString *v2 = [NSString new];NSNumber *v3 = [NSNumber new];NSArray *array = @[v1, v2, v3];for (id obj in array) { [obj boolValue];}
@protocol SafeProtocol - (void)func;@[email protected] SafeObj : [email protected]@implementation SafeObj- (void)func { }@[email protected] UnSafeObj : [email protected]@implementation [email protected]
SafeObj *v1 = [[SafeObj alloc] init];UnSafeObj *v2 = [[UnSafeObj alloc] init];// 由于v2没有实现协议SafeProtocol,所以此处Xcode会有警告// Object of type 'UnSafeObj *' is not compatible with array element type 'id'NSArray<id> *array = @[v1, v2];for (id obj in array) { [obj func];}
// 直接报错,而不是警告// Cannot convert value of type 'String' to expected argument type 'NSNumber'var array: [NSNumber] = []array.append(1)array.append("a") 2、横切关注点 我们很难在不同的继承体系中复用代码,用行话来讲就是横切关注点(Cross-Cutting Concerns)。比如下面的关注点myMethod,位于两条继承链 (UIViewController -> ViewCotroller 和 UIViewController -> UITableViewController -> AnotherViewController) 的横切面上。面向对象是一种不错的抽象方式,但是肯定不是最好的方式。它无法描述两个不同事物具有某个相同特性这一点。在这里,特性的组合要比继承更贴切事物的本质。 class ViewCotroller: UIViewController { func myMethod() { }} class AnotherViewController: UITableViewController { func myMethod() { }} 在面向对象编程中,针对这种问题的几种解决方案: – 1、Copy & Paste
– 2、引入 BaseViewController
– 3、依赖注入
– 4、多继承
protocol P { func myMethod()}extension P { func myMethod() { doWork() }} extension ViewController: P { }extension AnotherViewController: P { }viewController.myMethod()anotherViewController.myMethod() 3、菱形问题
上面的例子中,如果我们有多继承,那么 ViewController 和 AnotherViewController 的关系可能会是这样的: 如果ViewController 和UITableViewController都实现了myMethod方法,则在AnotherViewController中就会出现菱形缺陷问题。
五、编程实践:基于protocol的链表实现 import UIKitprotocol ChainListAble { associatedtype T: Equatable // 打印 var description: String{get} // 数量 var count: Int{get} /// 插入 func insertToHead(node: Node) func insertToHead(value: T) func insertToTail(node: Node) func insertToTail(value: T) func insert(node: Node, afterNode: Node) -> Bool func insert(value: T, afterNode: Node) -> Bool func insert(node: Node, beforNode: Node) -> Bool func insert(value: T, beforNode: Node) -> Bool /// 删除(默认第一个符合条件的) @discardableResult func delete(node: Node) -> Bool @discardableResult func delete(value: T) -> Bool @discardableResult func delete(index: Int) -> Bool //func delete(fromIndex: Int, toIndex: Int) -> Bool //func deleteAll() /// 查找(默认第一个符合条件的) func find(value: T) -> Node? func find(index: Int) -> Node? /// 判断结点是否在链表中 func isContain(node: Node) -> Bool}/// [值类型不能在递归里调用](https://www.codetd.com/article/40263),因此Node类型只能是class而不是struct// 有些时候你只能使用类而不能使用结构体,那就是递归里// struct报错:Value type 'Node' cannot have a stored property that recursively contains itclass Node { var value: T var next: Node? /// 便利构造方法 /// /// - Parameter value: value convenience init(value: T) { self.init(value: value, next: nil) } /// 默认指定初始化方法 /// /// - Parameters: /// - value: value /// - next: next init(value: T, next: Node?) { self.value = value } // 销毁函数 deinit { print("\(self.value) 释放") }}extension Node { /// 返回当前结点到链表尾的长度 var count: Int { var idx: Int = 1 var node: Node? = self while node?.value != nil { node = node?.next idx = idx + 1 } return idx }}class SingleChainList: ChainListAble { typealias T = String // 哨兵结点,不存储数据 private var dummy: Node = Node.init(value: "")}extension SingleChainList { var description: String { var description: String = "" var tempNode = self.dummy while let nextNode = tempNode.next { description = description + " " + nextNode.value tempNode = nextNode } return description } var count: Int { var count: Int = 0 var tempNode = self.dummy while let nextNode = tempNode.next { count = count + 1 tempNode = nextNode } return count } /// 在头部插入值 /// /// - Parameter value: value func insertToHead(value: T) { let node: Node = Node.init(value: value) self.insertToHead(node: node) } /// 在头部插入结点 /// /// - Parameter node: node func insertToHead(node: Node) { node.next = self.dummy.next self.dummy.next = node } /// 在尾部插入值 /// /// - Parameter value: value func insertToTail(value: T) { let node: Node = Node.init(value: value) self.insertToTail(node: node) } /// 在尾部插入结点 /// /// - Parameter node: node func insertToTail(node: Node) { var tailNode: Node = self.dummy while let nextNode = tailNode.next { tailNode = nextNode } tailNode.next = node } /// 在指定结点的后面插入新value /// /// - Parameters: /// - value: 新值 /// - afterNode: 指定结点 /// - Returns: true or false func insert(value: T, afterNode: Node) -> Bool { let node: Node = Node.init(value: value) return self.insert(node: node, afterNode: afterNode) } /// 在指定结点的后面插入新结点 /// /// - Parameters: /// - value: 新结点 /// - afterNode: 指定结点 /// - Returns: true or false func insert(node: Node, afterNode: Node) -> Bool { guard self.isContain(node: afterNode) else { return false } node.next = afterNode.next afterNode.next = node return true } /// 在指定结点的前面插入新value(双向链表实现这种插入方式速度比单向链表快) /// /// - Parameters: /// - value: 新值 /// - beforNode: 指定结点 /// - Returns: true or false func insert(value: T, beforNode: Node) -> Bool { let node: Node = Node.init(value: value) return self.insert(node: node, beforNode: beforNode) } /// 在指定结点的前面插入新结点(双向链表实现这种插入方式速度比单向链表快) /// /// - Parameters: /// - node: 新结点 /// - beforNode: 指定结点 /// - Returns: true or false func insert(node: Node, beforNode: Node) -> Bool { var tempNode: Node = self.dummy while let nextNode = tempNode.next { if nextNode === beforNode { node.next = beforNode tempNode.next = node return true } tempNode = nextNode } return false } /// 删除指定value的结点 /// /// - Parameter value: value /// - Returns: true or false func delete(value: T) -> Bool { var tempNode: Node = self.dummy while let nextNode = tempNode.next { // 此处判断 == 是否合理 if nextNode.value == value { tempNode.next = nextNode.next return true } tempNode = nextNode } return false } /// 删除指定的结点 /// /// - Parameter node: node /// - Returns: true or false func delete(node: Node) -> Bool { var tempNode = self.dummy while let nextNode = tempNode.next { if nextNode === node { tempNode.next = nextNode.next return true } tempNode = nextNode } return false } /// 删除指定下标的结点 /// /// - Parameter index: index /// - Returns: true or false func delete(index: Int) -> Bool { var idx: Int = 0 var tempNode: Node = self.dummy while let nextNode = tempNode.next { if index == idx { tempNode.next = nextNode.next return true } tempNode = nextNode idx = idx + 1 } return false } /// 查找指定值的node /// /// - Parameter value: value /// - Returns: node func find(value: T) -> Node? { var tempNode = self.dummy while let nextNode = tempNode.next { if nextNode.value == value { return nextNode } tempNode = nextNode } return nil } /// 查找指定下标的结点 /// /// - Parameter index: index /// - Returns: node func find(index: Int) -> Node? { var idx: Int = 0 var tempNode: Node = self.dummy while let nextNode = tempNode.next { if index == idx { return nextNode } tempNode = nextNode idx = idx + 1 } return nil } /// 判断给定的链表是否在链表中 /// /// - Parameter node: node /// - Returns: true or false func isContain(node: Node) -> Bool { var tempNode = self.dummy.next while tempNode != nil { if tempNode === node { return true } tempNode = tempNode?.next } return false } /// 单向链表反转:方式一非递归实现 /// /// - Parameter chainList: 源链表 /// - Returns: 反转后的链表 func reverseList() { var prevNode: Node? = self.dummy.next var curNode: Node? = prevNode?.next var tempNode: Node? = curNode?.next prevNode?.next = nil while curNode != nil { tempNode = curNode?.next curNode?.next = prevNode prevNode = curNode curNode = tempNode } self.dummy.next = prevNode } /// 单向链表反转:方式二递归实现 /// /// - Parameter chainList: 源链表 /// - Returns: 反转后的链表 func reverseListUseRecursion(head: Node?, isFirst: Bool) { var tHead = head if isFirst { tHead = self.dummy.next } guard let rHead = tHead else { return } if rHead.next == nil { self.dummy.next = rHead return } else { self.reverseListUseRecursion(head:rHead.next, isFirst: false) rHead.next?.next = rHead rHead.next = nil } }}class LinkedListVC: UIViewController { var chainList: SingleChainList = SingleChainList.init() override func viewDidLoad() { super.viewDidLoad() // 初始化链表 for i in 0..<10 { let node: Node = Node.init(value: String(i)) chainList.insertToTail(node: node) } // 查找结点 for i in 0..<12 { if let find: Node = chainList.find(index: i) { debugPrint("find = \(find.value)") } else { debugPrint("not find idx = \(i)") } } // 删除结点 if chainList.delete(index: 10) { debugPrint("删除 index = \(index)成功") } else { debugPrint("删除 index = \(index)失败") } // 打印结点value信息 debugPrint(chainList.description) // 打印结点个数 debugPrint(chainList.count) // 单向链表反转 chainList.reverseList() // 打印结点value信息 debugPrint(chainList.description) // 单向链表反转 chainList.reverseListUseRecursion(head: nil, isFirst: true) // 打印结点value信息 debugPrint(chainList.description) }} 参考博客 1、面向协议编程与 Cocoa 的邂逅 (上)2、面向协议编程与 Cocoa 的邂逅 (下)3、[译] Swift 面向协议编程入门 面向协议编程初探 面向协议(POP)以面向对象(OOP) 面向对象编程和面向协议编程 面向协议与面向对象的区别 面向协议编程的一些思考 iOS 面向协议方式封装空白页功能 iOS 面向协议封装全屏旋转功能 LXFProtocolTool 浅谈Swift和OC的区别
|
请发表评论