1. class 和 struct 的区别
class 为类, struct 为结构体, 类是引用类型, 结构体为值类型, 结构体不可以继承
2.map、filter、reduce 的作用
map 用于映射, 可以将一个列表转换为另一个列表
[1, 2, 3].map{"\($0)"}// 数字数组转换为字符串数组
//["1", "2", "3"]
filter 用于过滤, 可以筛选出想要的元素
[1, 2, 3].filter{$0 % 2 == 0} // 筛选偶数
//[2]
reduce 合并
[1, 2, 3].reduce(""){$0 + "\($1)"}// 转换为字符串并拼接
//"123"
3.map 与 flatmap 的区别
flatmap 有两个实现函数实现
public func flatMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
这个方法, 中间的函数返回值为一个可选值, 而 flatmap 会丢掉那些返回值为 nil 的值
例如
//例如
["1", "@", "2", "3", "a"].flatMap{Int($0)}
// [1, 2, 3]
["1", "@", "2", "3", "a"].map{Int($0) ?? -1}
//[Optional(1), nil, Optional(2), Optional(3), nil]
另一个实现
public func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Iterator.Element] where SegmentOfResult : Sequence
中间的函数, 返回值为一个数组, 而这个 flapmap 返回的对象则是一个与自己元素类型相同的数组
func someFunc(_ array:[Int]) -> [Int] {
return array
}
[[1], [2, 3], [4, 5, 6]].map(someFunc)
//[[1], [2, 3], [4, 5, 6]]
[[1], [2, 3], [4, 5, 6]].flatMap(someFunc)
//[1, 2, 3, 4, 5, 6]
其实这个实现, 相当于是在使用 map 之后, 再将各个数组拼起来一样的
[[1], [2, 3], [4, 5, 6]].map(someFunc).reduce([Int]()) {$0 + $1}
// [1, 2, 3, 4, 5, 6]
4.如何获取当前代码的函数名和行号
file 用于获取当前文件文件名
line 用于获取当前行号
column 用于获取当前列编号
function 用于获取当前函数名
var file: String = #file
var line: String = #line
var column: String = #column
var function: String = #function
method: String = #function,
print("\(file)--\(line)--\(columne)--\(function))
5.private,fileprivate,internal,public 和 open 五种访问控制的权限
//1.当private 或fileprivate 修饰属性的时候
privte 修饰的属性只能在本类的作用域且在当前文件内能访问
fileprivate 修饰的属性只能在当前文件内访问到,不管是否在本类作用域
//2. fileprivate 修饰方法的时候
fileprivate 修饰的方法,类的外部无法调用
fileprivate 修饰方法,子类定义的同一个文件中,可以访问
fileprivate 修饰方法,子类定义不在同一个文件,不可以访问
//3.public 和 open 的区别
这两个都用于在模块中声明需要对外界暴露的函数, 区别在于, public 修饰的类, 在模块外无法继承, 而 open 则可以任意继承, 公开度来说, public < open
6. guard 的使用场景
swift 的语法糖之一
//当(条件) 为false 的时候进入{}
guard 条件
{
}
7.if let 语法糖使用场景
swift 中因为有optional,所以需要经常判空,举例说明if let 解决了什么问题
//不使用if let
func doSometing(str: String?){
...
}
let value :String ! = str
if value != ni {
//如果value 不为 nil进入大括号执行
}
//使用了if let 简洁了很多
func doSometing(str: String?){
...
}
if let value = str {
//如果value 不为 nil进入大括号执行
}
8.defer的使用场景
defer 语句块中的代码, 会在当前作用域结束前调用, 常用场景如异常退出后, 关闭数据库连接
func someQuery() -> ([Result], [Result]){
//假如打开数据库失败
let db = DBOpen("xxx")
defer {
db.close()
}
//或者 查询失败导致异常退出 调用defer,执行里面的代码
guard results1 = db.query("query1") else {
return nil
}
guard results2 = db.query("query2") else {
return nil
}
return (results1, results2)
}
9.String 与 NSString 的关系与区别
NSString 与 String 之间可以随意转换
let someString = "123"
let someNSString = NSString(string: "n123")
let strintToNSString = someString as NSString
let nsstringToString = someNSString as String
10.associatedtype 的作用
简单来说就是 protocol 使用的泛型
例如定义一个列表协议
protocol ListProtcol {
associatedtype Element
func push(_ element:Element)
func pop(_ element:Element) -> Element?
}
实现协议的时候, 可以使用 typealias 指定为特定的类型, 也可以自动推断, 如
class IntList: ListProtcol {
typealias Element = Int // 使用 typealias 指定为 Int
var list = [Element]()
func push(_ element: Element) {
self.list.append(element)
}
func pop(_ element: Element) -> Element? {
return self.list.popLast()
}
}
class DoubleList: ListProtcol {
var list = [Double]()
func push(_ element: Double) {// 自动推断
self.list.append(element)
}
func pop(_ element: Double) -> Double? {
return self.list.popLast()
}
}
11.关于泛型的使用
class AnyList<T>: ListProtcol {
var list = [T]()
func push(_ element: T) {
self.list.append(element)
}
func pop(_ element: T) -> T? {
return self.list.popLast()
}
}
12.可以使用 where 字句限定 Element 类型, 如:
extension ListProtcol where Element == Int {
func isInt() ->Bool {
return true
}
}
13. ?? 的用法
可选值的默认值, 当可选值为nil 的时候, 会返回后面的值. 如
let someValue = optional1 ?? 0
14. lazy 的用法
swift 中的懒加载,只有被调用到的时候,才初始化和赋值
class LazyClass {
lazy var someLazyValue: Int = {
print("lazy init value")
return 1
}()
var someNormalValue: Int = {
print("normal init value")
return 2
}()
}
let lazyInstance = LazyClass()
print(lazyInstance.someNormalValue)
print(lazyInstance.someLazyValue)
15.swift block循环引用解决
在其参数前面使用[weak self]或者[unowned self]
let emtyOb = Observable<String>.empty()
_ = emtyOb.subscribe(onNext: { [weak self] (number) in
print("订阅:",number)
self.label.text = number
})
16. dynamic 的用法
由于 swift 是一个静态语言, 所以没有 Objective-C 中的消息发送这些动态机制, dynamic 的作用就是让 swift 代码也能有 Objective-C 中的动态机制, 常用的地方就是 KVO 了, 如果要监控一个属性, 则必须要标记为 dynamic, 可以参考文章http://www.jianshu.com/p/ae26100b9edf
什么时候使用 @objc
@objc 用途是为了在 Objective-C 和 Swift 混编的时候, 能够正常调用 Swift 代码. 可以用于修饰类, 协议, 方法, 属性.
常用的地方是在定义 delegate 协议中, 会将协议中的部分方法声明为可选方法, 需要用到@objc
@objc protocol OptionalProtocol {
@objc optional func optionalFunc()
func normalFunc()
}
class OptionProtocolClass: OptionalProtocol {
func normalFunc() {
}
}
let someOptionalDelegate: OptionalProtocol = OptionProtocolClass()
someOptionalDelegate.optionalFunc?()
17. 什么是高阶函数
一个函数如果可以以某一个函数作为参数, 或者是返回值, 那么这个函数就称之为高阶函数, 如 map, reduce, filter
18. static 和 class 有什么区别
static 定义的方法不可以被子类继承, class 则可以
class AnotherClass {
static func staticMethod(){}
class func classMethod(){}
}
class ChildOfAnotherClass: AnotherClass {
override class func classMethod(){}
//override static func staticMethod(){}// error
}
19.枚举定义
与OC不一样,Swift的枚举扩展性很强了,OC只能玩Int,swift 支持
整型(Integer)
浮点数(Float Point)
字符串(String)
布尔类型(Boolean)
enum Movement {
case letf
case right
case top
case bottom
}
enum Area: String {
case Dong = "dong"
case Nan = "nan"
case Xi = "xi"
case Bei = "bei"
}
//嵌套枚举
enum Area {
enum DongGuan {
case NanCheng
case DongCheng
}
enum GuangZhou {
case TianHe
case CheBei
}
}
//枚举关联值
enum Trade {
case Buy(stock:String,amount:Int)
case Sell(stock:String,amount:Int)
}
let trade = Trade.Buy(stock: "003100", amount: 100)
switch trade {
case .Buy(let stock,let amount):
print("stock:\(stock),amount:\(amount)")
case .Sell(let stock,let amount):
print("stock:\(stock),amount:\(amount)")
default:
()
}
20. swift中set 、get 方法
swift 中的set 和 get 要复杂一点。 在swift 中主要分存储型属性 和 计算型属性 这两种 , 一般 我们只是给计算属性添加 get\set 重写
var command:Int {
get {
//return command; 会导致死循环
//return self.command; 会导致死循环
//return _command; 会导致死循环
//且不能像OC那样 return _command;
return 1
}
set {
//新值 newValue
//value 为一个外部属性变量
value = newValue
}
}
//为了解决储型属性的set、get 方法问题
var _command:int?
var command :Int {
get {
return _command
}
set {
_command = newValue
}
}
21. swift 中 willset 和didset 方法
属性初始化的时候,willSet 和didSet 不会调用,只有在初始化上下文之外,属性发生改变的时候调用;
给属性添加观察者属性的时候,必须声明属性类型,否则编译会报错;
var command :Int {
willSet {
print("newValue is \(newValue)")
}
didSet {
print("newValue is \(newValue)")
print("oldValue is \(oldValue)")
}
}