[编程开发] 用纯swift开发iOS是怎么样一种体验?

[复制链接]
alexacn 发表于 2023-10-4 19:20:27|来自:中国 | 显示全部楼层 |阅读模式
题主做了快3年的iOS开发,一直用OC开发项目,从15年就一直在关注swift,但是只用来写demo,没有在公司项目里用过,看网上文章说今年年底会发布5.0版本,想问一下swift现在在企业开发中体验怎样,有没有特别大的坑,还有apple前段时间开源了swift-nio,在这种情况下可不可以入坑swift web开发。
全部回复5 显示全部楼层
稍息立正 发表于 2023-10-4 19:20:47|来自:中国 | 显示全部楼层
前言

代码风格可能是一个有争议的话题,并且在开发人员之间引发一些激烈的讨论。使用工具强制执行一套代码风格规则对于避免一些争论,以及确保在整个项目中保持代码风格的一致性非常有帮助。SwiftLint 可以很容易的整合进 Xcode 项目中,以便在编译时将代码风格冲突标记为警告或者错误。
使用 Xcode 集成 SwiftLint

你可以在 Github上 获得SwiftLint。它可以使用多种方式安装,比如,直接下载 SwiftLint.pkg 包,或者使用HomeBrew命令行。
  1. brew install swiftlint
复制代码
安装 SwiftLint 后,可以通过在主 app target 的Build Phase(构筑阶段)下添加一个Run Phase(运行阶段)的运行脚本,来集成进 Xcode 项目。点击+号按钮,选择"New Run Script Phase",添加下面的脚本。在 silicon Macs (搭载M1芯片)上需要添加export语句,因为HomeBrew的二进制文件默认安装在/opt/homebrew/bin目录之下。
译者注:并不一定在此目录下,具体可以点击这里。
  1. export PATH="$PATH:/opt/homebrew/bin"
  2. if which swiftlint > /dev/null; then
  3.   swiftlint
  4. else
  5.   echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
  6. fi
复制代码



在Xcode添加运行脚本以集成SwiftLint

在 Xcode 添加运行脚本以集成 SwiftLint
<hr/>SwiftLint 的规则冲突

好消息是,新建的 Xcode 项目没有违反 SwiftLint 的默认规则。一旦你知道了 SwiftLint,最好从一开始就立即将其添加到每个项目中。在刚才新建的 iOS App 的Text view后面添加一个空格。现在,编译代码时会生成警告。
  1. struct ContentView: View {
  2.     var body: some View {
  3.         VStack {
  4.             Text("Hello, world!")
  5.             Text("second line")
  6.             Spacer()
  7.         }
  8.     }
  9. }
复制代码
这段代码违反了trailing_whitespace规则,它默认是开启的。
  1. +------------------------------------------+--------+-------------+------------------------+-------------+----------+---------------+
  2. | identifier                               | opt-in | correctable | enabled in your config | kind        | analyzer | configuration |
  3. +------------------------------------------+--------+-------------+------------------------+-------------+----------+---------------+
  4. | trailing_whitespace                      | no     | yes         | yes                    | style       | no       | warning, i... |
复制代码



Swift正在警告在一行之后有一个额外的空格

Swift 正在警告在一行之后有一个额外的空格
<hr/>SwiftLint 的规则

