Skip to content

InventoryBox_Coding_Convention

Hwangho edited this page Jul 7, 2020 · 1 revision

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์—๊ฒŒ ์žˆ์Šต๋‹ˆ๋‹ค.

Clone this wiki locally