Forked from tylermilner/Slow_Compiling_Swift_Code.swift
Last active
May 24, 2021 10:55
-
-
Save Changzw/055f88454bbafcf0e1d3eed9a7468a70 to your computer and use it in GitHub Desktop.
Code samples of common sources of slowdowns for the Swift 2/3 compiler.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // The code snippets below showcase common "problem code" that can take a long time to compile. | |
| // These examples were primarily observed in Swift 2/3 and may no longer be relevant in Swift 4 or higher. | |
| // | |
| /// 1. Array concatenation | |
| // Observed by Robert Gummesson - https://medium.com/@RobertGummesson/regarding-swift-build-time-optimizations-fc92cdd91e31#c75c | |
| // Joining two arrays together with the '+' operator can be expensive to compile. | |
| let someArray = ["a", "b"] + ["c", "d"] | |
| /// 2. Extraneous casting | |
| // Observed by Robert Gummesson - https://medium.com/@RobertGummesson/regarding-swift-build-time-optimizations-fc92cdd91e31#60bf | |
| // Avoid casting values to their own type when doing calculations. | |
| // In the example below, the 'hour', 'hourDelta', 'minute', and 'minuteDelta' are already of type CGFloat. | |
| // Build time: 3431.7ms | |
| return CGFloat(M_PI) * (CGFloat((hour + hourDelta + CGFloat(minute + minuteDelta) / 60) * 5) - 15) * unit / 180 | |
| // Build time: 3.0ms | |
| return CGFloat(M_PI) * ((hour + hourDelta + (minute + minuteDelta) / 60) * 5 - 15) * unit / 180 | |
| /// 3. round() | |
| // Observed by Robert Gummesson - https://medium.com/@RobertGummesson/regarding-swift-build-time-optimizations-fc92cdd91e31#9b8b | |
| // Avoid rounding if it's not necessary for your calculations. | |
| // Build time: 1433.7ms | |
| let expansion = a - b - c + round(d * 0.66) + e | |
| // Build time: 34.7ms | |
| let expansion = a - b - c + d * 0.66 + e | |
| /// 4. Lazy properties | |
| // Observed by Robert Gummesson - https://medium.com/swift-programming/swift-build-time-optimizations-part-2-37b0a7514cbe#beb8 | |
| // Assigning the value of a lazy property to a private function that builds it instead of an in-line closure can improve compilation times. | |
| // Before | |
| private(set) lazy var chartViewColors: [UIColor] = [ | |
| self.chartColor, | |
| UIColor(red: 86/255, green: 84/255, blue: 124/255, alpha: 1), | |
| UIColor(red: 80/255, green: 88/255, blue: 92/255, alpha: 1), | |
| UIColor(red: 126/255, green: 191/255, blue: 189/255, alpha: 1), | |
| UIColor(red: 161/255, green: 77/255, blue: 63/255, alpha: 1), | |
| UIColor(red: 235/255, green: 185/255, blue: 120/255, alpha: 1), | |
| UIColor(red: 100/255, green: 126/255, blue: 159/255, alpha: 1), | |
| UIColor(red: 160/255, green: 209/255, blue: 109/255, alpha: 1), | |
| self.backgroundGradientView.upperColor | |
| ] | |
| // After | |
| // Cumulative build time: 56.3ms | |
| private(set) lazy var chartViewColors: [UIColor] = self.createChartViewColors() | |
| // Build time: 6.2ms | |
| private func createChartViewColors() -> [UIColor] { | |
| return [ | |
| chartColor, | |
| UIColor(red: 86/255, green: 84/255, blue: 124/255, alpha: 1), | |
| UIColor(red: 80/255, green: 88/255, blue: 92/255, alpha: 1), | |
| UIColor(red: 126/255, green: 191/255, blue: 189/255, alpha: 1), | |
| UIColor(red: 161/255, green: 77/255, blue: 63/255, alpha: 1), | |
| UIColor(red: 235/255, green: 185/255, blue: 120/255, alpha: 1), | |
| UIColor(red: 100/255, green: 126/255, blue: 159/255, alpha: 1), | |
| UIColor(red: 160/255, green: 209/255, blue: 109/255, alpha: 1), | |
| backgroundGradientView.upperColor | |
| ] | |
| } | |
| /// 5. In-line computation | |
| // Observed by Dejan Atanasov - https://hackernoon.com/speed-up-swift-compile-time-6f62d86f85e6#315a | |
| // Avoid doing computations directly in an 'if' statement. | |
| // Before | |
| if number == 60 * 60 { | |
| // ... | |
| } | |
| // After | |
| let number: Double = 60 * 60 | |
| if number == 3600 { | |
| // ... | |
| } | |
| // 任何运算式,赋值语句都要加上类型!!! 运算式包括,1,2,3位运算 | |
| /// 6. String concatenation | |
| // Observed by Dejan Atanasov - https://hackernoon.com/speed-up-swift-compile-time-6f62d86f85e6#315a | |
| // Favor string interpolation over concatenation (using the '+' operator). | |
| // Before | |
| let url = "https://google.com/" + "path/" + "anotherpath" | |
| // After | |
| let url = "https://google.com/\("path")/\("anotherpath")" | |
| /// 7. Ternary operator | |
| // Observed by Robert Gummesson - https://medium.com/swift-programming/swift-build-time-optimizations-part-2-37b0a7514cbe#56ea | |
| // Favoring 'if'/'else' over the ternary operator could improve compile times. | |
| // Before | |
| return someValue > 3 ? someValue - 2 : someValue + 2 | |
| // After | |
| if someValue > 3 { | |
| return someValue - 2 | |
| } else { | |
| return someValue + 2 | |
| } | |
| /// 8. Nil-coalescing operator | |
| // Observed by Robert Gummesson - https://medium.com/@RobertGummesson/regarding-swift-build-time-optimizations-fc92cdd91e31#ec7d | |
| // Favoring mutable state and multiple 'if'/'else' statements could improve compile times. | |
| // Before | |
| return CGSize(width: size.width + (rightView?.bounds.width ?? 0) + (leftView?.bounds.width ?? 0) + 22, height: bounds.height) | |
| // After | |
| var padding: CGFloat = 22 | |
| if let rightView = rightView { | |
| padding += rightView.bounds.width | |
| } | |
| if let leftView = leftView { | |
| padding += leftView.bounds.width | |
| } | |
| return CGSize(width: size.width + padding, height: bounds.height) | |
| /// 9. Function type inference | |
| // Observed by Paul Hudson - https://www.hackingwithswift.com/articles/11/how-to-make-swift-compile-faster | |
| // Using a similar function that takes a more generic argument can improve compile times. | |
| // In the example below, a String initializer that takes an "Any" type is used instead of an operator that takes an "Int" type. | |
| // Compile times can also be further reduced by splitting up the complex expression. | |
| // Before | |
| let sum = [1, 2, 3].map { String($0) }.flatMap { Int($0) }.reduce(0, +) | |
| // After | |
| let sum = [1, 2, 3].map { String(describing: $0) }.flatMap { Int($0) }.reduce(0, +) | |
| // After (splitting up expression) | |
| let numbers = [1, 2, 3] | |
| let stringNumbers = numbers.map { String($0) } | |
| let intNumbers = stringNumbers.flatMap { Int($0) } | |
| let sum = intNumbers.reduce(0, +) | |
| /// 10. Collection type inference | |
| // Observed by Dajan Atanasov - https://hackernoon.com/speed-up-swift-compile-time-6f62d86f85e6#315a | |
| // Manually adding type information to your arrays/dictionaries can improve compile times. | |
| // Before | |
| let someArray = ["a", "b", "c"] | |
| // After | |
| let someArray: [String] = ["a", "b", "c"] | |
| // 任何运算式,赋值语句都要加上类型!!! 运算式包括,1,2,3位运算 | |
| var prePadding = 0 | |
| //After | |
| var prePadding: Int = 0 | |
| let newContents = Language.current == .zh ? contents : contents.reversed() | |
| let newContents: [GlobalBannerContent] = Language.current == .zh ? contents : contents.reversed() | |
| let color1 = colors?.safeObject(at: 0) ?? "" | |
| let color1: String = colors?.safeObject(at: 0) ?? "" | |
| self.rank1stScoreLabel.text = item.score.map{ | |
| $0 >= 1_00_00 ? | |
| String(format: "%.2f", Float($0) / 1_00_00.0) + "w" : | |
| String($0) | |
| } | |
| // 加上语义明确的括号 | |
| let items: [LiveGiftItem] | |
| items = giftQueryByRoomRsp?.commonGifts?.compactMap { $0 } | |
| .filter { $0.sort ?? 0 > 0 && $0.id != 68 } | |
| .sorted(by: { $0.sort ?? 0 > $1.sort ?? 0 }) ?? [] | |
| items = giftQueryByRoomRsp?.commonGifts?.compactMap { $0 } | |
| .filter { $0.sort ?? 0 > 0 && $0.id != 68 } | |
| .sorted(by: { $0.sort ?? 0 > $1.sort ?? 0 }) ?? [] | |
| // wtf | |
| return radians / CGFloat.pi * 180.0 | |
| return radians / (CGFloat.pi * 180.0) | |
| // attention!!! 编译速度的大坑 | |
| String($0) + "/200" // 影响编译速度 | |
| "\($0)/200" //p.s. 这个会影响运行时速度 | |
| // wtf | |
| let refBounds = bounds.insetBy(dx: -tolerance, dy: -tolerance) | |
| let refBounds: CGRect = bounds.insetBy(dx: -tolerance, dy: -tolerance) | |
| // | |
| var giftSectionViewModels = [GiftSectionViewModel]() | |
| var giftSectionViewModels: [GiftSectionViewModel] = [] | |
| // | |
| row = CGFloat((viewModel.dataSource.count - 1) / Int(Self.column) + 1) | |
| let v: Int = (viewModel.dataSource.count - 1) / Int(Self.column) + 1 | |
| row = CGFloat(v) | |
| // | |
| let x = delegate?.collectionView?(cv, layout: self, insetForSectionAt: section).left ?? sectionInset.left | |
| let x: CGFloat = delegate?.collectionView?(cv, layout: self, insetForSectionAt: section).left ?? sectionInset.left | |
| // | |
| if danmakuView.queuingCount + danmakuView.animatingCount == 0 { | |
| superview?.isHidden = true | |
| } | |
| let v = danmakuView.queuingCount + danmakuView.animatingCount | |
| if v == 0 { | |
| superview?.isHidden = true | |
| } | |
| // | |
| levelUpExpLabel.text = "距离下一等级还差%d{# Android #}".localized(with: [(data?.nextExp ?? 0) - (data?.curExp ?? 0)]) | |
| let exp: Int | |
| if let n = data?.nextExp, | |
| let c = data?.curExp { | |
| exp = n - c | |
| }else { | |
| exp = 0 | |
| } | |
| levelUpExpLabel.text = "距离下一等级还差%d{# Android #}".localized(with: [exp]) | |
| // | |
| guard let URLStrings = self.allGiftsItems?.compactMap { $0.mp4s?.compactMap { $0 } }.flatMap { $0 }.filter({ $0.count > 0 }) else { return } | |
| let items = allGiftsItems? | |
| .compactMap { $0.mp4s?.compactMap { $0 } } | |
| .flatMap { $0 } | |
| .filter{ $0.count > 0 } | |
| guard let URLStrings = items else { return } | |
| // | |
| statusView.updateUI(with: room.redpacketArray?.compactMap { $0 } ?? [], status: room.callStatus ?? .none) | |
| let items: [RoomRedpacketItem] = room.redpacketArray?.compactMap { $0 } ?? [] | |
| statusView.updateUI(with: items, status: room.callStatus ?? .none) | |
| // | |
| vm_.realTimeDataUpdate | |
| .compactMap{ $0.income } | |
| .compactMap{ String($0) } | |
| .bind {[weak self] (v) in | |
| self?.incomeView?.income = v | |
| } | |
| .disposed(by: bag) | |
| let sig: Observable<String> = | |
| vm_.realTimeDataUpdate | |
| .compactMap{ $0.income } | |
| .compactMap{ String($0) } | |
| sig | |
| .bind {[weak self] (v) in | |
| self?.incomeView?.income = v | |
| } | |
| .disposed(by: bag) | |
| // 4 部分 | |
| // -----0 | |
| mk.width.equalTo(min(viewModel.items | |
| .map(\.title) | |
| .map{ $0.width(for: UIFont.UKIJQara(14)) + 20 } | |
| .reduce(0, +) + 10, UIScreen.main.bounds.width)) | |
| // -----1 | |
| let length: CGFloat = viewModel.items | |
| .map(\.title) | |
| .map{ $0.width(for: UIFont.UKIJQara(14)) + 20 } | |
| .reduce(0, +) + 10 | |
| mk.width.equalTo(min(length, UIScreen.main.bounds.width)) | |
| // -----2 | |
| let length: CGFloat = viewModel.items | |
| .map(\.title) | |
| .map{ $0.width(for: UIFont.UKIJQara(14)) + 20 } | |
| .reduce(0, +) | |
| let lengthBy10 = length + 10 | |
| mk.width.equalTo(min(lengthBy10, UIScreen.main.bounds.width)) | |
| // -----3 | |
| let length: CGFloat = viewModel.items | |
| .map(\.title) | |
| .map{ | |
| let w = $0.width(for: UIFont.UKIJQara(14)) | |
| return w + 20 | |
| } | |
| .reduce(0, +) | |
| let lengthBy10 = length + 10 | |
| mk.width.equalTo(min(lengthBy10, UIScreen.main.bounds.width)) | |
| // 1000+ | |
| let itemSize = (UIScreen.main.bounds.size.width - CGFloat(15 * 2 + 10 * 3)) / CGFloat(4) | |
| let itemSize = (UIScreen.main.bounds.size.width - 60/*15 * 2 + 10 * 3*/) / 4 | |
| // | |
| take = Double((item.startTime ?? 0) - Int(Date().timeIntervalSince1970)) * 1000.0 | |
| let start: Int = item.startTime ?? 0 | |
| take = Double(start - Int(Date().timeIntervalSince1970)) * 1000.0 | |
| // 1000+ms | |
| let customViewY = view.frame.height - view.safeAreaInsets.top - view.safeAreaInsets.bottom - buttonWith - 36 | |
| let customViewY: CGFloat = view.frame.height - view.safeAreaInsets.top - view.safeAreaInsets.bottom - buttonWith - 36 | |
| /* 总结 | |
| 1. 赋值时,添加值类型,在1,2,3位运算符号中都会提高编译速度 | |
| 2. 函数传参,if 判断,三位运算,?? 运算 都不要有赋值运算过程,or 函数式代码 | |
| 3. | |
| */ | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment