์ด ์˜์—ญ์„ ๋ˆ„๋ฅด๋ฉด ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™
์กฐ์ด's log ๋ธ”๋กœ๊ทธ์˜ ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™

์กฐ์ด's log

ํŽ˜์ด์ง€ ๋งจ ์œ„๋กœ ์˜ฌ๋ผ๊ฐ€๊ธฐ

์กฐ์ด's log

Swift API Design Guidelines - 2

  • 2023.03.13 12:56
  • ๊ณต์‹๋ฌธ์„œ ํ†บ์•„๋ณด๊ธฐ/Swift API Design Guidelines

[3] Conventions

(1) General conventions

computed property์˜ ๋ณต์žก๋„๊ฐ€ O(1)์ด ์•„๋‹ˆ๋ผ๋ฉด ๋ณต์žก๋„๋ฅผ ์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ์ฃผ์„ธ์š”.

import Founcation

/// Time Complexity: O(n^2)
class Company {
    var numberOfEmployees: Int {
        var result: Int = 0

        (0...n).forEach {
            (0...n).forEach{
                (0...n).forEach{
                    result += 1
                }
            }
        }
        return result
    }
}

์ „์—ญ ํ•จ์ˆ˜ ๋Œ€์‹ ์— method์™€ property๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ „์—ญ ํ•จ์ˆ˜๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

// ๋ช…ํ™•ํ•œ self ๊ฐ€ ์—†๋Š”๊ฒฝ์šฐ
min(x, y, z)  

//function์ด generic์œผ๋กœ ์ œ์•ฝ์กฐ๊ฑด์ด ๊ฑธ๋ ค์žˆ์ง€ ์•Š์„ ๋•Œ
print(x) 

//function ๊ตฌ๋ฌธ์ด ํ•ด๋‹น ๋„๋ฉ”์ธ์˜ ํ‘œ๊ธฐ๋ฒ•์ธ ๊ฒฝ์šฐ
sin(x) 

๋Œ€์†Œ๋ฌธ์ž ์ปจ๋ฒค์…˜์„ ๋”ฐ๋ฅด์„ธ์š”.

type, protocol์˜ ์ด๋ฆ„์€ UpperCamelCase, ๋‚˜๋จธ์ง€๋Š” lowerCamelCase๋ฅผ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.

    var utf8Bytes: [UTF8] = []
    var webstieURL: URL?
    var urlString: String?

๊ธฐ๋ณธ ๋œป์ด ๊ฐ™๊ฑฐ๋‚˜ ๊ตฌ๋ณ„๋˜๋Š” ์„œ๋กœ ๊ตฌ๋ณ„๋˜๋Š” ๋„๋ฉ”์ธ์—์„œ ์ž‘๋™ํ•˜๋Š” Method๋Š” base name์„ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ‘ [์ข‹์€ ์˜ˆ์‹œ 1]

๊ธฐ๋ณธ์ ์œผ๋กœ ๊ฐ™์€ ๋™์ž‘์„ ํ•˜๋Š” ๋ฉ”์†Œ๋“œ๋“ค์˜ ๋‚˜์—ด

struct Shape {
    func contains(_ otehr: Point) -> Bool {}
    func contains(_ other: Shape) -> Bool {}
}

let shape = Shape()
shape.contains(Point())
shape.contains(Shape())
๐Ÿ‘ [์ข‹์€ ์˜ˆ์‹œ 2]

์œ„์˜ Shape ์™€ collection type์€ ๊ตฌ๋ณ„๋œ ๋„๋ฉ”์ธ์ด๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ™์€ ํ”„๋กœ๊ทธ๋žจ ์•ˆ์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

struct Shape {
    func contains(_ otehr: Point) -> Bool {}
    func contains(_ other: Shape) -> Bool {}
}

extension Collection where Element : Equatable {
  func contains(_ sought: Element) -> Bool { ... }
}
๐Ÿ‘Ž [๋‚˜์œ ์˜ˆ์‹œ 1]

์•„๋ž˜์˜ index method๋Š” ๋‹ค๋ฅธ ์˜๋ฏธ๋ฅผ ๊ฐ–๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋‹ค๋ฅด๊ฒŒ ๋„ค์ด๋ฐ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

extension Database {
  /// Rebuilds the database's search index
  func index() { ... }

  /// Returns the `n`th row in the given table.
  func index(_ n: Int, inTable: TableID) -> TableRow { ... }
}
๐Ÿ‘Ž [๋‚˜์œ ์˜ˆ์‹œ 2]

"overloading on return type"(๋ฆฌํ„ด ๊ฐ’์„ ์˜ค๋ฒ„๋กœ๋”ฉ ํ•˜๋Š” ๊ฒฝ์šฐ)์€ ํƒ€์ž… ์ถ”๋ก ์˜ ์œ ๋ฌด์— ๋”ฐ๋ผ ๋ชจํ˜ธํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์–ด์„œ ๊ถŒ์žฅ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

