๐ŸŒฑ SeSAC

[TIL] 221103

taeeekki 2022. 11. 3. 12:53

- ๋‚ด๊ฐ€ ๋ณด๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจํ•˜๋Š” ํ‚ค์›Œ๋“œ(๋„ˆ๋ฌด ์ž์„ธํ•˜๊ฒŒ ์ ์œผ๋ ค๊ณ  ๋ถ€๋‹ด๊ฐ–์ง€ ๋ง๊ธฐ)
- ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋Š” ๋‚ด์šฉ์ด๋”๋ผ๋„ ์ ๊ณ  ๋‹ค์‹œ ์ƒ๊ฐํ•˜๊ณ  ์˜๋ฌธ์  ๊ฐ–๊ธฐ

1. Alamofire ์ค‘๋ณต ์ฝ”๋“œ ๊ฐœ์„ ํ•˜๊ธฐ

import Foundation

import Alamofire

final class Network {
    
    static let shared = Network()
    private init() {}
}

extension Network {
    func request<T: Decodable>(
        _ type: T.Type = T.self,
        url: URL,
        method: HTTPMethod = .get,
        parameters: [String: String]? = nil,
        headers: HTTPHeaders,
        completion: @escaping (Result<T, Error>) -> Void
    ) {
        AF.request(url, method: .get, parameters: parameters, headers: headers)
            .responseDecodable(of: T.self) { response in
                switch response.result {
                case .success(let data):
                    completion(.success(data))
                case .failure:
                    guard let statusCode = response.response?.statusCode else { return }
                    guard let error = SeSACError(rawValue: statusCode) else { return }
                    
                    completion(.failure(error))
                }
            }
    }
}
  • Generic ๋ฉ”์„œ๋“œ์˜ ์ธ์ž๋กœ ๋“ค์–ด์˜ค๋Š” ๊ฐ’์„ ํ”„๋กœํ† ์ฝœ๋กœ ๋ฌถ์–ด์ฃผ๋ฉด ์–ด๋–จ๊นŒ?
  • https://taekki-dev.tistory.com/23 (URLRequestConvertible ํ”„๋กœํ† ์ฝœ๋กœ ๊ฐœ์„ ํ•ด๋ณผ ์ˆ˜ ์žˆ์Œ, ์˜›๋‚ ์— ์“ด ๊ธ€์ด ์žˆ์—ˆ๋‹ค..)

2. Generic Type

  • Placeholder๋กœ์˜ ์—ญํ• 
  • ๋ชจ๋“  ํƒ€์ž…์ด ๋“ค์–ด์˜ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์ œ์•ฝ์„ ๊ฑธ์–ด์ฃผ๋Š” ๊ฒƒ์ด ํ•„์š”ํ•จ

3. Meta Type

  • ํƒ€์ž…์˜ ํƒ€์ž…
  • ํƒ€์ž… ์ž์ฒด๋ฅผ ๊ฐ€๋ฆฌ์ผœ์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์กด์žฌ
  • ํƒ€์ž…์ด๋ž€ ๋ฉ”ํƒ€ํƒ€์ž…์˜ ์ธ์Šคํ„ด์Šค

4. Escaping Closure/Auto Closure

5. Result Type

  • ๋„คํŠธ์›Œํฌ ํ†ต์‹  ์ˆ˜ํ–‰์˜ ๊ฒฐ๊ณผ๋Š” ์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๊ฒจ๋‚œ ํƒ€์ž…์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
@frozen public enum Result<Success, Failure> where Failure : Error {

    /// A success, storing a `Success` value.
    case success(Success)

    /// A failure, storing a `Failure` value.
    case failure(Failure)
}
  • @Frozen : ์ผ€์ด์Šค๊ฐ€ ๋”์ด์ƒ ์ถ”๊ฐ€๋˜์ง€ ์•Š์„ ๊ฒƒ์„ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ ์•Œ๋ ค์„œ ์„ฑ๋Šฅ ํ–ฅ์ƒ

6. Error

  • Error๋Š” Sendable์„ ์ฑ„ํƒํ•˜๋Š” ํ”„๋กœํ† ์ฝœ ํƒ€์ž…์ด๋‹ค.
  • ์ผ๋ฐ˜์ ์œผ๋กœ ํ†ต์‹ ์‹œ์— ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ์˜ ์ข…๋ฅ˜๋Š” ๋‹ค์–‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, Error๋ฅผ ์ฑ„ํƒํ•˜์—ฌ Customํ•œ Errorํƒ€์ž…์„ ์ •ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ์—ด๊ฑฐํ˜•๊ณผ ์—ฎ์–ด์„œ ์‚ฌ์šฉํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฒ”์šฉ์ ์œผ๋กœ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์—๋Ÿฌ๋„ ์ถ”๊ฐ€ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. (Offline ์ƒํƒœ)
