Skip to content

๐Ÿง ๋ถ€์ŠคํŠธ์บ ํ”„ iOS ๋ฆฌ๋ทฐ์–ด ํ™œ๋™ ๋‚ด์šฉ ์ •๋ฆฌ

Notifications You must be signed in to change notification settings

cozzin/ios-study-note

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

14 Commits
ย 
ย 

Repository files navigation

iOS Study Note

๋ถ€์ŠคํŠธ์บ ํ”„ iOS 6๊ธฐ ๋ฆฌ๋ทฐ์–ด ์ง„ํ–‰ํ•˜๋ฉด์„œ ๋‚ด์šฉ ์—…๋ฐ์ดํŠธ ์ค‘ ์ž…๋‹ˆ๋‹ค.

๊ณต์‹๋ฌธ์„œ

OOP

๋ช…๋ น-์ฟผ๋ฆฌ ๋ถ„๋ฆฌ

  • Query: ์งˆ๋ฌธํ•ด์„œ ๋‹ต์„ ์š”์ฒญ
  • Command : ๋ณ€๊ฒฝ์„ ์š”์ฒญ

์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ Query - Command ๊ฐ€ ๋ถ„๋ฆฌ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ํ˜ผ๋ž€์„ ๊ฒช์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํ•œ ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด๋ฉด

func isEmpty() -> Bool {
    count += 1
    return myArray.isEmpty
}

isEmpty()๋ฅผ ํ˜ธ์ถœํ•œ ์‚ฌ์šฉ์ž๋Š” count๊ฐ€ ์ฆ๊ฐ€๋˜๋Š” ๊ฒƒ์„ ์ธ์ง€ํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ์— count๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์—ผ๋‘ํ•ด๋‘๊ณ  ์žˆ๋”๋ผ๋„ 1. empty ์ธ๊ฐ€? + 2. count๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ฒ ๊ตฐ ์œผ๋กœ ์ƒ๊ฐํ•ด์•ผํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜ ํ•˜๋Š”๋ฐ ์–ด๋ ค์›€์„ ๊ฒช์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ์ฝ”๋“œ๋ฅผ ๋‚˜๋ˆ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

func isEmpty() -> Bool {
    return myArray.isEmpty
}

func increase() {
    count += 1
}

์ƒํ™ฉ์— ๋”ฐ๋ผ ์ด๊ฒŒ ๋ฒˆ๊ฑฐ๋กœ์šธ ์ˆ˜๋Š” ์žˆ๋Š”๋ฐ, ์œ ์ง€๋ณด์ˆ˜์— ํฐ ๋„์›€์ด ๋œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

๋””์ž์ธํŒจํ„ด

ํŒฉํ† ๋ฆฌ ํŒจํ„ด

์‹ฌํ”Œ ํŒฉํ† ๋ฆฌ

ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ฃผ์–ด์ง„ type์— ๋”ฐ๋ผ ๊ฐ์ฒด๋ฅผ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ http://ufx.kr/blog/191

์ถ”์ƒ ํŒฉํ† ๋ฆฌ

์ƒํ™ฉ์— ๋”ฐ๋ผ ํŒฉํ† ๋ฆฌ๋ฅผ ๊ฐˆ์•„๋ผ์šฐ๋ฉด์„œ ๊ฒฐ๊ณผ๋ฌผ์„ ๋‹ค๋ฅด๊ฒŒ ์ƒ์„ฑ https://johngrib.github.io/wiki/abstract-factory-pattern/

Mediator

https://ko.wikipedia.org/wiki/%EC%A4%91%EC%9E%AC%EC%9E%90_%ED%8C%A8%ED%84%B4

Architecture

MVC

image

์—ญํ• ๋ถ„๋ฆฌ

  • Model: ๋น„์ฆˆ๋‹ˆ์Šค๋กœ์ง ์ฒ˜๋ฆฌ. ๋ฐ์ดํ„ฐ/์•Œ๊ณ ๋ฆฌ์ฆ˜/๋„คํŠธ์›Œํ‚น
  • View: ๋””์Šคํ”Œ๋ ˆ์ด/์ด๋ฒคํŠธ ์บก์ณ/๋น„์ฃผ์–ผ ํ‘œํ˜„
  • Controller: ์กฐํ•ฉ/๋ธ๋ฆฌ๊ฒŒ์ด์…˜/ํŠน์ดํ•œ ์ž‘์—…

Loose Coupling ์ง€ํ–ฅ

  • ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๋‚ผ ๋•Œ MVC ๊ณ„์ธต์„ ๊ฑด๋„ˆ๋„์ง€ ์•Š๊ธฐ
  • ํ•˜๋‚˜์˜ ์˜ค๋ธŒ์ ํŠธ์— MVC ์—ญํ• ์„ ์„ž์ง€ ์•Š๊ธฐ
  • ๋ทฐ ํด๋ž˜์Šค์—์„œ ๋ชจ๋ธ ๋ฐ์ดํ„ฐ๋ฅผ ์„ ์–ธํ•˜์ง€ ์•Š๊ธฐ

๋ฉ”์„ธ์ง€ ๊ด€๋ฆฌ

  • ๋ชจ๋ธ๋ผ๋ฆฌ ์ง์ ‘์ ์ธ ์–‘๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ์ „์†ก X
  • ๋ชจ๋ธ์—์„œ Notify ํ•  Controller๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ผ ๋•Œ Key-Value Observing ์‚ฌ์šฉ

์ถœ์ฒ˜

MVP

image

์—ญํ• ๋ถ„๋ฆฌ

  • Model: ๋น„์ฆˆ๋‹ˆ์Šค๋กœ์ง ์ฒ˜๋ฆฌ
  • View: UIKit ์š”์†Œ๋“ค. UIView, UIViewController
  • Presenter: Model, View ์‚ฌ์ด์˜ Mediator.

MVC์™€ ๋‹ค๋ฅธ์ 

  • MVC์™€๋Š” ๋‹ค๋ฅด๊ฒŒ Presenter๊ฐ€ View๋ฅผ ์ฐธ์กฐํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • UIView๋ฅผ Presenter๊ฐ€ ์ง์ ‘ ๋‹ค๋ฃจ์ง€ ์•Š๊ณ  Delegate๋ฅผ ํ†ตํ•ด์„œ View ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•  ๋•Œ ์•Œ๋ ค์ฃผ๋Š” ๋ฐฉ๋ฒ•

์ถœ์ฒ˜

Swift

Access Control

https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html

Lazy Stored Properties

view๊ฐ€ load๋œ ํ›„์— ํŠน์ • ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ Optional Type ์‚ฌ์šฉ + viewDidLoad ์—์„œ ํ• ๋‹นํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ

final class ViewController: UIViewController {
    private var model: Model?

    override func viewDidLoad() {
        super.viewDidLoad()
        model = Model()
    }

    func useModel() {
        model?.use()
    }
}

lazy var๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Optional Type์ด ์•„๋‹ˆ๊ณ  ๊ธฐ์กด ์ฒ˜๋Ÿผ ํ•„์š”ํ•œ ์‹œ์ ์— init ๋จ.

final class ViewController: UIViewController {
    private lazy var model: Model = Model()

    func useModel() {
        model.use()
    }
}

Enum

Associated Values

enum์— ๊ฐ’์„ ๋‹ด์•„์„œ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์Œ

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

ํŒจํ„ด ๋งค์นญํ•ด์„œ case๋ฅผ ๋‚˜๋ˆ„๊ณ  Associated Values๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ

switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
    print("UPC: \(numberSystem), \(manufacturer), \(product), \(check).")
case .qrCode(let productCode):
    print("QR code: \(productCode).")
}
// Prints "QR code: ABCDEFGHIJKLMNOP."

https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html

๊ณ ์ฐจํ•จ์ˆ˜