struct Box {
    private let rawValue: Int

    init(_ rawValue: Int) {
        self.rawValue = rawValue
    }

    func value() -> Int? {
        rawValue
    }

    func value() -> String {
        "\(rawValue)"
    }
}

let myBox = Box(100)
myBox.value() as Int?
myBox.value() as String?

let intBoxValue: Int? = myBox.value()

(2) Parameters

์ฃผ์„์„ ์ฝ๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ ์ด๋ฆ„์„ ์„ ํƒํ•˜์„ธ์š”.

๐Ÿ‘ [์ข‹์€ ์˜ˆ์‹œ]
    /// Return an `Array` containing the elements of `self`
    /// that satisfy `predicate`.
    func filter(_ predicate: (Element) -> Bool) -> [Generator.Element]

    /// Replace the given `subRange` of elements with `newElements`.
    mutating func replaceRange(_ subRange: Range, with newElements: [E])

    func move(from start: Point, to end: Point){}
๐Ÿ‘Ž [๋‚˜์œ ์˜ˆ์‹œ]
    /// Return an `Array` containing the elements of `self`
    /// that satisfy `includedInResult`.
    func filter(_ includedInResult: (Element) -> Bool) -> [Generator.Element]

    /// Replace the range of elements indicated by `r` with
    /// the contents of `with`.
    mutating func replaceRange(_ r: Range, with: [E])

์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ์„ ๋‹จ์ˆœํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด, Defaulted Parameters๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”

๐Ÿ‘ [์ข‹์€ ์˜ˆ์‹œ]
// #1
let order = lastName
            .compare(royalFamilyName, options: [], range: nil, locale: nil)
let order = lastName.compare(royalFamilyName)

// #2
extension String {
  /// ...description...
  public func compare(
     _ other: String, options: CompareOptions = [],
     range: Range? = nil, locale: Locale? = nil
  ) -> Ordering
}
๐Ÿ‘Ž [๋‚˜์œ ์˜ˆ์‹œ]
extension String {
  /// ...description 1...
  public func compare(_ other: String) -> Ordering
  /// ...description 2...
  public func compare(_ other: String, options: CompareOptions) -> Ordering
  /// ...description 3...
  public func compare(
     _ other: String, options: CompareOptions, range: Range) -> Ordering
  /// ...description 4...
  public func compare(
     _ other: String, options: StringCompareOptions,
     range: Range, locale: Locale) -> Ordering
}

Default parameter๋ฅผ parameter list ๋ ๋ถ€๋ถ„์— ๋‘๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค

//Default Parameter๋ฅผ ๋๋ถ€๋ถ„์— ๋‘์—ˆ์„ ๊ฒฝ์šฐ์˜ ํ˜ธ์ถœ๋ฌธ
compare("A")
compare("B", locale: nil)
compare("B", options:[], locale: nil)
compare("B", options:[], range: nil, locale: nil)


//Default Parameter๋ฅผ ๋๋ถ€๋ถ„์— ๋‘์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ์˜ ํ˜ธ์ถœ๋ฌธ
compare("A")
compare(locale: nil, "B")
compare(options:[], locale: nil, "B")
compare(options:[], range: nil, locale: nil, "B")

(3) Argument Labels

// from๊ณผ to๊ฐ€ arugument label
func move(from start: Point, to end: Point)
x.move(from: x, to: y) 

label์„ ์จ๋„ ์œ ์šฉํ•˜๊ฒŒ ๊ตฌ๋ถ„์ด ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ชจ๋“  label์„ ์ƒ๋žตํ•˜์„ธ์š”

min(number1, number2)
zip(sequence1, sequence2)

๊ฐ’์„ ์œ ์ง€ํ•˜๋ฉด์„œ ํƒ€์ž… ๋ณ€ํ™˜์„ ํ•ด์ฃผ๋Š” initializer์—์„œ, ์ฒซ๋ฒˆ์งธ argument label์„ ์ƒ๋žตํ•˜์„ธ์š”.

Int64(someUInt32) // UInt32์—์„œ Int64๋กœ ํ™•์žฅ๋˜๋ฏ€๋กœ

์ฒซ๋ฒˆ์งธ argument๋Š” ํ•ญ์ƒ source of conversion ์ด์–ด์•ผ ํ•œ๋‹ค.
extension String {
// Convert `x` into its textual representation in the given radix
init(_ x: BigInt, radix: Int = 10)   โ† Note the initial underscore
}

text = "The value is: "
text += String(veryLargeNumber)
text += " and in hexadecimal, it's"
text += String(veryLargeNumber, radix: 16)

