来一次有侧重点的区分Swift与Objective-C

[TOC]html

@(swift)[温故而知新]node

面试中常常被问到Objective-CSwift的区别,其实区别仍是不少的,重点整理一下我的以为很重要的:面向协议编程git

1、Objective-C与Swift的异同

1.一、swift和OC的共同点:

  • - OC出现过的绝大多数概念,好比引用计数ARC(自动引用计数)、属性协议接口初始化扩展类命名参数匿名函数等,在Swift中继续有效(可能最多换个术语)。
  • - SwiftObjective-C共用一套运行时环境,Swift的类型能够桥接到Objective-C(下面我简称OC),反之亦然

1.二、swift的优势:

  • - swift注重安全,OC注重灵活
  • - swift注重面向协议编程、函数式编程、面向对象编程,OC注重面向对象编程
  • - swift注重值类型,OC注重指针和引用
  • - swift是静态类型语言,OC是动态类型语言
  • - swift容易阅读,文件结构和大部分语法简易化,只有.swift文件,结尾不须要分号
  • - swift中的可选类型,是用于全部数据类型,而不只仅局限于类。相比于OC中的nil更加安全和简明
  • - swift中的泛型类型更加方便和通用,而非OC中只能为集合类型添加泛型
  • - swift中各类方便快捷的高阶函数函数式编程) (Swift的标准数组支持三个高阶函数:mapfilterreduce,以及map的扩展flatMap)
  • - swift新增了两种权限,细化权限。open > public > internal(默认) > fileprivate > private
  • - swift中独有的元组类型(tuples),把多个值组合成复合值。元组内的值能够是任何类型,并不要求是相同类型的。

1.三、swift的不足:

  • - 版本不稳定
  • - 公司使用比例不高,使用人数比例偏低
  • - 有些语法其实能够只规定一种格式,没必要这样也行,那样也行。像Go同样禁止一切(Go有点偏激)耍花枪的东西,同一个规范,方便团队合做和阅读他人代码。

Swift 跟 JavaScript 有什么相同和不一样点?github

从数据结构角度,Golang和Swift对比,有何优缺点?面试

iOS——Objective-C与Swift优缺点对比编程

2、swift类(class)和结构体(struct)的区别

区别 class struct
定义属性用于存储值
定义方法用于提供功能
定义附属脚本用于访问值
定义构造器用于生成初始化值
经过扩展以增长默认实现的功能
遵照协议以对某类提供标准功能
是否能够继承
是否能够引用计数
类型转换
析构方法释放资源

2.1 定义

class Class {
    // class definition goes here
}

struct Structure {
    // structure definition goes here
}
复制代码

2.2 值 VS 引用

一、结构体 struct 和枚举 enum 是值类型,类 class 是引用类型。 二、String, ArrayDictionary都是结构体,所以赋值直接是拷贝,而NSString, NSArrayNSDictionary则是类,因此是使用引用的方式。 三、structclass 更“轻量级”,struct 分配在栈中,class 分配在堆中。swift

2.3 指针

若是你有 C,C++ 或者 Objective-C 语言的经验,那么你也许会知道这些语言使用指针来引用内存中的地址。一个 Swift 常量或者变量引用一个引用类型的实例与 C 语言中的指针相似,不一样的是并不直接指向内存中的某个地址,并且也不要求你使用星号(*)来代表你在建立一个引用。Swift 中这些引用与其它的常量或变量的定义方式相同。数组

2.4 选择使用类和结构体

使用struct任何状况下,优先考虑使用struct,若是知足不了,再考虑class安全

  • - 好比数据被多线程使用,并且数据没有使用class的必要性,就使用struct
  • - 但愿实例被拷贝时,不收拷贝后的新实例的影响
  • - 几何图形的大小,能够封装width和height属性,都是Double类型
  • - 指向连续序列范围的方法,能够封装start和length属性,都是Int类型
  • - 一个在3D坐标系统的点, 能够封装x, y和z属性,都是Double类型

使用classbash

  • - 须要继承
  • - 被递归调用的时候(参考链表的实现,node选用class而不是struct
  • - 属性数据复杂
  • - 但愿引用而不是拷贝

参考连接1:类和结构体 参考连接2:官方文档

3、Objective-C中的protocol与Swift中的protocol的区别

相比于OCSwift 能够作到protocol协议方法的具体默认实现(经过extension)相比多态更好的实现了代码复用,而 OC 则不行。

4、面向协议面向接口)与面向对象的区别

面向对象面向协议的的最明显区别是对抽象数据的使用方式,面向对象采用的是继承,而面向协议采用的是遵照协议。在面向协议设计中,Apple建议咱们更多的使用 值类型struct)而非 引用类型class)。这篇文章中有一个很好的例子说明了面向协议面向对象更符合某些业务需求。其中有飞机、汽车、自行车三种交通工具(均继承自父类交通工具);老虎、马三种动物(均继承父类自动物);在古代马其实也是一种交通工具,可是父类是动物,若是马也有交通工具的功能,则:


