OC和Swift比较

2018-06-07  本文已影响1518人  wordlesser

OC与swift

1.协议

OC:主要用来传值

swift:不仅可以用来传值,swift中的协议可以定义属性方法,并且其协议可以进行扩展,在扩展中还可以有自己的默认实现,这个特性使其可以面向协议的时候非常强大。

例:

//如果遵守了swift中的协议,那么里边的非扩展方法必须实现
protocol AnimationProtocol {
    //最大年龄(属性方法)
    var maxAge: Int {get}
    
    //动物都有自己的名字
    func name()
}

//swift中的协议支持扩展,并且可以再扩展中直接实现具体内容(扩展中不可以定义属性方法),似乎跟OC中的继承一样
extension AnimationProtocol {
    func eat() {
        print("eat");
    }
}


class Dog: AnimationProtocol {
    //maxAge必须实现
    var maxAge: Int {
        get {
            return 20
        }
    }
    
    //name必须实现
    func name() {
        print("name: dog")
    }
    
    //可以实现也可以省略(类似继承中的复写)
    func eat() {
        print("eat shit")
    }

}

class Cat: AnimationProtocol {
    
    var maxAge: Int {
        get {
            return 10
        }
    }
    
    func name() {
        print("name: cat")
    }
}

使用继承很容易出现父类越来越臃肿特别是多重继承时,最终变成方法垃圾场的情况;
但是利用swift的协议,可以实现类似于继承的功能,但是比继承更加灵活;当某几个类有共同特性的时候可以抽出一个协议,使用的时候遵守此协议即可,可以解放父类。

2.泛型

泛型在很多功能上看似可以用多态实现,但还是有很多区别的。
自己目前为止的看法,如下是使用泛型的例子:

    static func set<T>(_ key: String, value: T) {
        let stdDefaults = UserDefaults.standard
        stdDefaults.set(_T<Any>.cast(value), forKey: key)
        stdDefaults.synchronize()
    }
    
    static func get<T>(_ key: String) -> T? {
        let stdDefaults = UserDefaults.standard
        let value: Any? = stdDefaults.value(forKey: key)
        return _T<T>.cast(value)
    }

那么如果将泛型改为多态,如下:

    static func set(_ key: String, value: Any) {
        let stdDefaults = UserDefaults.standard
        stdDefaults.set(value, forKey: key)
        stdDefaults.synchronize()
    }
    
    static func get(_ key: String) -> Any? {
        let stdDefaults = UserDefaults.standard
        let value: Any? = stdDefaults.value(forKey: key)
        return value
    }

会有什么问题呢?
一个简单的例子,如果我获取的是一个model,那么如果是多态,使用应该是这样的:

        let model = Model()
        SDB.set("model", value: model)
        let md = SDB.get("model") as? Model  //使用了as?说明这是类型转换

如果是泛型,使用应该是这样的:

        SDB_T.set("model", value: model)
        let md_t: Model? = SDB_T.get("model")  //前边添加类型,属于泛型的特征类型推断
        
        //static func get<T>(_ key: String) -> T?

类型推断是swift特有的,比如说let str = "",swift可以推断出str为String类型

下边是一个项目中很有用的自定义去重算法:

    //去重算法 Equatable 判等协议
    func removalAlgorithm<T: Equatable>(a: [T], b:T) -> [T] {
        var items = a
        for i in 0..<a.count {
            let item = a[i]
            if item == b {
                items.remove(at: i)
            }
        }
        return items
    }

而mode中所要实现的协议如下:

class Model: Equatable {
    
    var mId: Int?
    var a: String?

    static func == (lhs: Model, rhs: Model) -> Bool {
        if lhs.mId == rhs.mId {
            return true
        }
        return false
    }
}

上边的方法,如果不用泛型,想使用可能就比较麻烦了,需要各种类型转换。

3.结构体和类

oc和swift中结构体何磊的类型是相同的,即结构体是值类型,class是指针类型。
但是swift中结构体更强大,可以实现很多类似于类的功能,目前swift中的Array,Dictory,String均为结构体,因此这些常用的数据类型用法有比较大的差异。
String为例:
OC中两个字符串对象是不可以直接用==进行比较的,但是swift就可以(数组,字典同理)。
既然是值类型,那么有些运算符就可以直接使用,如+:

    func test() {
        var arr1 = [1]
        let arr2 = [2]
        arr1 = arr1 + arr2
        print(arr1 == arr2)
    }

4.?&!

swift是类型确定型语言,对类型是否有值有严格要求,因此引入了?和!来对值进行明确。
oc中如下:

- (NSString *)test {
    return nil;
}

这样写在oc中是完全没有问题的,但是使用者可能就比较麻烦了,因为外部使用者并不能确定这个有没有值,因此每个使用此方法的人都需要去判断返回值是否符合自己预期;

swift中如下:

    func test() ->String {
        //错误的写法,编译器会报错
        return nil
    }

这样写在swift中是会报错的,因为你的返回值String没有带?因此默认是一个非空的,所以此函数的作者就需要去考虑如果这儿是空或者这儿的类型不是我想要的,我要做哪些补救措施,其实就是从源头上对一些错误特别是野指针问题做了预防。
那么在swift中怎么正确使用这一特性呢?
1.在某些场景下,你确定此函数会返回一个有效值,那么你就可以在返回值后边加!或者默认不加;

    func test() ->String {
        return ""
    }

2.有时候我们就是要告诉外边,这个不一定是有效的,需要外部使用者自己处理,那就在返回值后便加?;

    func test() ->String? {
        return nil
    }

5.??

swift中多了一种??判断符,它的作用类似三元运算符,但是使用场景比较多的地方是对一个为空的值做询问,如果为空怎么怎么样,如下:

    func test(_ a :String?) ->String? {
        //如果a为空,则返回空字符串(其实这样写,返回值已经不可能为空了)
        return a ?? ""
    }
上一篇下一篇

猜你喜欢

热点阅读