๊ฐ’์˜ ๋ฒ”์œ„๊ฐ€ ์ขํ˜€์ง€๋Š” ํƒ€์ž… ๋ณ€ํ™˜์˜ ๊ฒฝ์šฐ, label์„ ๋ถ™์—ฌ์„œ ์„ค๋ช…ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค

extension UInt32 {
/// Creates an instance having the specified `value`.
init(_ value: Int16)            โ† Widening, so no label

/// Creates an instance having the lowest 32 bits of `source`.
// ๊ฐ’์ด ์ค„์—ฌ์ง€๋ฏ€๋กœ truncating ๋ถ™์–ด์•ผ ํ•œ๋‹ค.
init(truncating source: UInt64)

/// Creates an instance having the nearest representable
/// approximation of `valueToApproximate`.
init(saturating valueToApproximate: UInt64)
}

์ฒซ ๋ฒˆ์งธ argument๊ฐ€ ์ „์น˜์‚ฌ๊ตฌ์˜ ์ผ๋ถ€์ผ ๋•Œ, argument label๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค

argument label์€ ๋ณดํ†ต ์ „์น˜์‚ฌ๋กœ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

func removeBoxes(havingLength length: Int) {}

x.removeBoxes(havingLength: 12)

์ฒ˜์Œ์— ๋‚˜์˜ค๋Š” 2๊ฐœ์˜ argument๋“ค์ด ๋‹จ์ผ ์ถ”์ƒํ™”๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์˜ˆ์™ธ์ž…๋‹ˆ๋‹ค.

// ๐Ÿ‘ ์ข‹์€ ์˜ˆ์‹œ 
a.moveTo(x: b, y: c)
a.fadeFrom(red: b, green: c, blue: d)

// ๐Ÿ‘Ž ๋‚˜์œ ์˜ˆ์‹œ
a.move(toX: b, y: c)
a.fade(fromRed: b, green: c, blue: d)

๋งŒ์•ฝ ์ฒซ๋ฒˆ์งธ argument๊ฐ€ ๋ฌธ๋ฒ•์  ๊ตฌ์ ˆ์„ ๋งŒ๋“ ๋‹ค๋ฉด label์€ ์ œ๊ฑฐํ•˜๊ณ , ํ•จ์ˆ˜ ์ด๋ฆ„์— base name์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

x.addSubview(y)

์ฒซ๋ฒˆ์งธ argument๊ฐ€ ๋ฌธ๋ฒ•์ ์œผ๋กœ ๊ตฌ์ ˆ์„ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค๋ฉด, label์„ ๋‘ฌ์•ผํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•”์‹œํ•ฉ๋‹ˆ๋‹ค.

// ๐Ÿ‘ ์ข‹์€ ์˜ˆ์‹œ 
view.dismiss(animated: false)
let text = words.split(maxSplits: 12)
let studentsByName = students.sorted(isOrderedBefore: Student.namePrecedes)

// ๐Ÿ‘Ž ๋‚˜์œ ์˜ˆ์‹œ
view.dismiss(false)   Don't dismiss? Dismiss a Bool?
words.split(12)       Split the number 12?

default value๋ฅผ ๊ฐ€์ง„ argument๋Š” ์ƒ๋žต๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ๊ฒฝ์šฐ ๋ฌธ๋ฒ• ๊ตฌ๋ฌธ์˜ ์ผ๋ถ€๋ฅผ ํ˜•์„ฑํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ•ญ์ƒ ๋ ˆ์ด๋ธ”์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

extension String {
  /// ...description...
  public func compare(
     _ other: String, options: CompareOptions = [],
     from range: Range? = nil, with locale: Locale? = nil
  ) -> Ordering
}

๋‚˜๋จธ์ง€ ๋ชจ๋“  ๊ฒฝ์šฐ, argument๋“ค์€ Label์„ ๋ถ™์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค


[4] Special Instructions

tuple members์™€ closure parameters์— Label์„ ๋ถ™์ด์„ธ์š”.

struct Storage {
    func doSomething() -> (reallocated: Bool, capacityChanged: Bool) {
        return (true, false)
    }
}

let storage = Storage()
let result = storage.doSomething()

result.reallocated // true
result.capacityChanged //false

overload set์—์„œ์˜ ๋ชจํ˜ธํ•จ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด, ์ œ์•ฝ ์—†๋Š” ๋‹คํ˜•์„ฑ์— ๊ฐ๋ณ„ํžˆ ์ฃผ์˜ํ•˜์„ธ์š”.

๐Ÿ‘ ์ข‹์€ ์˜ˆ์‹œ
struct Array {
  /// Inserts `newElement` at `self.endIndex`.
  public mutating func append(_ newElement: Element)

  /// Inserts the contents of `newElements`, in order, at
  /// `self.endIndex`.
  public mutating func append(contentsOf newElements: S)
    where S.Generator.Element == Element
}

