Skip to content

Latest commit

Β 

History

History
535 lines (382 loc) Β· 13 KB

Swift Style Guide by StyleShare.md

File metadata and controls

535 lines (382 loc) Β· 13 KB

λ³Έ 글은 StyleShareμ—μ„œ μž‘μ„±ν•œ Swift ν•œκ΅­μ–΄ μŠ€νƒ€μΌ κ°€μ΄λ“œλ₯Ό Forkν•œ κ²ƒμž…λ‹ˆλ‹€.

Swift Style Guide

Swift Creative Commons License

StyleShare ꡬ성원듀이 Swift μ½”λ“œλ₯Ό μ΄ν•΄ν•˜κΈ° 쉽고 λͺ…ν™•ν•˜κ²Œ μž‘μ„±ν•˜κΈ° μœ„ν•œ μŠ€νƒ€μΌ κ°€μ΄λ“œμž…λ‹ˆλ‹€. κ΅¬μ„±μ›λ“€μ˜ μ˜μ‚¬κ²°μ •μ— 따라 μˆ˜μ‹œλ‘œ 변경될 수 μžˆμŠ΅λ‹ˆλ‹€.

λ³Έ λ¬Έμ„œμ— λ‚˜μ™€μžˆμ§€ μ•Šμ€ κ·œμΉ™μ€ μ•„λž˜ λ¬Έμ„œλ₯Ό λ”°λ¦…λ‹ˆλ‹€.

λͺ©μ°¨

μ½”λ“œ λ ˆμ΄μ•„μ›ƒ

λ“€μ—¬μ“°κΈ° 및 띄어쓰기

  • λ“€μ—¬μ“°κΈ°μ—λŠ” νƒ­(tab) λŒ€μ‹  2개의 spaceλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

  • 콜둠(:)을 μ“Έ λ•Œμ—λŠ” 콜둠의 였λ₯Έμͺ½μ—λ§Œ 곡백을 λ‘‘λ‹ˆλ‹€.

    let names: [String: String]?
  • μ—°μ‚°μž μ˜€λ²„λ‘œλ”© ν•¨μˆ˜ μ •μ˜μ—μ„œλŠ” μ—°μ‚°μžμ™€ κ΄„ν˜Έ 사이에 ν•œ μΉΈ λ„μ–΄μ”λ‹ˆλ‹€.

    func ** (lhs: Int, rhs: Int)

μ€„λ°”κΏˆ

  • ν•¨μˆ˜ μ •μ˜κ°€ μ΅œλŒ€ 길이λ₯Ό μ΄ˆκ³Όν•˜λŠ” κ²½μš°μ—λŠ” μ•„λž˜μ™€ 같이 μ€„λ°”κΏˆν•©λ‹ˆλ‹€.

    func collectionView(
      _ collectionView: UICollectionView,
      cellForItemAt indexPath: IndexPath
    ) -> UICollectionViewCell {
      // doSomething()
    }
    
    func animationController(
      forPresented presented: UIViewController,
      presenting: UIViewController,
      source: UIViewController
    ) -> UIViewControllerAnimatedTransitioning? {
      // doSomething()
    }
  • ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” μ½”λ“œκ°€ μ΅œλŒ€ 길이λ₯Ό μ΄ˆκ³Όν•˜λŠ” κ²½μš°μ—λŠ” νŒŒλΌλ―Έν„° 이름을 κΈ°μ€€μœΌλ‘œ μ€„λ°”κΏˆν•©λ‹ˆλ‹€.

    let actionSheet = UIActionSheet(
      title: "정말 계정을 μ‚­μ œν•˜μ‹€ κ±΄κ°€μš”?",
      delegate: self,
      cancelButtonTitle: "μ·¨μ†Œ",
      destructiveButtonTitle: "μ‚­μ œν•΄μ£Όμ„Έμš”"
    )

    단, νŒŒλΌλ―Έν„°μ— ν΄λ‘œμ €κ°€ 2개 이상 μ‘΄μž¬ν•˜λŠ” κ²½μš°μ—λŠ” 무쑰건 λ‚΄λ €μ“°κΈ°ν•©λ‹ˆλ‹€.

    UIView.animate(
      withDuration: 0.25,
      animations: {
        // doSomething()
      },
      completion: { finished in
        // doSomething()
      }
    )
  • if let ꡬ문이 κΈΈ κ²½μš°μ—λŠ” μ€„λ°”κΏˆν•˜κ³  ν•œ μΉΈ λ“€μ—¬μ”λ‹ˆλ‹€.

    if let user = self.veryLongFunctionNameWhichReturnsOptionalUser(),
      let name = user.veryLongFunctionNameWhichReturnsOptionalName(),
      user.gender == .female {
      // ...
    }
  • guard let ꡬ문이 κΈΈ κ²½μš°μ—λŠ” μ€„λ°”κΏˆν•˜κ³  ν•œ μΉΈ λ“€μ—¬μ”λ‹ˆλ‹€. elseλŠ” guard와 같은 λ“€μ—¬μ“°κΈ°λ₯Ό μ μš©ν•©λ‹ˆλ‹€.

    guard let user = self.veryLongFunctionNameWhichReturnsOptionalUser(),
      let name = user.veryLongFunctionNameWhichReturnsOptionalName(),
      user.gender == .female
    else {
      return
    }