若是采用面向对象编程,则须要既要继承动物,还要继承交通工具,可是父类交通工具备些功能马是不须要的。因而可知继承,做为代码复用的一种方式,耦合性仍是太强。事物每每是一系列特质的组合,而不仅仅是以一脉相承并逐渐扩展的方式构建的。之后慢慢会发现面向对象不少时候其实不能很好地对事物进行抽象。

若是采用面向协议编程,马只须要实现出行协议就能够拥有交通工具的功能了。面向协议就是这样的抽离方式,更好的职责划分,更加具象化,职责更加单一。很明显面向协议的目的是为了下降代码的耦合性

总结:

面向协议相对于面向对象来讲更具备可伸缩性可重用性,而且在编程的过程当中更加模块化,经过协议以及协议扩展替代一个庞大的基类,这在大规模系统编程中会有很大的便捷之处。

3.一、协议协议扩展基类有三个明显的优势

  • 一、类型能够遵照多个协议可是只有一个基类。 这意味着类型能够随意遵照任何想要特性的协议,而不须要一个巨大的基类。
  • 二、不须要知道源码就可使用协议扩展添加功能。这意味着咱们能够任意扩展协议,包括swift内置的协议,而不须要修改基类源码。通常状况下咱们会给特定的类而非类的层级继承体系)添加扩展;可是若是必要,咱们依然能够给基类添加扩展,使全部的子类继承添加的功能。使用协议,全部的属性方法构造函数都被定义在遵照协议的类型自身中。这让咱们很容易地查看到全部东西是怎么被定义初始化的。咱们不须要在类的层级之间来回穿梭以查看全部东西是如何初始化的。忘记设置超类可能没有什么大问题,可是在更复杂的类型中,忘记合理地设置某个属性可能会致使意想不到的行为。
  • 三、协议能够被类、结构体和枚举遵照,而类层级约束为类类型。 协议协议扩展可让咱们在更合理的地方使用值类型引用类型值类型的一个主要的区别就是类型是如何传递的。当咱们传递引用类型(class)的实例时,咱们传递的对原实例的引用。这意味着所作的任何更改都会反射回原实例中。当咱们传递值类型的实例时,咱们传递的是对原实例的一份拷贝。这意味着所作的任何更改都不会反射回原实例中。使用值类型确保了咱们老是获得一个惟一的实例由于咱们传递了一份对原实例的拷贝而非对原实例的引用。所以,咱们能相信没有代码中的其它部分会意外地修改咱们的实例。这在多线程环境中尤为有用,其中不一样的线程能够修改数据并建立意外地行为

3.二、面向对象的特色

优势:
  • - 封装

数据封装、访问控制、隐藏实现细节、类型抽象为类;

代码以逻辑关系组织到一块儿,方便阅读;

高内聚、低耦合的系统结构

  • - 继承

代码重用,继承关系,更符合人类思惟

  • - 多态

接口重用,父类指针可以指向子类对象

当父类的引用指向子类对象时,就发生了向上转型,即把子类类型对象转成了父类类型。

向上转型的好处是隐藏了子类类型,提升了代码的扩展性。

多态的不足:
  • - 父类有部分public方法是子类不须要的,也不容许子类覆盖重写
  • - 父类有一些方法是必需要子类去覆盖重写的,在父类的方法其实也是一个空方法
  • - 父类的一些方法即使被子类覆盖重写,父类原方法仍是要执行的
  • - 父类的一些方法是可选覆盖重写的,一旦被覆盖重写,则以子类为准
较好的抽象类型应该:
  • - 更多地支持值类型,同时也支持引用类型
  • - 更多地支持静态类型关联(编译期),同时也支持动态派发(runtime)
  • - 结构不庞大不复杂
  • - 模型可扩展
  • - 不给模型强制添加数据
  • - 不给模型增长初始化任务的负担
  • - 清楚哪些方法该实现哪些方法不需实现

3.三、OneV's Den提到的面向对象的三个困境:

一、动态派发的安全性(这应该是OC的困境,在Swift中Xcode是不可能让这种问题编译经过的)

Objective-C中下面这段代码编译是不会报警告和错误的

NSObject *v1 = [NSObject new];
NSString *v2 = [NSString new];
NSNumber *v3 = [NSNumber new];
NSArray *array = @[v1, v2, v3];
for (id obj in array) {
    [obj boolValue];
}
复制代码

Objective-C中能够借助泛型检查这种潜在的问题,Xocde会提示警告

@protocol SafeProtocol <NSObject>
- (void)func;
@end

@interface SafeObj : NSObject<SafeProtocol>
@end
@implementation SafeObj
- (void)func {
    
}
@end

@interface UnSafeObj : NSObject
@end
@implementation UnSafeObj
@end
复制代码

Objective-CXcode7中,可使用带泛型容器也能够解决这个问题,可是只是⚠️,程序运行期间仍可能因为此问题致使的崩溃

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<SafeProtocol>'
NSArray<id<SafeProtocol>> *array = @[v1, v2];
for (id obj in array) {
    [obj func];
}
复制代码

使用swift,必须指定类型,不然不是⚠️,而是❌,因此swift编译阶段就能够检查出问题

// 直接报错,而不是警告
// Cannot convert value of type 'String' to expected argument type 'NSNumber'
var array: [NSNumber] = []
array.append(1)
array.append("a")
复制代码
二、横切关注点

咱们很难在不一样的继承体系复用代码,用行话来说就是横切关注点Cross-Cutting Concerns)。好比下面的关注点myMethod,位于两条继承链 (UIViewController -> ViewCotrollerUIViewController -> UITableViewController -> AnotherViewController) 的横切面上。面向对象是一种不错的抽象方式,可是确定不是最好的方式。它没法描述两个不一样事物具备某个相同特性这一点。在这里,特性的组合要比继承更贴切事物的本质。

class ViewCotroller: UIViewController {   
    func myMethod() {
        
    }
}
复制代码
class AnotherViewController: UITableViewController {
    func myMethod() {
        
    }
}
复制代码

面向对象编程中,针对这种问题的几种解决方案:

  • - 一、Copy & Paste

快速,可是这也是坏代码的开头。咱们应该尽可能避免这种作法。

  • - 二、引入 BaseViewController

看起来这是一个稍微靠谱的作法,可是若是不断这么作,会让所谓的 Base 很快变成垃圾堆。职责不明确,任何东西都能扔进 Base,你彻底不知道哪些类走了 Base,而这个“超级类”对代码的影响也会不可预估。

  • - 三、依赖注入

经过外界传入一个带有 myMethod 的对象,用新的类型来提供这个功能。这是一个稍好的方式,可是引入额外的依赖关系,可能也是咱们不太愿意看到的。

  • - 四、多继承

固然,Swift 是不支持多继承的。不过若是有多继承的话,咱们确实能够从多个父类进行继承,并将 myMethod 添加到合适的地方。有一些语言选择了支持多继承 (好比 C++),可是它会带来 OOP 中另外一个著名的问题:菱形缺陷

Swift面向协议编程中,针对这种问题的解决方案使用协议扩展添加默认实现):

protocol P {
    func myMethod()
}
extension P {
    func myMethod() {
        doWork()
    }
}
复制代码
extension ViewController: P { }
extension AnotherViewController: P { }

viewController.myMethod()
anotherViewController.myMethod()
复制代码
三、菱形问题

多继承中,两个父类实现了相同的方法,子类没法肯定继承哪一个父类的此方法,因为多继承的拓扑结构是一个菱形,因此这个问题有被叫作菱形缺陷(Diamond Problem)。

上面的例子中,若是咱们有多继承,那么 ViewControllerAnotherViewController 的关系可能会是这样的:

若是ViewControllerUITableViewController都实现了myMethod方法,则在AnotherViewController中就会出现菱形缺陷问题。

咱们应该着眼于写干净并安全的代码,干净的代码是很是易读和易理解的代码。

5、编程实践:基于protocol的链表实现

import UIKit

protocol ChainListAble {
    associatedtype T: Equatable
    // 打印
    var description: String{get}
    // 数量
    var count: Int{get}
    
    /// 插入
    func insertToHead(node: Node<T>)
    func insertToHead(value: T)
    func insertToTail(node: Node<T>)
    func insertToTail(value: T)
    func insert(node: Node<T>, afterNode: Node<T>) -> Bool
    func insert(value: T, afterNode: Node<T>) -> Bool
    func insert(node: Node<T>, beforNode: Node<T>) -> Bool
    func insert(value: T, beforNode: Node<T>) -> Bool
    
    /// 删除(默认第一个符合条件的)
    @discardableResult func delete(node: Node<T>) -> 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<T>?
    func find(index: Int) -> Node<T>?
    
    /// 判断结点是否在链表中
    func isContain(node: Node<T>) -> Bool
}

/// [值类型不能在递归里调用](https://www.codetd.com/article/40263),所以Node类型只能是class而不是struct
// 有些时候你只能使用类而不能使用结构体,那就是递归里
// struct报错:Value type 'Node' cannot have a stored property that recursively contains it
class Node<T: Equatable> {
    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<T>) {
        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<T>) {
        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<T>) -> 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<T>, afterNode: Node<T>) -> 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<T>) -> 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<T>, beforNode: Node<T>) -> 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<T>) -> 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<T>? {
        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<T>? {
        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<T>) -> 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<String>? = self.dummy.next
        var curNode: Node<String>? = prevNode?.next
        var tempNode: Node<String>? = 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<T>?, 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)
    }
}
复制代码

参考博客

一、面向协议编程与 Cocoa 的邂逅 (上) 二、面向协议编程与 Cocoa 的邂逅 (下) 三、[译] Swift 面向协议编程入门

面向协议编程初探

面向协议(POP)以面向对象(OOP)

面向对象编程和面向协议编程

面向协议与面向对象的区别

面向协议编程的一些思考

iOS 面向协议方式封装空白页功能

iOS 面向协议封装全屏旋转功能

LXFProtocolTool

浅谈Swift和OC的区别

相关文章
相关标签/搜索