enum SeSACError: Int, Error {
    case invalidAuthorization = 401
    case takenEmail = 406
    case emptyParameters = 501
}

extension SeSACError: LocalizedError {
    var errorDescription: String? {
        switch self {
        case .invalidAuthorization:
            return "ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์‹œ ๋กœ๊ทธ์ธ ํ•ด์ฃผ์„ธ์š”."
        case .takenEmail:
            return "์ด๋ฏธ ๊ฐ€์ž…๋œ ํšŒ์›์ž…๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ ํ•ด์ฃผ์„ธ์š”."
        case .emptyParameters:
            return "ํ•„์š”ํ•œ ์ •๋ณด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."
        }
    }
}
guard let error = SeSACError(rawValue: statusCode) else { return }

7. ์บ์‹œ

  • shorturl.at/ryY05

์บ์‹œ ์ข…๋ฅ˜

์†๋„์™€ ์šฉ๋Ÿ‰ ์ธก๋ฉด์—์„œ ์ฐจ์ด๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ ์ ˆํ•œ ์‚ฌ์šฉ ํ•„์š”
  • ์บ์‹œ ๋ฉ”๋ชจ๋ฆฌ(๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ)
  • ๋””์Šคํฌ ์บ์‹œ

8. RxSwift

  • Single Traits : ๊ฐœ๋… ์ž์ฒด๋Š” ์–ด๋ ต์ง€ ์•Š๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ตฌ์กฐ์ ์ธ ์ธก๋ฉด์—์„œ ํ™œ์šฉํ•˜๋Š”๊ฒŒ ๊ฐ์ด ์ž˜ ์•ˆ์™€์„œ ์ข€ ํ—ค๋งธ๋‹ค.
  • subscribe, bind, drive
  • Driver vs Signal

9. Copy on Write (CoW)

  • ์‹ค์ œ ๊ฐ’์˜ ์ˆ˜์ • ๋˜๋Š” ์‚ญ์ œ ๋“ฑ ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค.
  • Collection ํƒ€์ž…(Array, Dictionary, Set)์— ๋Œ€ํ•ด์„œ ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ œ๊ณต
// ํฌ์ธํ„ฐ ์ฃผ์†Œ๋ฅผ ์•Œ์•„๋ณด์ž
func address(_ value: UnsafeRawPointer) {
    let address = String(format: "%p", Int(bitPattern: value))   // pointer ์ถ”์ 
    print(address)
}

10. ์„œ๋ธŒ์Šคํฌ๋ฆฝํŠธ(Subscript)

  • ํŠน์ • ๋ฉค๋ฒ„ ์—˜๋ฆฌ๋จผํŠธ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ๋ฌธ๋ฒ•
  • ์ปฌ๋ ‰์…˜์— ๊ธฐ๋ณธ ๊ตฌํ˜„์ด ๋˜์–ด ์žˆ์Œ
  • String์—์„œ ์“ฐ๋ฉด ์œ ์šฉํ•  ๊ฒƒ์œผ๋กœ ์ƒ๊ฐํ•จ(ํŠนํžˆ ์ฝ”ํ…Œ)
extension String {
    
    // "abcde" >>> [1] >>> b
    subscript(idx: Int) -> String? {
        guard (0..<count).contains(idx) else {
            return nil // early exit
        }
        
        let result = index(startIndex, offsetBy: idx)
        return String(self[result])
    }
}

11. ETC

  • ARC
  • final, AnyObject
  • ์ ‘๊ทผ์ œ์–ด
  • ๊ฐ•์ œํ•ด์ œ ์—ฐ์‚ฐ์ž ์ง€์–‘
  • ์•ˆ์“ฐ๋Š” ์ฝ”๋“œ, ํŒŒ์ผ ์ œ๊ฑฐ(print, ์ฃผ์„, storyboard ๋“ฑ)
  • Appearance
    • ํ˜ธ์ถœํ•œ ์‹œ์ ๋ถ€ํ„ฐ ๋ชจ๋“  ๊ณณ์— ์ ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์—, AppDelegate or SceneDelegate์—์„œ ํ˜ธ์ถœํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Available(*, unavailable)
  • DTO
    • ์›๋ณธ ๋ฐ์ดํ„ฐ์™€ ํ™”๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.