Delegation

  • ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฐ์ฒด๋ฅผ ๊ฐ™์ด ๋‹ด์•„์„œ ๋ณด๋‚ด์ฃผ๋ฉด delegate ๊ตฌํ˜„ํ•  ๋•Œ ํŽธ๋ฆฌํ•จ
  • delegate?.doSomething(self, additional:) ์ด๋Ÿฐ์‹์œผ๋กœ ํ˜ธ์ถœํ•จ
protocol DiceGame {
    var dice: Dice { get }
    func play()
}
protocol DiceGameDelegate: AnyObject {
    func gameDidStart(_ game: DiceGame)
    func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
    func gameDidEnd(_ game: DiceGame)
}
class SnakesAndLadders: DiceGame {
    let finalSquare = 25
    let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
    var square = 0
    var board: [Int]
    init() {
        board = Array(repeating: 0, count: finalSquare + 1)
        board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
        board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
    }
    weak var delegate: DiceGameDelegate?
    func play() {
        square = 0
        delegate?.gameDidStart(self)
        gameLoop: while square != finalSquare {
            let diceRoll = dice.roll()
            delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
            switch square + diceRoll {
            case finalSquare:
                break gameLoop
            case let newSquare where newSquare > finalSquare:
                continue gameLoop
            default:
                square += diceRoll
                square += board[square]
            }
        }
        delegate?.gameDidEnd(self)
    }
}

https://docs.swift.org/swift-book/LanguageGuide/Protocols.html

Naming

Type, Procotocl์€ UpperCamelCase, ๋‚˜๋จธ์ง€๋Š” lowerCamelCase image https://swift.org/documentation/api-design-guidelines/

Weak, Unowned

https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html

Foundation

NotificationCenter

object ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์—ญํ• : ํŠน์ • ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ๋ฐœ์ƒํ•œ ๋…ธํ‹ฐ๋งŒ ํ•„ํ„ฐํ•ด์„œ ์ˆ˜์‹ . ๋งŒ์•ฝ nil ์ด๋ฉด ํ•„ํ„ฐ ์—†์ด ์ˆ˜์‹ . ํ•„ํ„ฐ๋ง์ด ํ•„์š” ์—†์œผ๋ฉด nil๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

anObject The object that sends notifications to the observer. Specify a notification sender to deliver only notifications from this sender.

When nil, the notification center doesnโ€™t use sender names as criteria for delivery.

object ํŒŒ๋ผ๋ฏธํ„ฐ์˜ ์—ญํ• : ๋…ธํ‹ฐ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌ. (sender ๊ฐœ๋…). ์ˆ˜์‹ ํ•˜๋Š” ์ชฝ์—์„œ ๊ตฌ๋ถ„์ด ํ•„์š” ์—†์œผ๋ฉด nil ์ „๋‹ฌํ•ด๋„ ์ •์ƒ์ž‘๋™ํ•จ.

anObject The object posting the notification.

object ์ „๋‹ฌํ•˜๋Š” ์˜ˆ์ œ

extension NSNotification.Name {
    static let modelDidUpdateTitle: NSNotification.Name = .init("didUpdateTitle")
}
class ViewController: UIViewController {

    private lazy var model: Model = Model()

    override func viewDidLoad() {
        NotificationCenter.default.addObserver(self, selector: #selector(didUpdateTitle(_:)), name: .modelDidUpdateTitle, object: model)
    }

    @objc private func didUpdateTitle(_ notification: Notification) {
        guard let updatedTitle = notification.userInfo?["updatedTitle"] as? String else {
            return
        }
        // ์ถ”๊ฐ€ ์ž‘์—… ...
    }

    private func updateTitle() {
        model.update(title: "testTitle")
    }
}
final class Model {
    private var title: String = ""

    func update(title: String) {
        self.title = title
        NotificationCenter.default.post(name: .modelDidUpdateTitle, object: nil, userInfo: ["updatedTitle": title])
    }
}

object์— struct๋ฅผ ๋„ฃ์œผ๋ฉด ์ž‘๋™ํ•˜์ง€ ์•Š์Œ