SwiftLint 包含了200多条规则,并且 Swift 社区仍在不间断的贡献更多的规则。查看 SwiftLint 规则的一种方法是在终端中运行swiftlint rules命令(此种方式需要安装swiftlint)。这将会显示规则以及规则的一系列属性,比如是否可选,是否可纠正。
以下是 SwiftLint 0.46.5的默认规则:
  1. swiftlint rules
  2. +------------------------------------------+--------+-------------+------------------------+-------------+----------+---------------+
  3. | identifier                               | opt-in | correctable | enabled in your config | kind        | analyzer | configuration |
  4. +------------------------------------------+--------+-------------+------------------------+-------------+----------+---------------+
  5. | anonymous_argument_in_multiline_closure  | yes    | no          | no                     | idiomatic   | no       | warning       |
  6. | anyobject_protocol                       | yes    | yes         | no                     | lint        | no       | warning       |
  7. | array_init                               | yes    | no          | no                     | lint        | no       | warning       |
  8. | attributes                               | yes    | no          | no                     | style       | no       | warning, a... |
  9. | balanced_xctest_lifecycle                | yes    | no          | no                     | lint        | no       | warning       |
  10. | block_based_kvo                          | no     | no          | yes                    | idiomatic   | no       | warning       |
  11. | capture_variable                         | yes    | no          | no                     | lint        | yes      | warning       |
  12. | class_delegate_protocol                  | no     | no          | yes                    | lint        | no       | warning       |
  13. | closing_brace                            | no     | yes         | yes                    | style       | no       | warning       |
  14. | closure_body_length                      | yes    | no          | no                     | metrics     | no       | warning: 2... |
  15. | closure_end_indentation                  | yes    | yes         | no                     | style       | no       | warning       |
  16. | closure_parameter_position               | no     | no          | yes                    | style       | no       | warning       |
  17. | closure_spacing                          | yes    | yes         | no                     | style       | no       | warning       |
  18. | collection_alignment                     | yes    | no          | no                     | style       | no       | warning, a... |
  19. | colon                                    | no     | yes         | yes                    | style       | no       | warning, f... |
  20. | comma                                    | no     | yes         | yes                    | style       | no       | warning       |
  21. | comment_spacing                          | no     | yes         | yes                    | lint        | no       | warning       |
  22. | compiler_protocol_init                   | no     | no          | yes                    | lint        | no       | warning       |
  23. | computed_accessors_order                 | no     | no          | yes                    | style       | no       | warning, o... |
  24. | conditional_returns_on_newline           | yes    | no          | no                     | style       | no       | warning, i... |
  25. | contains_over_filter_count               | yes    | no          | no                     | performance | no       | warning       |
  26. | contains_over_filter_is_empty            | yes    | no          | no                     | performance | no       | warning       |
  27. | contains_over_first_not_nil              | yes    | no          | no                     | performance | no       | warning       |
  28. | contains_over_range_nil_comparison       | yes    | no          | no                     | performance | no       | warning       |
  29. | control_statement                        | no     | yes         | yes                    | style       | no       | warning       |
  30. | convenience_type                         | yes    | no          | no                     | idiomatic   | no       | warning       |
  31. | custom_rules                             | no     | no          | no                     | style       | no       | user-defin... |
  32. | cyclomatic_complexity                    | no     | no          | yes                    | metrics     | no       | warning: 1... |
  33. | deployment_target                        | no     | no          | yes                    | lint        | no       | warning, i... |
  34. | discarded_notification_center_observer   | yes    | no          | no                     | lint        | no       | warning       |
  35. | discouraged_assert                       | yes    | no          | no                     | idiomatic   | no       | warning       |
  36. | discouraged_direct_init                  | no     | no          | yes                    | lint        | no       | warning, t... |
  37. | discouraged_none_name                    | yes    | no          | no                     | idiomatic   | no       | warning       |
  38. | discouraged_object_literal               | yes    | no          | no                     | idiomatic   | no       | warning, i... |
  39. | discouraged_optional_boolean             | yes    | no          | no                     | idiomatic   | no       | warning       |
  40. | discouraged_optional_collection          | yes    | no          | no                     | idiomatic   | no       | warning       |
  41. | duplicate_enum_cases                     | no     | no          | yes                    | lint        | no       | error         |
  42. | duplicate_imports                        | no     | no          | yes                    | idiomatic   | no       | warning       |
  43. | duplicated_key_in_dictionary_literal     | no     | no          | yes                    | lint        | no       | warning       |
  44. | dynamic_inline                           | no     | no          | yes                    | lint        | no       | error         |
  45. | empty_collection_literal                 | yes    | no          | no                     | performance | no       | warning       |
  46. | empty_count                              | yes    | no          | no                     | performance | no       | error, onl... |
  47. | empty_enum_arguments                     | no     | yes         | yes                    | style       | no       | warning       |
  48. | empty_parameters                         | no     | yes         | yes                    | style       | no       | warning       |
  49. | empty_parentheses_with_trailing_closure  | no     | yes         | yes                    | style       | no       | warning       |
  50. | empty_string                             | yes    | no          | no                     | performance | no       | warning       |
  51. | empty_xctest_method                      | yes    | no          | no                     | lint        | no       | warning       |
  52. | enum_case_associated_values_count        | yes    | no          | no                     | metrics     | no       | warning: 5... |
  53. | expiring_todo                            | yes    | no          | no                     | lint        | no       | (approachi... |
  54. | explicit_acl                             | yes    | no          | no                     | idiomatic   | no       | warning       |
  55. | explicit_enum_raw_value                  | yes    | no          | no                     | idiomatic   | no       | warning       |
  56. | explicit_init                            | yes    | yes         | no                     | idiomatic   | no       | warning       |
  57. | explicit_self                            | yes    | yes         | no                     | style       | yes      | warning       |
  58. | explicit_top_level_acl                   | yes    | no          | no                     | idiomatic   | no       | warning       |
  59. | explicit_type_interface                  | yes    | no          | no                     | idiomatic   | no       | warning, e... |
  60. | extension_access_modifier                | yes    | no          | no                     | idiomatic   | no       | warning       |
  61. | fallthrough                              | yes    | no          | no                     | idiomatic   | no       | warning       |
  62. | fatal_error_message                      | yes    | no          | no                     | idiomatic   | no       | warning       |
  63. | file_header                              | yes    | no          | no                     | style       | no       | warning, r... |
  64. | file_length                              | no     | no          | yes                    | metrics     | no       | warning: 4... |
  65. | file_name                                | yes    | no          | no                     | idiomatic   | no       | (severity)... |
  66. | file_name_no_space                       | yes    | no          | no                     | idiomatic   | no       | (severity)... |
  67. | file_types_order                         | yes    | no          | no                     | style       | no       | warning, o... |
  68. | first_where                              | yes    | no          | no                     | performance | no       | warning       |
  69. | flatmap_over_map_reduce                  | yes    | no          | no                     | performance | no       | warning       |
  70. | for_where                                | no     | no          | yes                    | idiomatic   | no       | warning       |
  71. | force_cast                               | no     | no          | yes                    | idiomatic   | no       | error         |
  72. | force_try                                | no     | no          | yes                    | idiomatic   | no       | error         |
  73. | force_unwrapping                         | yes    | no          | no                     | idiomatic   | no       | warning       |
  74. | function_body_length                     | no     | no          | yes                    | metrics     | no       | warning: 4... |
  75. | function_default_parameter_at_end        | yes    | no          | no                     | idiomatic   | no       | warning       |
  76. | function_parameter_count                 | no     | no          | yes                    | metrics     | no       | warning: 5... |
  77. | generic_type_name                        | no     | no          | yes                    | idiomatic   | no       | (min_lengt... |
  78. | ibinspectable_in_extension               | yes    | no          | no                     | lint        | no       | warning       |
  79. | identical_operands                       | yes    | no          | no                     | lint        | no       | warning       |
  80. | identifier_name                          | no     | no          | yes                    | style       | no       | (min_lengt... |
  81. | implicit_getter                          | no     | no          | yes                    | style       | no       | warning       |
  82. | implicit_return                          | yes    | yes         | no                     | style       | no       | warning, i... |
  83. | implicitly_unwrapped_optional            | yes    | no          | no                     | idiomatic   | no       | warning, m... |
  84. | inclusive_language                       | no     | no          | yes                    | style       | no       | warning, a... |
  85. | indentation_width                        | yes    | no          | no                     | style       | no       | severity: ... |
  86. | inert_defer                              | no     | no          | yes                    | lint        | no       | warning       |
  87. | is_disjoint                              | no     | no          | yes                    | idiomatic   | no       | warning       |
  88. | joined_default_parameter                 | yes    | yes         | no                     | idiomatic   | no       | warning       |
  89. | large_tuple                              | no     | no          | yes                    | metrics     | no       | warning: 2... |
  90. | last_where                               | yes    | no          | no                     | performance | no       | warning       |
  91. | leading_whitespace                       | no     | yes         | yes                    | style       | no       | warning       |
  92. | legacy_cggeometry_functions              | no     | yes         | yes                    | idiomatic   | no       | warning       |
  93. | legacy_constant                          | no     | yes         | yes                    | idiomatic   | no       | warning       |
  94. | legacy_constructor                       | no     | yes         | yes                    | idiomatic   | no       | warning       |
  95. | legacy_hashing                           | no     | no          | yes                    | idiomatic   | no       | warning       |
  96. | legacy_multiple                          | yes    | no          | no                     | idiomatic   | no       | warning       |
  97. | legacy_nsgeometry_functions              | no     | yes         | yes                    | idiomatic   | no       | warning       |
  98. | legacy_objc_type                         | yes    | no          | no                     | idiomatic   | no       | warning       |
  99. | legacy_random                            | yes    | no          | no                     | idiomatic   | no       | warning       |
  100. | let_var_whitespace                       | yes    | no          | no                     | style       | no       | warning       |
  101. | line_length                              | no     | no          | yes                    | metrics     | no       | warning: 1... |
  102. | literal_expression_end_indentation       | yes    | yes         | no                     | style       | no       | warning       |
  103. | lower_acl_than_parent                    | yes    | no          | no                     | lint        | no       | warning       |
  104. | mark                                     | no     | yes         | yes                    | lint        | no       | warning       |
  105. | missing_docs                             | yes    | no          | no                     | lint        | no       | warning: o... |
  106. | modifier_order                           | yes    | yes         | no                     | style       | no       | warning, p... |
  107. | multiline_arguments                      | yes    | no          | no                     | style       | no       | warning, f... |
  108. | multiline_arguments_brackets             | yes    | no          | no                     | style       | no       | warning       |
  109. | multiline_function_chains                | yes    | no          | no                     | style       | no       | warning       |
  110. | multiline_literal_brackets               | yes    | no          | no                     | style       | no       | warning       |
  111. | multiline_parameters                     | yes    | no          | no                     | style       | no       | warning, a... |
  112. | multiline_parameters_brackets            | yes    | no          | no                     | style       | no       | warning       |
  113. | multiple_closures_with_trailing_closure  | no     | no          | yes                    | style       | no       | warning       |
  114. | nesting                                  | no     | no          | yes                    | metrics     | no       | (type_leve... |
  115. | nimble_operator                          | yes    | yes         | no                     | idiomatic   | no       | warning       |
  116. | no_extension_access_modifier             | yes    | no          | no                     | idiomatic   | no       | error         |
  117. | no_fallthrough_only                      | no     | no          | yes                    | idiomatic   | no       | warning       |
  118. | no_grouping_extension                    | yes    | no          | no                     | idiomatic   | no       | warning       |
  119. | no_space_in_method_call                  | no     | yes         | yes                    | style       | no       | warning       |
  120. | notification_center_detachment           | no     | no          | yes                    | lint        | no       | warning       |
  121. | nslocalizedstring_key                    | yes    | no          | no                     | lint        | no       | warning       |
  122. | nslocalizedstring_require_bundle         | yes    | no          | no                     | lint        | no       | warning       |
  123. | nsobject_prefer_isequal                  | no     | no          | yes                    | lint        | no       | warning       |
  124. | number_separator                         | yes    | yes         | no                     | style       | no       | warning, m... |
  125. | object_literal                           | yes    | no          | no                     | idiomatic   | no       | warning, i... |
  126. | opening_brace                            | no     | yes         | yes                    | style       | no       | warning, a... |
  127. | operator_usage_whitespace                | yes    | yes         | no                     | style       | no       | warning, l... |
  128. | operator_whitespace                      | no     | no          | yes                    | style       | no       | warning       |
  129. | optional_enum_case_matching              | yes    | yes         | no                     | style       | no       | warning       |
  130. | orphaned_doc_comment                     | no     | no          | yes                    | lint        | no       | warning       |
  131. | overridden_super_call                    | yes    | no          | no                     | lint        | no       | warning, e... |
  132. | override_in_extension                    | yes    | no          | no                     | lint        | no       | warning       |
  133. | pattern_matching_keywords                | yes    | no          | no                     | idiomatic   | no       | warning       |
  134. | prefer_nimble                            | yes    | no          | no                     | idiomatic   | no       | warning       |
  135. | prefer_self_in_static_references         | yes    | yes         | no                     | style       | no       | N/A           |
  136. | prefer_self_type_over_type_of_self       | yes    | yes         | no                     | style       | no       | warning       |
  137. | prefer_zero_over_explicit_init           | yes    | yes         | no                     | idiomatic   | no       | warning       |
  138. | prefixed_toplevel_constant               | yes    | no          | no                     | style       | no       | warning, o... |
  139. | private_action                           | yes    | no          | no                     | lint        | no       | warning       |
  140. | private_outlet                           | yes    | no          | no                     | lint        | no       | warning, a... |
  141. | private_over_fileprivate                 | no     | yes         | yes                    | idiomatic   | no       | warning, v... |
  142. | private_subject                          | yes    | no          | no                     | lint        | no       | warning       |
  143. | private_unit_test                        | no     | no          | yes                    | lint        | no       | warning: X... |
  144. | prohibited_interface_builder             | yes    | no          | no                     | lint        | no       | warning       |
  145. | prohibited_super_call                    | yes    | no          | no                     | lint        | no       | warning, e... |
  146. | protocol_property_accessors_order        | no     | yes         | yes                    | style       | no       | warning       |
  147. | quick_discouraged_call                   | yes    | no          | no                     | lint        | no       | warning       |
  148. | quick_discouraged_focused_test           | yes    | no          | no                     | lint        | no       | warning       |
  149. | quick_discouraged_pending_test           | yes    | no          | no                     | lint        | no       | warning       |
  150. | raw_value_for_camel_cased_codable_enum   | yes    | no          | no                     | lint        | no       | warning       |
  151. | reduce_boolean                           | no     | no          | yes                    | performance | no       | warning       |
  152. | reduce_into                              | yes    | no          | no                     | performance | no       | warning       |
  153. | redundant_discardable_let                | no     | yes         | yes                    | style       | no       | warning       |
  154. | redundant_nil_coalescing                 | yes    | yes         | no                     | idiomatic   | no       | warning       |
  155. | redundant_objc_attribute                 | no     | yes         | yes                    | idiomatic   | no       | warning       |
  156. | redundant_optional_initialization        | no     | yes         | yes                    | idiomatic   | no       | warning       |
  157. | redundant_set_access_control             | no     | no          | yes                    | idiomatic   | no       | warning       |
  158. | redundant_string_enum_value              | no     | no          | yes                    | idiomatic   | no       | warning       |
  159. | redundant_type_annotation                | yes    | yes         | no                     | idiomatic   | no       | warning       |
  160. | redundant_void_return                    | no     | yes         | yes                    | idiomatic   | no       | warning       |
  161. | required_deinit                          | yes    | no          | no                     | lint        | no       | warning       |
  162. | required_enum_case                       | yes    | no          | no                     | lint        | no       | No protoco... |
  163. | return_arrow_whitespace                  | no     | yes         | yes                    | style       | no       | warning       |
  164. | self_in_property_initialization          | no     | no          | yes                    | lint        | no       | warning       |
  165. | shorthand_operator                       | no     | no          | yes                    | style       | no       | error         |
  166. | single_test_class                        | yes    | no          | no                     | style       | no       | warning       |
  167. | sorted_first_last                        | yes    | no          | no                     | performance | no       | warning       |
  168. | sorted_imports                           | yes    | yes         | no                     | style       | no       | warning       |
  169. | statement_position                       | no     | yes         | yes                    | style       | no       | (statement... |
  170. | static_operator                          | yes    | no          | no                     | idiomatic   | no       | warning       |
  171. | strict_fileprivate                       | yes    | no          | no                     | idiomatic   | no       | warning       |
  172. | strong_iboutlet                          | yes    | yes         | no                     | lint        | no       | warning       |
  173. | superfluous_disable_command              | no     | no          | yes                    | lint        | no       | warning       |
  174. | switch_case_alignment                    | no     | no          | yes                    | style       | no       | warning, i... |
  175. | switch_case_on_newline                   | yes    | no          | no                     | style       | no       | warning       |
  176. | syntactic_sugar                          | no     | yes         | yes                    | idiomatic   | no       | warning       |
  177. | test_case_accessibility                  | yes    | yes         | no                     | lint        | no       | warning, a... |
  178. | todo                                     | no     | no          | yes                    | lint        | no       | warning       |
  179. | toggle_bool                              | yes    | yes         | no                     | idiomatic   | no       | warning       |
  180. | trailing_closure                         | yes    | no          | no                     | style       | no       | warning, o... |
  181. | trailing_comma                           | no     | yes         | yes                    | style       | no       | warning, m... |
  182. | trailing_newline                         | no     | yes         | yes                    | style       | no       | warning       |
  183. | trailing_semicolon                       | no     | yes         | yes                    | idiomatic   | no       | warning       |
  184. | trailing_whitespace                      | no     | yes         | yes                    | style       | no       | warning, i... |
  185. | type_body_length                         | no     | no          | yes                    | metrics     | no       | warning: 2... |
  186. | type_contents_order                      | yes    | no          | no                     | style       | no       | warning, o... |
  187. | type_name                                | no     | no          | yes                    | idiomatic   | no       | (min_lengt... |
  188. | unavailable_function                     | yes    | no          | no                     | idiomatic   | no       | warning       |
  189. | unneeded_break_in_switch                 | no     | no          | yes                    | idiomatic   | no       | warning       |
  190. | unneeded_parentheses_in_closure_argument | yes    | yes         | no                     | style       | no       | warning       |
  191. | unowned_variable_capture                 | yes    | no          | no                     | lint        | no       | warning       |
  192. | untyped_error_in_catch                   | yes    | yes         | no                     | idiomatic   | no       | warning       |
  193. | unused_capture_list                      | no     | no          | yes                    | lint        | no       | warning       |
  194. | unused_closure_parameter                 | no     | yes         | yes                    | lint        | no       | warning       |
  195. | unused_control_flow_label                | no     | yes         | yes                    | lint        | no       | warning       |
  196. | unused_declaration                       | yes    | no          | no                     | lint        | yes      | severity: ... |
  197. | unused_enumerated                        | no     | no          | yes                    | idiomatic   | no       | warning       |
  198. | unused_import                            | yes    | yes         | no                     | lint        | yes      | severity: ... |
  199. | unused_optional_binding                  | no     | no          | yes                    | style       | no       | warning, i... |
  200. | unused_setter_value                      | no     | no          | yes                    | lint        | no       | warning       |
  201. | valid_ibinspectable                      | no     | no          | yes                    | lint        | no       | warning       |
  202. | vertical_parameter_alignment             | no     | no          | yes                    | style       | no       | warning       |
  203. | vertical_parameter_alignment_on_call     | yes    | no          | no                     | style       | no       | warning       |
  204. | vertical_whitespace                      | no     | yes         | yes                    | style       | no       | warning, m... |
  205. | vertical_whitespace_between_cases        | yes    | yes         | no                     | style       | no       | warning       |
  206. | vertical_whitespace_closing_braces       | yes    | yes         | no                     | style       | no       | N/A           |
  207. | vertical_whitespace_opening_braces       | yes    | yes         | no                     | style       | no       | N/A           |
  208. | void_return                              | no     | yes         | yes                    | style       | no       | warning       |
  209. | weak_delegate                            | yes    | yes         | no                     | lint        | no       | warning       |
  210. | xct_specific_matcher                     | yes    | no          | no                     | idiomatic   | no       | warning       |
  211. | xctfail_message                          | no     | no          | yes                    | idiomatic   | no       | warning       |
  212. | yoda_condition                           | yes    | no          | no                     | lint        | no       | warning       |
  213. +------------------------------------------+--------+-------------+------------------------+-------------+----------+---------------+
复制代码
<hr/>在终端运行 SwiftLint

SwiftLint 可以配置为一个仓库预提交的钩子,用以保证提交代码的风格一致。它也可以在终端中作为命令运行,只需在项目目录中运行swiftlint即可。运行swiftlint --help查看更多选项。
  1. swiftlint --help
  2. OVERVIEW: A tool to enforce Swift style and conventions.
  3. USAGE: swiftlint <subcommand>
  4. OPTIONS:
  5.   --version               Show the version.
  6.   -h, --help              Show help information.
  7. SUBCOMMANDS:
  8.   analyze                 Run analysis rules
  9.   docs                    Open SwiftLint documentation website in the default web browser
  10.   generate-docs           Generates markdown documentation for all rules
  11.   lint (default)          Print lint warnings and errors
  12.   rules                   Display the list of rules and their identifiers
  13.   version                 Display the current version of SwiftLint
  14.   See 'swiftlint help <subcommand>' for detailed help.
复制代码
在(之前新建的项目)HelloSwiftLintApp(目录下)在终端运行swiftlint同样会显示违反了trailing_whitespace规则。
  1. swiftlint
  2. Linting Swift files in current working directory
  3. Linting 'HelloSwiftLintApp.swift' (1/2)
  4. Linting 'ContentView.swift' (2/2)
  5. ...HelloSwiftLint/ContentView.swift:13:1: warning: Trailing Whitespace Violation: Lines should not have trailing whitespace. (trailing_whitespace)
  6. Done linting! Found 1 violation, 0 serious in 2 files.
复制代码
<hr/>自动修复 SwiftLint 冲突

从上面的规则列表可以看出,有一些规则是可以自动修正的。这是直接针对间距规则的,就像上面介绍的额外空格一样。只要可以进行 SwiftLint  分析,就可以进行 SwiftLint 自动修正。
在终端运行swiftlint --fix就会自动修正那些可以被自动修正的 SwiftLint 冲突。
  1. swiftlint --fix
  2. Correcting Swift files in current working directory
  3. Correcting 'HelloSwiftLintApp.swift' (1/2)
  4. Correcting 'ContentView.swift' (2/2)
  5. .../HelloSwiftLint/ContentView.swift:13:1 Corrected Trailing Whitespace
  6. Done inspecting 2 files for auto-correction!
复制代码
或者,可以将自动修复整合到 Xcode 的Build Phase。编辑"Run Script Phase"下的 SwiftLint 脚本。现在,在 Xcode 中编译代码时,添加尾随空格会自动删除。
  1. export PATH="$PATH:/opt/homebrew/bin"
  2. if which swiftlint > /dev/null; then
  3.   swiftlint --fix && swiftlint
  4. else
  5.   echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
  6. fi
复制代码



<hr/>手动修复 SwiftLint 规则冲突

并非所有的规则冲突都可以自动修复。对于 SwiftLint 分析生成的警告以及错误,有很多种处理方式。如果只有一到两个冲突,最好的办法是修复它们,然后继续。
处理 SwiftLint 冲突的一些选项:
  1. 1. 修改代码以符合 SwiftLint 规则
  2. 2. 在代码中添加特例,以忽略特定的规则冲突
  3. 3. 为项目定制 SwiftLint 规则
  4. 4. 忽略这些警告 -- 这不是一个好的选项
复制代码
修复冲突是最好的方法,当 SwiftLint 从项目的一开始就被整合时,这可以很容易的被实现。
下面是我写的示例代码,它遍历了 vertices 数组,创建了一条路径。使用enumerated方法生成了索引以及数据项,使用单个字符n作为变量名会导致编译时错误,仅使用字符作为变量名会导致编译时警告。
  1. for (n, pt) in vertices.enumerated() {
  2.      n == 0 ? path.move(to: pt) : path.addLine(to: pt)
  3. }
复制代码
这些“标识符名称”(identifier-name冲突不能被自动修复。为此类冲突创建一些例外可能会很有诱惑力,但是从长远来看,(此类规则)将有助于代码的可读性以及可维护性。
  1. for (index, point) in vertices.enumerated() {
  2.      index == 0 ? path.move(to: point) : path.addLine(to: point)
  3. }
复制代码
我发现关于enumerated苹果的示例代码存在着同样的问题!




SwiftLint的标识符冲突无法被修复

SwiftLint 的标识符冲突无法被修复
<hr/>一些规则的例外情况

在某些情况下,代码需要与某些外部API或数据源兼容。Open Weather API提供了如Read JSON with codeable in Swift中所描述的 JSON 数据。这些天气数据中main数据段含有一些有下划线的标识符,比如,feels_like 。用于 Swift 解码此 JSON 的结构体必须与 JSON 中的字段名称匹配,由于 SwiftLint 的”***identifier_name***”规则,Swift 代码会产生编译时错误。
天气数据的示例 JSON
  1. {
  2.     "coord": {
  3.         "lon": -122.08,
  4.         "lat": 37.39
  5.     },
  6.     "weather": [
  7.         {
  8.             "id": 800,
  9.             "main": "Clear",
  10.             "description": "clear sky",
  11.             "icon": "01d"
  12.         }
  13.     ],
  14.     "base": "stations",
  15.     "main": {
  16.         "temp": 9.4,
  17.         "feels_like": 8.71,
  18.         "temp_min": 7.22,
  19.         "temp_max": 11.11,
  20.         "pressure": 1023,
  21.         "humidity": 100,
  22.         "sea_level": 100
  23.     },
  24.     "visibility": 16093,
  25.     "wind": {
  26.         "speed": 1.5,
  27.         "deg": 350
  28.     },
  29.     "clouds": {
  30.         "all": 1
  31.     },
  32.     "dt": 1560350645,
  33.     "sys": {
  34.         "type": 1,
  35.         "id": 5122,
  36.         "message": 0.0139,
  37.         "country": "US",
  38.         "sunrise": 1560343627,
  39.         "sunset": 1560396563
  40.     },
  41.     "timezone": -25200,
  42.     "id": 420006353,
  43.     "name": "Mountain View",
  44.     "cod": 200
  45. }
  46. struct WeatherRawData: Codable {
  47.     var name: String
  48.     var timezone: Double
  49.     var weather: [WeatherData]
  50.     var main: MainData
  51.     var wind: WindData
  52.     var clouds: CloudsData
  53.     struct WeatherData: Codable {
  54.         var id: Double
  55.         var main: String
  56.         var description: String
  57.         var icon: String
  58.     }
  59.     struct MainData: Codable {
  60.         var temp: Double
  61.         var feels_like: Double
  62.         var temp_min: Double
  63.         var temp_max: Double
  64.         var pressure: Double
  65.         var humidity: Double
  66.     }
  67.     struct WindData: Codable {
  68.         var speed: Double
  69.         var deg: Double
  70.     }
  71.     struct CloudsData: Codable {
  72.         var all: Double
  73.     }
  74. }
复制代码



不是每个(冲突)都需要被抛出。在这种情况下,可以在出现问题的代码之前简单地禁用 SwiftLint 规则,然后重新启用该规则。显然,如果这些启用/禁用代码片段在代码中到处都是,那就不太好了。这种技术应该谨慎地被使用。如果发现需要在多个位置禁用同一规则,请考虑为整个项目禁用该规则。
  1. struct WeatherRawData: Codable {
  2.     var name: String
  3.     var timezone: Double
  4.     var weather: [WeatherData]
  5.     var main: MainData
  6.     var wind: WindData
  7.     var clouds: CloudsData
  8.     struct WeatherData: Codable {
  9.         var id: Double
  10.         var main: String
  11.         var description: String
  12.         var icon: String
  13.     }
  14.     // swiftlint:disable identifier_name
  15.     struct MainData: Codable {
  16.         var temp: Double
  17.         var feels_like: Double
  18.         var temp_min: Double
  19.         var temp_max: Double
  20.         var pressure: Double
  21.         var humidity: Double
  22.     }
  23.     // swiftlint:enable identifier_name
  24.     struct WindData: Codable {
  25.         var speed: Double
  26.         var deg: Double
  27.     }
  28.     struct CloudsData: Codable {
  29.         var all: Double
  30.     }
  31. }
复制代码



<hr/>不要急于禁用规则

偶尔会有一些 SwiftLint 规则的特例,但是不要急于禁用规则。在上面的例子中,有一种更好的方法,可以使用CodingKeys将 Swift 变量名映射到 JSON 内容。与其注释 SwiftLint 规则,不如使用属性名feelsLike并指定feels_like的可选值来匹配JSON数据。
  1. // swiftlint:disable identifier_name
  2.     struct MainData: Codable {
  3.         var temp: Double
  4.         var feels_like: Double
  5.         var temp_min: Double
  6.         var temp_max: Double
  7.         var pressure: Double
  8.         var humidity: Double
  9.     }
  10.     // swiftlint:enable identifier_name
  11. struct MainData: Codable {
  12.     let temp: Double
  13.     let feelsLike: Double
  14.     let tempMin: Double
  15.     let tempMax: Double
  16.     let pressure: Double
  17.     let humidity: Double
  18.     enum CodingKeys: String, CodingKey {
  19.         case temp
  20.         case feelsLike = "feels_like"
  21.         case tempMin = "temp_min"
  22.         case tempMax = "temp_max"
  23.         case pressure
  24.         case humidity
  25.     }
  26. }
复制代码



使用CodingKeys来映射JSON变量好于禁用SwiftLint规则

使用 CodingKeys 来映射 JSON 变量好于禁用 SwiftLint 规则
<hr/>自定义 SwiftLint 规则

如果将 SwiftLint 添加到显示数百个问题的现有项目中,“修复所有冲突”的方法可能非常困难。在这种情况下,将 SwiftLint 配置添加到项目中可能更合适。这是一个YAML文件,在该文件中可以禁用规则,列出选择开启的规则,或者将规则仅限于此文件中的规则。这样, SwiftLint 就可以无限定制。有关更多详细信息,请参阅SwiftLint配置部分。
警告的一个例子是代码中存在 TODO 注释。SwiftLint 将这些 TODO 标记为警告,以表示这些地方还有未完成的工作。




TODO注释被SwiftLint默认编译成一个警告

TODO 注释被 SwiftLint 默认编译成一个警告
很多时候你既想合并代码时保留这些 TODO,也希望在编译时没有这些警告。可以在每个单独的TODO注释前面加disable/enable,也可以在.swiftlint.yml文件中来禁用整个整个项目的此规则。将下方的.swiftlint.yml文件添加到项目中,会允许项目编译而不生成 TODO 注释警告,其他规则不受影响。
  1. disabled_rules: # rule identifiers to exclude from running
  2.   - todo
  3. struct ContentView: View {
  4.     var body: some View {
  5.         VStack {
  6.             Text("Hello, world!")
  7.             // TODO: Remove this function when done
  8.             let a = 24
  9.             Text("second line \(a)")
  10.             Spacer()
  11.         }
  12.     }
  13. }
复制代码



TODO注释没有造成警告,其他规则不受影响

TODO 注释没有造成警告,其他规则不受影响
在已有的规则上使用 SwiftLint 最简单的方法是:

  • 安装 SwiftLint
  • 通过编译阶段脚本,将 SwiftLint 整合进 Xcode 项目中
  • 编译以评估所有警告和错误
  • 添加.swiftlint.yml文件,并禁用冲突数最多的规则
  • 一次启用一条规则并修复代码中的问题
<hr/>结论

对于任何 Swift 开发者来说,使用 SwiftLint 都是必要的。它有助于避免团队中关于代码样式的争论,以及建立代码风格的统一性。就我而言,它帮我摆脱了诸如创建单字符标识符等坏习惯。
将 SwiftLint 添加到已有的代码库可能比添加到新项目要复杂得多,因为它可能会显示数百个警告和错误。通过配置规则,并逐渐开启更多的规则,可以在现有项目中采用 SwiftLint。
SwiftLint 的自动修复冲突的能力非常强大,通过自动修复冲突可以显著解决数百个冲突的初始情况。只需要确保代码在进行大范围的自动更改之前已经纳入了版本控制,这样在出问题时就能很容易撤销。
<hr/>译者的一些补充

关于 SwiftLint 的安装

安装的方式有几种,原文介绍的是使用 homebrew 安装。译者比较推荐直接使用CocoaPods:
  1. pod 'SwiftLint', '0.46.5'
复制代码
能清晰明了的指明项目使用了 SwiftLint ,同时也方便指定版本。
SwiftLint 不仅仅能帮助解决格式问题

SwiftLint 不仅仅能解决很多格式问题,它的功能还有很多。比如限制一个函数参数的个数,函数、文件最长多少行,使用更精简,更Swift 的函数等等。这能在很大程度上帮助我们写出高质量的代码。
很多团队伙伴在写代码时,一开始的函数,文件可能没那么臃肿。但是随着功能的增加,不断地往一个函数添加参数,不断修改函数的功能,不断往一个文件增加新的函数等等,各个地方开始变得臃肿。当 SwiftLint 告诉你函数参数个数超过了指定的个数,函数行数超过了最大值,文件超过了最大行数等等时,就应该认真考虑是不是该重构了。
在已有项目中添加 SwiftLint

在添加 SwiftLint 之前,最重要的是全体应该开一个简短的会。用来同步以及确定规则。让所有人充分表达意见,而不是一个人制定,有些人不赞同。将一些模棱两可的规则确定清楚之后,写入到 SwiftLint 配置当中,所有人都应该遵守。
译者的项目非常的庞大,刚添加 SwiftLint 的时候,警告加错误高达5000多了,根本改不过来。我采用的方法是分路径配置 SwiftLint。那些比较老的,不怎么会动的目录采用较为宽松的配置。新起一个目录,之后的新代码原则上都应该在此目录之下。此目录的配置会较为严格。
Hook git pre-commit在提交之前做规则检查,如有问题,直接报错,无法提交代码。这样就不会产生新的警告和错误,慢慢的再修改之前的代码,经过1年多,整个项目基本就覆盖全了。
另外,关于项目的警告也需要管理,很多时候有些成员写代码的时候无视警告,导致项目警告几百个,而且越来越多。这就导致警告失去了它原有的作用,译者项目的警告是0,能够很轻松的定位哪个地方发出了新的警告。同时代码 Review 也非常重要,有些成员为了避免麻烦,各个地方都直接 disable 了 SwiftLint 的规则,这是不应该的。
最后,永远记得你只是在使用的只是一个工具,而不是目的。请充分衡量成本和收益。
54down 发表于 2023-10-4 19:21:05|来自:中国 | 显示全部楼层
也没什么特别的,就那样,xcode比较大,有时也比较慢,但是因为都是苹果官方提供的
所以你在部署等问题上,遇到bug的可能性要小很多,如果你换其他语言开发,遇到bug的可能性比较大
如果你有java,或者安卓,flutter等经验的话,弄swift会很快,尤其是还有kotlin经验的话
它的函数类型用()->{}表示,lambda用in
而其他语言的lambda则用->或者=>,函数类型则是显式声明为Function
正好有点跟swift倒过来,其他都差不太多,swift还支持tuple
目前swift跟dart对比,swift还缺少async/await,这个在后续的几个版本中也要加入了
还有jit,没有jit的话,开发时候,编译慢死了,你改一个东西,编译半天,然后还要部署,烦死
有了jit之后,编译就快了,部署到真机上去测试就很方便了
这两点是swift目前还需要加强的
其他的嘛,gui,2d游戏引擎,3d渲染,苹果都给你做好了,用就是了,简单得很
<hr/>你说swift-nio,其实就是swift版的netty,作者是一个人,都是norman
现在swift-nio在sswg里面,sswg现在越来越多公司了,一个值得注意的是跟aws的配合
你现在可以用swift来写aws的faas,serverless那些东西,苹果也嫌贫爱富,跟ibm分手了,毕竟cloud这一块,aws才是老大
还有mongodb什么,可以说比较适合个人独立开发者,未必适合公司和企业
后端这一块,如果是公司或者企业做,那还是java,但是如果独立开发者,你可以考虑用swift写云端,反正能存数据就行了嘛,对吧,你一个小app,也用不了太复杂的后端
zzfsmsk 发表于 2023-10-4 19:21:17|来自:中国 | 显示全部楼层
OC代码太难看,写了Swift就回不去了。Swift取代OC是必然的,只是时间问题。如果是新项目的话,直接上Swift 吧。我现在在一个美国公司,16年开始就纯Swift 开发了。
周亮 发表于 2023-10-4 19:21:42|来自:中国 | 显示全部楼层
应该说是非常爽的。及时之前是混编。一旦入手了 Swift 会觉得写代码的效率飞速提升。

缺点是编译比较慢,不过后来问了不少其他朋友,他们都直接用垃圾桶来。。。仔细想想,其实我们纯 OC 的项目确实编译也不快,做好 CI 是关键。
再者,Swift 在不断改进,4 比 3又改进了一大截。就个人来看,如果你讨厌频繁变动的 ABI,从 3.2 开始就可以入手了,慢慢你能体会到 Swift 的快速进步。
zknet 发表于 2023-10-4 19:22:26|来自:中国 | 显示全部楼层
前段时间准备用swift写一个react native热更新。选了rxswift。遇到一个block,里面报错,编译不过。删除里面的日志打印就没事,加上就编译不过。
语法太灵活,连Xcode都支持不到,用起来太别扭。

快速回帖

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则