μ΅œλŒ€ 쀄 길이

  • ν•œ 쀄은 μ΅œλŒ€ 99자λ₯Ό λ„˜μ§€ μ•Šμ•„μ•Ό ν•©λ‹ˆλ‹€.

    Xcode의 Preferences β†’ Text Editing β†’ Display의 'Page guide at column' μ˜΅μ…˜μ„ ν™œμ„±ν™”ν•˜κ³  99자둜 μ„€μ •ν•˜λ©΄ νŽΈλ¦¬ν•©λ‹ˆλ‹€.

빈 쀄

  • 빈 μ€„μ—λŠ” 곡백이 ν¬ν•¨λ˜μ§€ μ•Šλ„λ‘ ν•©λ‹ˆλ‹€.

  • λͺ¨λ“  νŒŒμΌμ€ 빈 μ€„λ‘œ λλ‚˜λ„λ‘ ν•©λ‹ˆλ‹€.

  • MARK ꡬ문 μœ„μ™€ μ•„λž˜μ—λŠ” 곡백이 ν•„μš”ν•©λ‹ˆλ‹€.

    // MARK: Layout
    
    override func layoutSubviews() {
      // doSomething()
    }
    
    // MARK: Actions
    
    override func menuButtonDidTap() {
      // doSomething()
    }

μž„ν¬νŠΈ

λͺ¨λ“ˆ μž„ν¬νŠΈλŠ” μ•ŒνŒŒλ²³ 순으둜 μ •λ ¬ν•©λ‹ˆλ‹€. λ‚΄μž₯ ν”„λ ˆμž„μ›Œν¬λ₯Ό λ¨Όμ € μž„ν¬νŠΈν•˜κ³ , 빈 μ€„λ‘œ κ΅¬λΆ„ν•˜μ—¬ μ„œλ“œνŒŒν‹° ν”„λ ˆμž„μ›Œν¬λ₯Ό μž„ν¬νŠΈν•©λ‹ˆλ‹€.

import UIKit

import SwiftyColor
import SwiftyImage
import Then
import URLNavigator

넀이밍

클래슀

  • 클래슀 μ΄λ¦„μ—λŠ” UpperCamelCaseλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
  • 클래슀 μ΄λ¦„μ—λŠ” 접두사Prefixλ₯Ό 뢙이지 μ•ŠμŠ΅λ‹ˆλ‹€.

