Skip to content

Ounce_Coding_Convention

Junhyeon edited this page Jun 30, 2020 · 2 revisions
  • Ounce

    Coding-Convention

    Swift Creative Commons License

    Style Share의 swift-style-guide λ¬Έμ„œλ₯Ό μ°Έκ³ ν•΄ λ§Œλ“  λ¬Έμ„œμž…λ‹ˆλ‹€.

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

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

    λͺ©μ°¨

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

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

    • λ“€μ—¬μ“°κΈ°μ—λŠ” νƒ­(tab)을 μ‚¬μš©ν•©λ‹ˆλ‹€

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

      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 β†’ Editing의 '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?
      

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

    • ν΄λž˜μŠ€μ™€ ꡬ쑰체 λ‚΄λΆ€μ—μ„œλŠ” 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μ—κ²Œ μžˆμŠ΅λ‹ˆλ‹€.