  • ์ด์œ : https://stackoverflow.com/a/56826646
  • objective-c ์‹œ์ ˆ์— ๋งŒ๋“ค์–ด์ง„ API ์ธ๋ฐ id ํƒ€์ž…์„ Swift๋กœ ๊ฐ€์ ธ์˜ค๋‹ค๋ณด๋‹ˆ Any๋กœ ํฌํŒ…๋จ.
  • ์‹ค์ œ๋กœ๋Š” class๋ฅผ ์ „๋‹ฌํ•ด์ค˜์•ผํ•จ

UIKit

UITouch

UIGestureRecognizer

IBInspectable

IBDesignable + IBInspectable ์‚ฌ์šฉํ•˜๋ฉด ์ธํ„ฐํŽ˜์ด์Šค ๋นŒ๋”์—์„œ Layer ์†์„ฑ๋„ ๊ฐ„ํŽธํ•˜๊ฒŒ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ

image

import UIKit

@IBDesignable extension UIView {
    @IBInspectable var borderColor: UIColor? {
        set {
            layer.borderColor = newValue?.cgColor
        }
        get {
            guard let color = layer.borderColor else {
                return nil
            }
            return UIColor(cgColor: color)
        }
    }
    @IBInspectable var borderWidth: CGFloat {
        set {
            layer.borderWidth = newValue
        }
        get {
            return layer.borderWidth
        }
    }
    @IBInspectable var cornerRadius: CGFloat {
        set {
            layer.cornerRadius = newValue
            clipsToBounds = newValue > 0
        }
        get {
            return layer.cornerRadius
        }
    }
}

https://stackoverflow.com/a/35372610

UIGraphicsImageRenderer

  • ์ด๋ฏธ์ง€๋ฅผ ์ง์ ‘ ๊ทธ๋ฆด ๋•Œ UIGraphicsBeginImageContextWithOptions / UIGraphicsEndImageContext๋กœ Context๋ฅผ ์—ด๊ณ  ๋‹ซ์•„์ค˜์•ผ ํ•จ
let rect = CGRect(origin: .zero, size: size)
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
UIColor.darkGray.setFill()
UIRectFill(CGRect(x: 1, y: 1, width: 140, height: 140))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
  • UIGraphicsImageRenderer๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํด๋กœ์ € ์•ˆ์—์„œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋”ฐ๋กœ ์—ด๊ณ  ๋‹ซ๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ํ•„์š”์—†๋Š” ์žฅ์ ์ด ์žˆ์Œ: ๊ฐ€๋…์„ฑ ์ฆ๊ฐ€, ์‹ค์ˆ˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 200, height: 200))
let image = renderer.image { (context) in
  UIColor.darkGray.setFill()
  context.fill(CGRect(x: 1, y: 1, width: 140, height: 140))
}

https://developer.apple.com/documentation/uikit/uigraphicsimagerenderer

Networking

Http ํ†ต์‹ 

  • NSAllowsArbitraryLoads: ๋ชจ๋“  ๋„๋ฉ”์ธ HTTP ํ†ต์‹  ํ—ˆ์šฉ
  • NSExceptionDomains: ํŠน์ • ๋„๋ฉ”์ธ๋งŒ HTTP ํ†ต์‹  ํ—ˆ์šฉ

Throttle

  • ์—„๋ฐ€ํžˆ ๋งํ•˜๋ฉด ๋„คํŠธ์›Œํฌ๋Š” ์•„๋‹ˆ์ง€๋งŒ ๋„คํŠธ์›Œํฌ ๊ธฐ๋Šฅ๊ณผ ๋ฐ€์ ‘ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Œ https://eunjin3786.tistory.com/80

Xcode

Debugging

About

๐Ÿง ๋ถ€์ŠคํŠธ์บ ํ”„ iOS ๋ฆฌ๋ทฐ์–ด ํ™œ๋™ ๋‚ด์šฉ ์ •๋ฆฌ

Topics

Resources

Stars

Watchers

Forks