ν•¨μˆ˜

  • ν•¨μˆ˜ μ΄λ¦„μ—λŠ” lowerCamelCaseλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

  • ν•¨μˆ˜ 이름 μ•žμ—λŠ” λ˜λ„λ‘μ΄λ©΄ get을 뢙이지 μ•ŠμŠ΅λ‹ˆλ‹€.

    쒋은 예:

    func name(for user: User) -> String?

    λ‚˜μœ 예:

    func getName(for user: User) -> String?
  • Action ν•¨μˆ˜μ˜ 넀이밍은 'μ£Όμ–΄ + 동사 + λͺ©μ μ–΄' ν˜•νƒœλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    • *Tap(λˆŒλ €λ‹€ λ—Œ)*은 UIControlEvents의 .touchUpInside에 λŒ€μ‘ν•˜κ³ , *Press(λˆ„λ¦„)*λŠ” .touchDown에 λŒ€μ‘ν•©λ‹ˆλ‹€.
    • will~은 νŠΉμ • ν–‰μœ„κ°€ μΌμ–΄λ‚˜κΈ° 직전이고, did~λŠ” νŠΉμ • ν–‰μœ„κ°€ μΌμ–΄λ‚œ μ§ν›„μž…λ‹ˆλ‹€.
    • should~λŠ” 일반적으둜 Bool을 λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜μ— μ‚¬μš©λ©λ‹ˆλ‹€.

    쒋은 예:

    func backButtonDidTap() {
      // ...
    }

    λ‚˜μœ 예:

    func back() {
      // ...
    }
    
    func pressBack() {
      // ...
    }

λ³€μˆ˜

  • λ³€μˆ˜ μ΄λ¦„μ—λŠ” lowerCamelCaseλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

μƒμˆ˜

  • μƒμˆ˜ μ΄λ¦„μ—λŠ” lowerCamelCaseλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    쒋은 예:

    let maximumNumberOfLines = 3

    λ‚˜μœ 예:

    let kMaximumNumberOfLines = 3
    let MAX_LINES = 3

μ—΄κ±°ν˜•

  • enum의 각 caseμ—λŠ” lowerCamelCaseλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    쒋은 예:

    enum Result {
      case .success
      case .failure
    }

    λ‚˜μœ 예:

    enum Result {
      case .Success
      case .Failure
    }

μ•½μ–΄

  • μ•½μ–΄λ‘œ μ‹œμž‘ν•˜λŠ” 경우 μ†Œλ¬Έμžλ‘œ ν‘œκΈ°ν•˜κ³ , κ·Έ μ™Έμ˜ κ²½μš°μ—λŠ” 항상 λŒ€λ¬Έμžλ‘œ ν‘œκΈ°ν•©λ‹ˆλ‹€.

    쒋은 예:

      let userID: Int?
      let html: String?
      let websiteURL: URL?
      let urlString: String?
      

    λ‚˜μœ 예:

      let userId: Int?
      let HTML: String?
      let websiteUrl: NSURL?
      let URLString: String?
      

Delegate

  • Delegate λ©”μ„œλ“œλŠ” ν”„λ‘œν† μ½œλͺ…μœΌλ‘œ λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό κ΅¬λΆ„ν•©λ‹ˆλ‹€.

    쒋은 예:

    protocol UserCellDelegate {
      func userCellDidSetProfileImage(_ cell: UserCell)
      func userCell(_ cell: UserCell, didTapFollowButtonWith user: User)
    }

    λ‚˜μœ 예:

    protocol UserCellDelegate {
      func didSetProfileImage()
      func followPressed(user: User)
    
      // `UserCell`μ΄λΌλŠ” ν΄λž˜μŠ€κ°€ μ‘΄μž¬ν•  경우 컴파일 μ—λŸ¬ λ°œμƒ
      func UserCell(_ cell: UserCell, didTapFollowButtonWith user: User)
    }

