美文网首页
iOS 面试题(四)

iOS 面试题(四)

作者: 派大星的博客 | 来源:发表于2020-05-25 11:37 被阅读0次

1. Property wrappers in Swift【属性包装】

官方文档 -- Property wrappers
Swift 5 属性包装器Property Wrappers完整指南 -- 掘金
0258-property-wrappers

  • 它在管理属性存储方式与定义属性的代码之间增加了一层封装
    A property wrapper adds a layer of separation between code that manages how a property is stored and the code that defines a property.

主旨就是:通过property Wrapper机制,对一些类似的属性的实现代码做同一封装。

说简单点: 通过@propertyWrapper可以移除掉一些重复或者类似的代码。

  • 定义
@propertyWrapper
struct TwelveOrLess {
    private var number: Int
    init() { self.number = 0 }
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}
  • 使用
struct SmallRectangle {
    @TwelveOrLess var height: Int
    @TwelveOrLess var width: Int
}

var rectangle = SmallRectangle()
print(rectangle.height)
// Prints "0"

rectangle.height = 10
print(rectangle.height)
// Prints "10"

rectangle.height = 24
print(rectangle.height)
// Prints "12"
  • 使用限制

Property wrappers并非没有限制。 他们强加了许多限制:

带有包装器的属性不能在子类中覆盖。
具有包装器的属性不能是lazy,@NSCopying,@NSManaged,weak或unowned。
具有包装器的属性不能具有自定义的set或get方法。
wrappedValue,init(wrappedValue :)和projectedValue必须具有与包装类型本身相同的访问控制级别
不能在协议或扩展中声明带有包装器的属性。
属性包装器需要Swift 5.1,Xcode 11和iOS 13。


2. JSON Parsing in Swift

  • SwiftyJSON Github 上 Star 最多的 Swift JSON 解析框架. 其本质其实只是将 JSON 解析成了字典类型的数据,而实际使用时依然需要使用下标方式去取值,非常繁琐且容易出错,不易阅读和维护。

  • HandyJSON 阿里推出的一个用于 Swift 语言中的 JSON 解析框架。采用的是 Swift 反射 + 内存赋值的方式来构造 Model 实例。但是有内存泄露,兼容性差等问题。思路与 Codable 殊途同归。


  • ObjectMapper 面向协议的 Swift JSON 解析框架, 使用范型机制进行模型解析,但是需要手动对每一个属性写映射关系。
struct Record: Mappable {
    var id: Int?
    var quarter: String?
    var volumeOfMobileData: String?
    var volume: NSDecimalNumber {
        return NSDecimalNumber(string: volumeOfMobileData)
    }
    init?(map: Map) {}
    init() {}

    mutating func mapping(map: Map) {
        id <- map["_id"]
        quarter <- map["quarter"]
        volumeOfMobileData <- map["volume_of_mobile_data"]
    }
}


/// A type that can convert itself into and out of an external representation.
public typealias Codable = Decodable & Encodable

/// A type that can encode itself to an external representation.
public protocol Encodable {
    public func encode(to encoder: Encoder) throws
}

/// A type that can decode itself from an external representation.
public protocol Decodable {
    public init(from decoder: Decoder) throws
}
  • 二次封装: 因为Codable 是 Data <-> Object 之间的转化,而通常我们可能更需要的是 Dictionary <-> Object 之间的转化。
import Foundation

public typealias JSONObject = [String: Any]
public typealias JSONCodable = JSONEncodable & JSONDecodable

public protocol JSONDecodable: Decodable {
    init(json: JSONObject) throws
}

public protocol JSONEncodable: Encodable {
    func toDictionary() -> JSONObject?
}

public extension JSONDecodable {
    init(json: JSONObject) throws {
        let data: Data = try JSONSerialization.data(withJSONObject: json, options: [])
        self = try JSONDecoder().decode(Self.self, from: data)
    }
    
}

public extension JSONEncodable {
    func toDictionary() -> JSONObject? {
        guard let data = try? JSONEncoder().encode(self) else {
            return nil
        }
        
        guard let serializedObject = try?
            JSONSerialization.jsonObject(with: data, options: []) else {
            return nil
        }
        
        guard let jsonObject = serializedObject as? JSONObject else {
            return nil
        }
        
        return jsonObject
    }
}


3. Unit Test:UserDefaults

对单例的测试
对数据持久化的测试

class UserDefaultsManager {
    static let shared = UserDefaultsManager(UserDefaults.standard)
    let userDefaults: UserDefaults!
    init(_ userDefaults: UserDefaults) {
        self.userDefaults = userDefaults
    }
}

extension UserDefaultsManager {
    func setBannersEnabled(_ enabled: Bool, for key: String) {
        self.userDefaults.set(enabled, forKey: key)
    }
    
    func getBannersEnabled(by key: String) -> Bool {
        return self.userDefaults.bool(forKey: key)
    }
}
//
//  UserDefaultsManagerTests.swift
//  SphDemoTests
//
//  Created by shengnan liu on 19/5/20.
//  Copyright © 2020 sph. All rights reserved.
//

import Quick
import Nimble
import RxBlocking

@testable import SphDemo

class UserDefaultsManagerTests: QuickSpec {
    override func spec() {
        var manager: UserDefaultsManager!
        var userDefaults: UserDefaults!
        let suitName = "Test"
        
        beforeEach {
            userDefaults = UserDefaults(suiteName: suitName)
            manager = UserDefaultsManager(userDefaults)
        }

        afterEach {
            userDefaults.removePersistentDomain(forName: suitName)
            manager = nil
            userDefaults = nil
        }
        
        describe("UserDefaultsManager") {
            it("should get BannersEnabled after saved") {
                let mockValue = true
                manager.setBannersEnabled(mockValue, for: "BannersEnabled")
                let bannersEnabled = manager.getBannersEnabled(by: "BannersEnabled")
                expect(bannersEnabled) == mockValue
            }
            it("shouldn't get BannersEnabled before saved") {
                let bannersEnabled = manager.getBannersEnabled(by: "BannersEnabled")
                expect(bannersEnabled) == false
            }
        }
    }
}


4. Unit Test:Api


5. RxSwift


相关文章

网友评论

      本文标题:iOS 面试题(四)

      本文链接:https://www.haomeiwen.com/subject/jlgbnhtx.html