var values: [Any] = [1, "a"]
values.append(contentsOf:[2, 3, 4]) //[1,"a", 2, 3, 4]
๐Ÿ‘Ž ๋‚˜์œ ์˜ˆ์‹œ
struct Array {
  /// Inserts `newElement` at `self.endIndex`.
  public mutating func append(_ newElement: Element)

  /// Inserts the contents of `newElements`, in order, at
  /// `self.endIndex`.
  public mutating func append(_ newElements: S)
    where S.Generator.Element == Element
}

var values: [Any] = [1, "a"]
values.append([2, 3, 4]) // [1, "a", [2, 3, 4]] or [1, "a", 2, 3, 4]?

์ฐธ๊ณ 

  • ๊ณต์‹ ๋ฌธ์„œ: https://www.swift.org/documentation/api-design-guidelines/
  • ๋ฒˆ์—ญ๋ณธ: https://cozzin.gitbook.io/swift-api-design-guidelines/naming/strive-for-fluent-usage
์ €์ž‘์žํ‘œ์‹œ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'๊ณต์‹๋ฌธ์„œ ํ†บ์•„๋ณด๊ธฐ > Swift API Design Guidelines' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Swift API Design Guidelines - 1  (0) 2023.03.13

๋Œ“๊ธ€

์ด ๊ธ€ ๊ณต์œ ํ•˜๊ธฐ

  • ๊ตฌ๋…ํ•˜๊ธฐ

    ๊ตฌ๋…ํ•˜๊ธฐ

  • ์นด์นด์˜คํ†ก

    ์นด์นด์˜คํ†ก

  • ๋ผ์ธ

    ๋ผ์ธ

  • ํŠธ์œ„ํ„ฐ

    ํŠธ์œ„ํ„ฐ

  • Facebook

    Facebook

  • ์นด์นด์˜ค์Šคํ† ๋ฆฌ

    ์นด์นด์˜ค์Šคํ† ๋ฆฌ

  • ๋ฐด๋“œ

    ๋ฐด๋“œ

  • ๋„ค์ด๋ฒ„ ๋ธ”๋กœ๊ทธ

    ๋„ค์ด๋ฒ„ ๋ธ”๋กœ๊ทธ

  • Pocket

    Pocket

  • Evernote

    Evernote

๋‹ค๋ฅธ ๊ธ€

  • Swift API Design Guidelines - 1

    Swift API Design Guidelines - 1

    2023.03.13
๋‹ค๋ฅธ ๊ธ€ ๋” ๋‘˜๋Ÿฌ๋ณด๊ธฐ

์ •๋ณด

์กฐ์ด's log ๋ธ”๋กœ๊ทธ์˜ ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™

์กฐ์ด's log

  • ์กฐ์ด's log์˜ ์ฒซ ํŽ˜์ด์ง€๋กœ ์ด๋™

๋ฉ”๋‰ด

  • ํ™ˆ
  • ํƒœ๊ทธ

๊ฒ€์ƒ‰

์นดํ…Œ๊ณ ๋ฆฌ

  • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (12)
    • iOS ์ฐจ๊ณก์ฐจ๊ณก (1)
    • ๊ณต์‹๋ฌธ์„œ ํ†บ์•„๋ณด๊ธฐ (2)
      • WWDC (0)
      • Swift API Design Guidelines (2)
    • ํ›„๊ธฐ (9)
      • ํ”„๋กœ์ ํŠธ ํšŒ๊ณ  (0)
      • ์ฑ… (5)
      • ํ…Œํฌ talk (4)
    • ์—๋Ÿฌ๋…ธํŠธ (0)

๋‚˜์˜ ์™ธ๋ถ€ ๋งํฌ

์ •๋ณด

์กฐ์ด๐Ÿ˜ƒ์˜ ์กฐ์ด's log

์กฐ์ด's log

์กฐ์ด๐Ÿ˜ƒ

๋ธ”๋กœ๊ทธ ๊ตฌ๋…ํ•˜๊ธฐ

  • ๊ตฌ๋…ํ•˜๊ธฐ
  • RSS ํ”ผ๋“œ

๋ฐฉ๋ฌธ์ž

  • ์ „์ฒด ๋ฐฉ๋ฌธ์ž
  • ์˜ค๋Š˜
  • ์–ด์ œ

ํ‹ฐ์Šคํ† ๋ฆฌ

  • ํ‹ฐ์Šคํ† ๋ฆฌ ํ™ˆ
  • ์ด ๋ธ”๋กœ๊ทธ ๊ด€๋ฆฌํ•˜๊ธฐ
  • ๊ธ€์“ฐ๊ธฐ
Powered by Tistory / Kakao. © ์กฐ์ด๐Ÿ˜ƒ. Designed by Fraccino.

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”