ν΄λ‘œμ €

  • νŒŒλΌλ―Έν„°μ™€ 리턴 νƒ€μž…μ΄ μ—†λŠ” Closure μ •μ˜μ‹œμ—λŠ” () -> Voidλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    쒋은 예:

    let completionBlock: (() -> Void)?

    λ‚˜μœ 예:

    let completionBlock: (() -> ())?
    let completionBlock: ((Void) -> (Void))?
  • Closure μ •μ˜μ‹œ νŒŒλΌλ―Έν„°μ—λŠ” κ΄„ν˜Έλ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

    쒋은 예:

    { operation, responseObject in
      // doSomething()
    }

    λ‚˜μœ 예:

    { (operation, responseObject) in
      // doSomething()
    }
  • Closure μ •μ˜μ‹œ κ°€λŠ₯ν•œ 경우 νƒ€μž… μ •μ˜λ₯Ό μƒλž΅ν•©λ‹ˆλ‹€.

    쒋은 예:

    ...,
    completion: { finished in
      // doSomething()
    }

    λ‚˜μœ 예:

    ...,
    completion: { (finished: Bool) -> Void in
      // doSomething()
    }
  • Closure ν˜ΈμΆœμ‹œ λ˜λ‹€λ₯Έ μœ μΌν•œ Closureλ₯Ό λ§ˆμ§€λ§‰ νŒŒλΌλ―Έν„°λ‘œ λ°›λŠ” 경우, νŒŒλΌλ―Έν„° 이름을 μƒλž΅ν•©λ‹ˆλ‹€.

    쒋은 예:

    UIView.animate(withDuration: 0.5) {
      // doSomething()
    }

    λ‚˜μœ 예:

    UIView.animate(withDuration: 0.5, animations: { () -> Void in
      // doSomething()
    })

ν΄λž˜μŠ€μ™€ ꡬ쑰체

  • ν΄λž˜μŠ€μ™€ ꡬ쑰체 λ‚΄λΆ€μ—μ„œλŠ” selfλ₯Ό λͺ…μ‹œμ μœΌλ‘œ μ‚¬μš©ν•©λ‹ˆλ‹€.

  • ꡬ쑰체λ₯Ό 생성할 λ•Œμ—λŠ” Swift ꡬ쑰체 μƒμ„±μžλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    쒋은 예:

    let frame = CGRect(x: 0, y: 0, width: 100, height: 100)

    λ‚˜μœ 예:

    let frame = CGRectMake(0, 0, 100, 100)

νƒ€μž…

  • Array<T>와 Dictionary<T: U> λ³΄λ‹€λŠ” [T], [T: U]λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

    쒋은 예:

    var messages: [String]?
    var names: [Int: String]?

    λ‚˜μœ 예:

    var messages: Array<String>?
    var names: Dictionary<Int, String>?

주석

  • ///λ₯Ό μ‚¬μš©ν•΄μ„œ λ¬Έμ„œν™”μ— μ‚¬μš©λ˜λŠ” 주석을 λ‚¨κΉλ‹ˆλ‹€.

    /// μ‚¬μš©μž ν”„λ‘œν•„μ„ κ·Έλ €μ£ΌλŠ” λ·°
    class ProfileView: UIView {
    
      /// μ‚¬μš©μž λ‹‰λ„€μž„μ„ κ·Έλ €μ£ΌλŠ” 라벨
      var nameLabel: UILabel!
    }
  • // MARK:λ₯Ό μ‚¬μš©ν•΄μ„œ μ—°κ΄€λœ μ½”λ“œλ₯Ό κ΅¬λΆ„μ§“μŠ΅λ‹ˆλ‹€.

    Objective-Cμ—μ„œ μ œκ³΅ν•˜λŠ” #pragma mark와 같은 κΈ°λŠ₯으둜, μ—°κ΄€λœ μ½”λ“œμ™€ 그렇지 μ•Šμ€ μ½”λ“œλ₯Ό ꡬ뢄할 λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

    // MARK: Init
    
    override init(frame: CGRect) {
      // doSomething()
    }
    
    deinit {
      // doSomething()
    }
    
    
    // MARK: Layout
    
    override func layoutSubviews() {
      // doSomething()
    }
    
    
    // MARK: Actions
    
    override func menuButtonDidTap() {
      // doSomething()
    }

