工作生活

Swift知识点(2)

2019-07-01  本文已影响0人  萤火虫离别的礼物

1、as、as?、as!三种区别

as

switch person1 {
    case let person1 as Student:
        print("是Student类型,打印学生成绩单...")
    case let person1 as Teacher:
        print("是Teacher类型,打印老师工资单...")
    default: break
}

as!
向下转型(Downcasting, 基类转换为派生类)时使用。由于是强制类型转换,如果转换失败会报 runtime 运行错误。
as?
as? 和 as! 操作符的转换规则完全一样。但 as? 如果转换不成功的时候便会返回一个 nil 对象。成功的话返回可选类型值。由于 as? 在转换失败的时候也不会出现错误,所以对于如果能确保100%会成功的转换则可使用 as!,否则使用 as?

2、便利构造函数

示例:

convenience init(imageName: String, bgImageName: String){  
        self.init() 
        setImage(UIImage(named:imageName), for: .normal)   
    }  

使用convenience修饰的构造函数叫做便利构造函数
便利构造函数通常用在对系统的类进行构造函数的扩充时使用。

3、private(set)

private(set)将set方法的访问级别降低,低于get访问级别,set方法只有在该模块中调用,对外是只读的。
示例:

public private(set) lazy var name: String = {
        return "hello";
 }()

4、Swift和OC混编

5、NS_ASSUME_NONNULL_BEGIN & NS_ASSUME_NONNULL_END

Swift中的对象使用 ? 和 ! 可以分为可选和不可选,OC里面没有这个区分,导致OC和Swift混编的时候,Swift不知道一个Objective-C对象到底是optional还是non-optional,因此这种情况下编译器会隐式地将Objective-C的对象当成是non-optional。
为了解决这个问题,苹果在Xcode 6.3引入了一个Objective-C的新特性:nullability annotations。这一新特性的核心是两个新的类型注释: __nullable 和 __nonnull,如果需要每个属性或每个方法都去指定nonnull和nullable,是一件非常繁琐的事。苹果为了减轻我们的工作量,专门提供了两个宏:NS_ASSUME_NONNULL_BEGIN, NS_ASSUME_NONNULL_END。在这两个宏之间的代码,所有简单指针对象都被假定为nonnull,因此我们只需要去指定那些nullable的指针。

NS_ASSUME_NONNULL_BEGIN
@interface TestObject : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic) BOOL isOpen;

- (void)setDataAccessDate:(NSDate*)date forRequestWithIdentifier:(NSString* _Nullable)identifier;

@end
NS_ASSUME_NONNULL_END

6、Switch语句

Swift中Switch语句不需要在每个case后面加break,会自动跳出不执行后面的case,如果想按顺序执行下面的case,可以加上fallthrough语句。

7、可失败构造器

如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器。使用 init? 的方法,当返回nil的时候表示构造失败。

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}

8、try try? try! 的区别

发生异常的时候的三种处理方式:

do {
    var str = try testFunc(str: "three")
} catch {
    print(“error”)
}
var str = try? testFunc(str: "three")
var str = try! testFunc(str: "three")

9、逃逸闭包和非逃逸闭包

闭包只有在函数中做参数时才会区分逃逸闭包和非逃逸闭包。
Swift 3.0之后,传递闭包到函数中的时候,系统会默认为非逃逸闭包类型@noescaping,逃逸闭包在闭包前要添加@escaping关键字。
两者生命周期的区别:
非逃逸闭包的生命周期与函数相同:

逃逸闭包的生命周期:

//ClassDetailsDAO.swift
func enrollToClass(classUUID: String, spot: String?, completion: @escaping (Result<ClassData>) -> Void) {
        guard let calendarEntry = model.calendarEntry(withUUID: classUUID, createNew: false) else {
            completion(.failure(ClassDetailsDAOError.entryNotFound))
            return
        }
    }

逃逸闭包一般使用的场景:网络请求请求结束后才调用的闭包,因为发起请求后过了一段时间后这个闭包才执行,并不一定是在函数作用域内执行。

循环引用

非逃逸闭包不会产生循环引用,它会在函数作用域内释放,编译器可以保证在函数结束时闭包会释放它捕获的所有对象。
逃逸闭包会产生循环引用的问题,为了解决循环引用问题,使用[weak self]

classDetailsDAO.enrollToClass(classUUID: classUUID, spot: spot) { [weak self] (result) in
         guard let strongSelf = self else {
             return
         }

         switch result {
         case .success(let classData):
             strongSelf.presenter.didEnrollToClass(classData: classData)
         case .failure(let error):
             strongSelf.presenter.didFailToEnrollToClass(error: error)
        }
}

10、Any和AnyObject

11、String(describing:)

获取类名称的字符串

class Foo {

    // 实例属性中指定明确的类名来获取名称
    var typeName: String {
        return String(describing: Foo.self)
    }

    // 实例属性中动态获取类名来获取名称
    var otherTypeName: String {
        let thisType = type(of: self)
        return String(describing: thisType)
    }

    // 类属性中直接获取名称
    static var typeName: String {
        return String(describing: self)
    }

}

Foo().typeName       // = "Foo"
Foo().otherTypeName  // = "Foo"
Foo.typeName         // = "Foo"

12、defer的使用

Swift2.0中加入了defer新语法声明,defer译为延缓、推迟之意。
使用场景:
比如,读取某目录下的文件内容并处理数据,你需要首先定位到文件目录,打开文件夹,读取文件内容以及处理数据,在读取文件内容失败、处理数据失败的情况下要关闭文件的操作,在读取成功的情况下最后也要关闭文件的操作,这个时候可以把关闭文件的代码放到defer中来延迟执行。
所以,defer{}中的代码会在作用域结束之前或者说return之前最后调用
例子:

func fridgeContains(_ food: String) -> Bool {
    fridgeIsOpen = true
    defer {
        //最后调用
        fridgeIsOpen = false
    }
    
    let result = fridgeContent.contains(food)
    return result
}

13、@discardableResult的作用

@discardableResult func doSomething() -> Bool {
  return true
}

例如上面的方法,如果使用 doSomething() 调用该函数,但是没有用变量来接收函数的返回参数时,就会报警告,这时候@discardableResult来消除警告。

上一篇下一篇

猜你喜欢

热点阅读