Swift 4 遷移踩坑

切一斤桃花賣酒錢發表於2019-03-04

文件

  1. private 屬性作用域擴大到 extension , 防止 fileprivate 的濫用
  2. 可以把型別和協議用 & 組合在一起作為一個型別使用,優化程式碼結構
  3. Associated Type 可以追加 Where 約束語句
  4. keyPath:

    Swift 3

    let barKeyPath = #keyPath(Foo.bar)
    var bar = foo.value(forKeyPath: barKeyPath)
    foo.setValue("BAR", forKeyPath: barKeyPath)複製程式碼

    Swift 4

    let barKeyPath = Foo.bar
     var bar = foo[keyPath: barKeyPath]
     foo[keyPath: barKeyPath] = "BAR"複製程式碼

    swift 4: 更安全,控制 value 的 anyObject 型別,並且不需要類繼承 NSObject

  1. 下標支援泛型
  2. 以及一些系統優化: unicode count 計算,字串處理速度
  3. String.Charactor.startIndex -> String.startIndex 去掉 charactor 中間屬性,直接取 string 的屬性
  4. String 當做 Collection 來用(即 String 擁有 Collection 的屬性) eg: string.reversed() string.filter string.map …
  5. 多行字串字面量,省去繁瑣換行操作

      let joke = """
         Q: Why does (name) have (n) (character)`s in their name?
         A: I don`t know, why does (name) have (n) (character)`s in their name?
         Q: Because otherwise they`d be called (punchline).
         """複製程式碼
  6. Encoding and Decoding

    讓歸檔更簡單隻能, 繼承 Codeable 協議的物件都可 實現 let encoded = try? JSONEncoder().encode(swift) 將 物件歸檔為Data,相反解檔


看完文件,正式開始

遷移順序

  • 第一步: 自動遷移。按照 Xcode 9 提示,選擇 automatic mergation
    注意:
    (1) 當一個 workSpace 中有多個 target , 優先遷移多個 target,。有錯誤先不要著急改,等自動遷移完成後再一步步改錯,否則改動會導致遷移其他 target 出錯。
    (2) 如果用 cocoapods 管理的第三方庫,自動遷移的時候會提示選擇需要遷移的 framework, 因為 Swift 4.0 是相容 Swift 3.2 的,考慮到有些第三方庫沒有及時遷移到 4.0 ,所以此時可以不勾選第三方庫的遷移選項,僅遷移當前專案即可。

  • 第二步: 更新升級專案 config

  • 第三步: 修改 error, 專案不會一次性顯示所有 error ,每次改完編譯會出新 error

  • 第四步: 最後再修改 warning


Error

  1. 報錯 Ambiguous reference to member `+` + 號表達不明確,將表示式拆分
  2. accesses to 0x7f887f904430, but modification requires exclusive access 可能會有多個原因,如果是 KVO 報此錯誤,是因為 Swift 4 使用了新的 KVO 方法。 參照 Swift 新的 KVO 方法
    或: github 例項

    // MARK: - Property
    
    fileprivate var _observation: NSKeyValueObservation?
    
    //MARK: - Lifecycle
    
    _observation = LCKXMPPActivity.sharedInstance.observe(.status,   options: [.initial, .old]) { (child, change) in
         //
     }複製程式碼

    statusLCKXMPPActivity 中宣告為 @objc dynamic 的屬性

    @objc open dynamic var status: LCKXMPPStatus

    遇到一個很很很奇怪的問題, _observation 物件如果不宣告為全域性的話, observe 方法並不會被 status 的的改變而觸發

  1. 屬性字串 NSAttriburedString

    Swift 3
    
     let attributes = [NSStrikethroughStyleAttributeName : NSUnderlineStyle.styleSingle.rawValue,
     NSForegroundColorAttributeName: UIColor.kTitleColor4] as [String : Any]
    
    Swift 4
    
     let attributes: [NSAttributedStringKey: Any] =     [NSAttributedStringKey.strikethroughStyle: NSUnderlineStyle.styleSingle.rawValue,
     NSAttributedStringKey.foregroundColor: UIColor.kTitleColor4]複製程式碼

    attributedStringkey 統一通過 NSAttributedStringKey 呼叫,並且 NSAttributedString(string: <#T##String#>, attributes: <#T##[NSAttributedStringKey : Any]?#>) 接受的型別是 [NSAttributedStringKey : Any] 型別

warning

  1. swap(&a, &b) –> swapAt(Index:Int, Index: Int)
  2. init(colorLiteralRed:green:blue:alpha:) –> init(red:green:blue:alpha:)
  3. redundant conformance of XXX to protocol YYY 協議宣告重複,檢視當前所繼承的協議是否有重複,或者檢視子類是否又繼承了一遍
  4. The use of Swift 3 @objc inference in Swift 4 mode is deprecated.
    首先在設定裡如圖所示:

    inference.png
    inference.png

    Swift 4 中不再預設[推斷]為 OC 的方法加上 @objc 屬性,所以需要 swift 呼叫 OC 的地方手動加上 objc.
    參見資料: stackoverflow evgenii

  5. Multiple Closures with Trailing Closure Violation: Trailing closure syntax should not be used when passing more than one closure argument. (multiple_closures_with_trailing_closure)

     warning: 
    
     ObjectiveManager.shared.finishObjective(objectiveID: "2", keyResults: [], success: {
           //
         }) { _ in
           //
         }
    
     success:
    
     ObjectiveManager.shared.finishObjective(objectiveID: "2", keyResults: [], success: {
       //
     }, failure: { _ in
       //
     })複製程式碼

    尾隨閉包的問題,參見資料: Apple

  6. Declarations in extensions cannot override yet
    override 使用者新增新方法,但不能修改原方法,所以講 override 的方法不能放在 extension 中. 父方法前加 @objc

  7. This block declaration is not a prototype
    修改 strict prototypes set no 或者 OC 的 block 一個一個慢慢改吧,這裡是混編 OC 的問題。
    參照資料 stackoverflow

  8. 當 OC 呼叫 swift 時報錯 No known class method for selector 所呼叫的方法前加 @objc
  9. `substring(from:)` is deprecated: Please use String slicing subscript with a `partial range from` operator.
    Stringsubstring屬性在 Swift 4 新的實現
    let newStr = str.substring(to: index) -->  let newStr = String(str[..<index])複製程式碼

    如果是某一範圍 str[..<str.index(str.startIndex, offsetBy: 8)]
    參照資料: stackoverflow

  10. tableview height for header & footer 不呼叫, 因為estimatedSectionHeaderHeight 在 iOS 11 不再有預設值。解決方案: 設定 tableview.estimatedSectionHeaderHeight = 0 或者
    實現 viewForFooterInSection 代理返回 nil, footer 同理

有些問題可能忘寫了,以及不清楚的地方請留言討論

持續更新,可以收藏關注先。。。

下一篇 iOS 11 以及 iPhone X 適配(11 已完成, X 還在掙扎中)

最後

寫這篇部落格的時候,並沒有女朋友餵我水果吃 = =