ν”„λ‘œκ·Έλž˜λ° ꢌμž₯사항

  • κ°€λŠ₯ν•˜λ‹€λ©΄ λ³€μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ ν•¨κ»˜ μ΄ˆκΈ°ν™”ν•˜λ„λ‘ ν•©λ‹ˆλ‹€. Then을 μ‚¬μš©ν•˜λ©΄ μ΄ˆκΈ°ν™”μ™€ ν•¨κ»˜ 속성을 지정할 수 μžˆμŠ΅λ‹ˆλ‹€.

    let label = UILabel().then {
      $0.textAlignment = .center
      $0.textColor = .black
      $0.text = "Hello, World!"
    }
  • μƒμˆ˜λ₯Ό μ •μ˜ν•  λ•Œμ—λŠ” enumλ₯Ό λ§Œλ“€μ–΄ λΉ„μŠ·ν•œ μƒμˆ˜λΌλ¦¬ λͺ¨μ•„λ‘‘λ‹ˆλ‹€. μž¬μ‚¬μš©μ„±κ³Ό μœ μ§€λ³΄μˆ˜ μΈ‘λ©΄μ—μ„œ 큰 ν–₯상을 κ°€μ Έμ˜΅λ‹ˆλ‹€. struct λŒ€μ‹  enum을 μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ”, μƒμ„±μžκ°€ μ œκ³΅λ˜μ§€ μ•ŠλŠ” μžλ£Œν˜•μ„ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œμž…λ‹ˆλ‹€. CGFloatLiteralκ³Ό SwiftyColorλ₯Ό μ‚¬μš©ν•΄μ„œ μ½”λ“œλ₯Ό λ‹¨μˆœν™”μ‹œν‚΅λ‹ˆλ‹€.

    final class ProfileViewController: UIViewController {
    
      private enum Metric {
        static let profileImageViewLeft = 10.f
        static let profileImageViewRight = 10.f
        static let nameLabelTopBottom = 8.f
        static let bioLabelTop = 6.f
      }
    
      private enum Font {
        static let nameLabel = UIFont.boldSystemFont(ofSize: 14)
        static let bioLabel = UIFont.boldSystemFont(ofSize: 12)
      }
    
      private enum Color {
        static let nameLabelText = 0x000000.color
        static let bioLabelText = 0x333333.color ~ 70%
      }
    
    }

    μ΄λ ‡κ²Œ μ„ μ–Έλœ μƒμˆ˜λ“€μ€ λ‹€μŒκ³Ό 같이 μ‚¬μš©λ  수 μžˆμŠ΅λ‹ˆλ‹€.

    self.profileImageView.frame.origin.x = Metric.profileImageViewLeft
    self.nameLabel.font = Font.nameLabel
    self.nameLabel.textColor = Color.nameLabelText
  • 더이상 상속이 λ°œμƒν•˜μ§€ μ•ŠλŠ” ν΄λž˜μŠ€λŠ” 항상 final ν‚€μ›Œλ“œλ‘œ μ„ μ–Έν•©λ‹ˆλ‹€.

  • ν”„λ‘œν† μ½œμ„ μ μš©ν•  λ•Œμ—λŠ” extension을 λ§Œλ“€μ–΄μ„œ κ΄€λ ¨λœ λ©”μ„œλ“œλ₯Ό λͺ¨μ•„λ‘‘λ‹ˆλ‹€.

    쒋은 예:

    final class MyViewController: UIViewController {
      // ...
    }
    
    // MARK: - UITableViewDataSource
    
    extension MyViewController: UITableViewDataSource {
      // ...
    }
    
    // MARK: - UITableViewDelegate
    
    extension MyViewController: UITableViewDelegate {
      // ...
    }

    λ‚˜μœ 예:

    final class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
      // ...
    }

λΌμ΄μ„ΌμŠ€

λ³Έ λ¬Έμ„œλŠ” ν¬λ¦¬μ—μ΄ν‹°λΈŒ 컀먼즈 μ €μž‘μžν‘œμ‹œ 4.0 ꡭ제 λΌμ΄μ„ΌμŠ€μ— 따라 μ΄μš©ν•  수 있으며, μ €μž‘κΆŒμ€ μ „μˆ˜μ—΄κ³Ό StyleShareμ—κ²Œ μžˆμŠ΅λ‹ˆλ‹€.