美文网首页
Swift小点(3)

Swift小点(3)

作者: 纳兰沫 | 来源:发表于2020-06-08 09:27 被阅读0次

    随机数生成

    由于iPhoen5和之前的手机是32位CPU,arc4random 所返回的值不论在什么平台上都是一个 UInt32 ,于是在 32 位的平 台上就有一半几率在进行 Int 转换时越界 故使用func arc4random_uniform(_: UInt32) -> UInt32

    let diceFaceCount: UInt32 = 6
    let randomRoll = Int(arc4random_uniform(diceFaceCount)) + 1 
    print(randomRoll)
    
    func random(in range: Range<Int>) -> Int {
        let count = UInt32(range.endIndex - range.startIndex)
        return Int(arc4random_uniform(count)) + range.startIndex
    }
    for _ in 0...100 {
        let range = Range<Int>(1...6)
        print(random(in: range))
    }
    

    print 和 debugPrint

    extension Meeting: CustomStringConvertible {
        var description: String {
            return "于 \(self.date) 在 \(self.place) 与 \(self.attendeeName) 进行会议"
        }
    }
    

    1.CustomDebugStringConvertible仅发生在调试中使用debugger来进行打印的时候的输出
    2.对于实现了CustomDebugStringConvertible协议的类型 可以在打断点并在控制台使用po 对象的命令进行打印

    错误和异常处理

    do {
        try d.write(toFile: "Hello", options: [])
    } catch let error as NSError {
        print ("Error: \(error.domain)")
    }
    
    enum LoginError: Error {
        case UserNotFound, UserPasswordNotMatch
    }
    func login(user: String, password: String) throws {
        //users 是 [String: String],存储[用户名:密码]
        if !users.keys.contains(user) {
            throw LoginError.UserNotFound
        }
        if users[user] != password {
            throw LoginError.UserPasswordNotMatch
        }
        print("Login successfully.")
    }
    

    断言

      func convertToKelvin(_ celsius: Double) -> Double {
            assert(celsius > -273.15, "输入的摄氏温度不能低于绝对零度")
            return celsius - (-273.15)
       }
    

    断言是开发时的特性 只有在Debug编译的时候有效,而在运行时是不被编译执行的,因此断言并不会消耗运行时的性能

    image.png

    可以强制禁用断言

    fatalError

    class MyClass {
        func methodMustBeImplementedInSubclass() {
            fatalError("这个方法必须在子类中被重写")
        }
    }
    class YourClass: MyClass {
        override func methodMustBeImplementedInSubclass() {
            print("YourClass 实现了该方法")
        }
    }
    class TheirClass: MyClass {
        func someOtherMethod() {
        }
    }
    YourClass().methodMustBeImplementedInSubclass()
    // YourClass 实现了该方法
    TheirClass().methodMustBeImplementedInSubclass()
    

    JSON 和 Codable

    struct Obj: Codable {
        let menu: Menu
        struct Menu: Codable {
            let id: String
            let value: String
            let popup: Popup
        }
        struct Popup: Codable {
            let menuItem: [MenuItem]
            enum CodingKeys: String, CodingKey {
                case menuItem = "menuitem"
            }
        }
        struct MenuItem: Codable {
            let value: String
            let onClick: String
            enum CodingKeys: String, CodingKey {
                case value
                case onClick = "onclick"
                
            }
        }
    }
    

    1.只有一个类型中所有成员都实现了Codable 那么这个类型就自动满足Codable的要求
    2.如果Json中的key和类型中的变量名不一致 要在对应类中声明CodingKeys枚举,并用合适的键值覆盖对应的默认值

    let data = jsonString.data(using: .utf8)!
    do {
        let obj = try JSONDecoder().decode(Obj.self, from: data)
        let value = obj.menu.popup.menuItem[0].value
        print(value)
    } catch {
        print("出错啦:\(error)")
    }
    

    NSNull

    NSNull 会默默的被通过Optional Binding被转换为nil 避免被执行

    // 假设 jsonValue 是从一个 JSON 中取出的 NSNull
    let jsonValue: AnyObject = NSNull()
    if let string = jsonValue as? String {
        print(string.hasPrefix("a"))
    } else {
        print("不能解析")
    }
    // 输出: // 不能解析
    

    属性访问控制

    当希望读取到这个类的属性 但是要保证类型的封装和安全 只能在类型内部对其进行改变或者设置

     class MyClass {
        private(set) var name: String?
    }
    

    泛型扩展

    extension Array {
        var random: Element? {
            return self.count != 0 ? self[Int(arc4random_uniform(UInt32(self.count)))] :nil
        }
    }
    let languages = ["Swift","ObjC","C++","Java"]
    languages.random!
    // 随机输出是这四个字符串中的某个
    let ranks = [1,2,3,4]
    ranks.random!
    // 随机输出是这四个数字中的某个
    

    尾递归

    func sum(_ n: UInt) -> UInt {
        if n == 0 {
            return 0
        }
        return n + sum(n - 1)
    }
    sum(4) // 10
    sum(100) // 5050
    

    当输入的数字过大时 就会出现错误 是因为每次对于sum的递归调用都需要在调用栈上保存当前状态,否则无法计算最后的值,当n足够大,调用栈足够深的时候,栈空间被耗尽而导致错误 栈溢出

    使用尾递归的方式解决该问题 尾递归就是让函数里的最后一个动作是一个函数调用的形式,这个调用的返回值将直接被当前函数返回 从而避免在栈上保存状态 这样就是更新最后的栈帧 不是新建一个 来避免栈溢出的发生

    func tailSum(_ n: UInt) -> UInt {
        func sumInternal(_ n: UInt, current: UInt) -> UInt {
            if n == 0 {
                return current
            } else {
                return sumInternal(n - 1, current: current + n)
            }
        }
        return sumInternal(n, current: 0)
    }
    tailSum(1000000)
    

    由于默认Debug模式下Swift编译器不会对尾递归进行优化 可以改为Relese模式 再运行

    相关文章

      网友评论

          本文标题:Swift小点(3)

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