Giter Club home page Giter Club logo

customkeyboard's Introduction

๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ ํŒ€์› ์†Œ๊ฐœ

UY ์šฐ์ง€


๐Ÿ–ฅ ํ”„๋กœ์ ํŠธ ์†Œ๊ฐœ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๋ช…

  • ์„œ๋ฒ„ API๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ฆฌ๋ทฐ ๋ชฉ๋ก์„ ๊ฐ€์ ธ์˜ค๊ณ , ์ƒˆ๋กœ์šด ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ํ™”๋ฉด์— ํ‚ค๋ณด๋“œ ์žํŒ ๋ฒ„ํŠผ๋“ค์„ ๋ฐฐ์น˜ํ•ด์„œ, ๋ˆ„๋ฅด๋ฉด ํ•œ๊ธ€ ํ‚ค๋ณด๋“œ์ฒ˜๋Ÿผ ์กฐํ•ฉ๋˜๋Š” ํ•œ๊ธ€ ์ฟผํ‹ฐ ํ™”๋ฉด์„ ๊ตฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Keyboard Extension์„ ์ด์šฉํ•˜์—ฌ ์‹ค์ œ ํ•œ๊ธ€ ํ‚ค๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ด…๋‹ˆ๋‹ค.

์‹คํ–‰ ํ™”๋ฉด

์•ฑ ์ง„์ž…๊ณผ ๋ฆฌ๋ทฐ ๋ชฉ๋ก ๋ฆฌ๋ทฐ ์ž‘์„ฑ ํ‚ค๋ณด๋“œ ์ž…๋ ฅ ๋ฆฌ๋ทฐ ์ž‘์„ฑ ์™„๋ฃŒ์™€ ํฌ์ŠคํŒ… ๋น„์–ด ์žˆ๋Š” ๋ฆฌ๋ทฐ ๊ฒฝ๊ณ 
Simulator Screen Recording - iPhone 11 - 2022-07-23 at 12 24 23 Simulator Screen Recording - iPhone 11 - 2022-07-23 at 12 24 39 Simulator Screen Recording - iPhone 11 - 2022-07-23 at 12 25 12 Simulator Screen Recording - iPhone 11 - 2022-07-23 at 12 59 06 Simulator Screen Recording - iPhone 11 - 2022-07-23 at 12 34 43


โฑ๏ธ ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„ ๋ฐ ์‚ฌ์šฉ ๊ธฐ์ˆ 

  • ๊ฐœ๋ฐœ ๊ธฐ๊ฐ„: 2022.07.11 ~ 2022.07.23 (2์ฃผ)
  • ์‚ฌ์šฉ ๊ธฐ์ˆ : UIKit, URLSession, ExtensionKeyboard, NSCache, MVC


๐Ÿ–ผ ๋””์ž์ธ ํŒจํ„ด

MVVM? MVC?

  • MVC๋ฅผ ์„ ํƒํ•œ ์ด์œ 
  1. ๊ทœ๋ชจ๊ฐ€ ํฌ์ง€ ์•Š์€ ํ”„๋กœ์ ํŠธ์—์„œ ๋ณด์—ฌ์ค„ ๋ทฐ์˜ ์ˆ˜๊ฐ€ ๋งŽ์ง€ ์•Š์Œ

  2. ๊ธฐ๋Šฅ์˜ ์ง๊ด€์ ์ธ ๋ถ„๋ฆฌ

  3. ๋ชจ๋“ˆํ™”๋ฅผ ํ†ตํ•œ VC์˜ ์ฑ…์ž„ ๋ถ„์‚ฐ -> ๊ธฐ์กด MVC์˜ ๋‹จ์  ํ•ด์†Œ



๐Ÿ“Œย ํ•ต์‹ฌ ๊ธฐ์ˆ 

  • ํ•œ๊ธ€ ํ‚ค๋ณด๋“œ?

    ์˜์–ด์™€ ํ•œ๊ธ€์˜ ์ฐจ์ด - ์กฐํ•ฉํ˜•์ธ๊ฐ€ ๋‚˜์—ดํ˜•์ธ๊ฐ€?
    => ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ๋งŒ๋“ค์–ด ์กฐํ•ฉํ•˜์ž!!

  • Keyboard Automata

    ํ•ต์‹ฌ - stage์— ๋”ฐ๋ฅธ ์กฐํ•ฉ

struct HangulKeyboardData {
    
    enum HangulState: Int {
        case empty = 0
        case cho = 1
        case doubleCho = 2
        case jung = 3
        case doubleJung = 4
        case jong = 5
        case doubleJong = 6
    }
    
    var hangul: String = ""
    var unicode: Int = 0
    var bornState: HangulState = .empty
    
    ...
}
switch processingBuffer.currentState {
        case .empty:
            processingBuffer = emptyStage(status: processingBuffer, input: inputData)
        case .cho:
            processingBuffer = singleChoStage(status: processingBuffer, input: inputData)
        case .doubleCho:
            processingBuffer = doubleChoStage(status: processingBuffer, input: inputData)
        case .jung:
            processingBuffer = singleJungStage(status: processingBuffer, input: inputData)
        case .doubleJung:
            processingBuffer = doubleJungStage(status: processingBuffer, input: inputData)
        case .jong:
            processingBuffer = singleJongStage(status: processingBuffer, input: inputData)
        case .doubleJong:
            processingBuffer = doubleJongStage(status: processingBuffer, input: inputData)
        }
 func [์Œ์†Œ๋ณ„ ์Šคํ…Œ์ด์ง€] (ํ˜„์žฌ ์Šคํ…Œ์ด์ง€, ํ‚ค๋ณด๋“œ ์ž…๋ ฅ) -> ์ƒํƒœ๊ฐ’[ํ˜„์žฌ์ƒํƒœ, ๊ธ€์ž๋ฐฐ์—ด, ๋ชจ๋“œ] {
 
 	...
 
        alphaRepository.append(๋“ค์–ด์˜จ ํ‚ค๋ณด๋“œ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€)

        if ์ž…๋ ฅ๊ฐ’์ด ์ดˆ์„ฑ์ธ์ง€ ์ค‘์„ฑ์ธ์ง€ ์ข…์„ฑ์ธ์ง€ {
	
	...
	
	์ƒํƒœ.๋ชจ๋“œ = ์ด์ค‘ ์ž๋ชจ or ์™„๋ฃŒ์—ฌ๋ถ€
	์ƒํƒœ.์Šคํ…Œ์ด์ง€ = ๋“ค์–ด์˜จ ํ‚ค๋ณด๋“œ ๋ฐ์ดํ„ฐ์— ๋”ฐ๋ผ ๋‹ค์Œ ์ด๋™ ํ•  stage๊ฐ€ ๊ฒฐ์ •๋œ๋‹ค
	
	...
	
	}
            
        if ์‚ญ์ œ ์ธ์ง€ {
	๋ชจ๋“œ = ์‚ญ์ œ
	}
        return currentStatus
    }


๐Ÿ“–ย DataFlow

CustomKeyboard



โš ๏ธ ์ด์Šˆ

  • URLSession Network Layer์— ๊ด€ํ•œ ๊ณ ๋ฏผ

โ†’ ๋„คํŠธ์›Œํฌ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๋•Œ ํšจ์œจ์ ์ธ network layer๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„์ง€์— ๋Œ€ํ•œ ๊ณ ๋ฏผ๊ณผ ์—๋Ÿฌ ๋ฐ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ
โ†’ ์—ฌ๋Ÿฌ ์‹œ๋„ ํ›„ URL, NetworkError, HTTPMethod, URLSession, URLRequest, API, Resource ๋“ฑ์œผ๋กœ ๋‚˜๋ˆ„์–ด ๊ตฌํ˜„
โ†’ ConstanURLย : โ€œGETโ€, โ€œPOSTโ€ ํ†ต์‹ ์„ ํ•˜๋Š” URL ๋“ฑ์„ ์ง€์ •ํ•˜๋Š” ๋ณ„๋„ ํŒŒ์ผ
โ†’ NetworkError : ๋„คํŠธ์›Œํฌ ๋ฐ ์„œ๋น„์Šค ๊ด€๋ จ ์„ค์ •ํ•œ ์—๋Ÿฌ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒ์„ฑ
โ†’ Resource : Encodable, Decodable type์„ Genericํ•˜๊ฒŒ ์ž…๋ ฅ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์ƒ์„ฑ
โ†’ HTTPMethod : HTTPMethod๋ฅผ enum type ์œผ๋กœ ์ „๋‹ฌ
โ†’ URLSession : URLSession์˜ request๋ฅผ Resource์— ๋งž์ถฐ requestํ•  ์ˆ˜ ์žˆ๋„๋ก, upload, load ํ•จ์ˆ˜ ์ƒ์„ฑ
โ†’ API : Singleton ๋ฐฉ์‹์œผ๋กœ API ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๊ณ  ํ†ต์‹ ์„ ์‹œ๋„ํ•˜๋Š” ๊ฐ์ฒด
โ†’ ํ˜„์žฌ URL์ด ์ ์–ด URL์ฃผ์†Œ ์ „์ฒด๋ฅผ ์ ์šฉํ–ˆ์œผ๋‚˜ ์ถ”ํ›„ ๋งŽ์€ ์–‘์˜ URL์ฃผ์†Œ๊ฐ€ ์žˆ์„ ์‹œ 
  URL์„ scheme, host, path, parameter(questyString) ๋“ฑ์œผ๋กœ ๋‚˜๋ˆ„์–ด ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์ ์šฉํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์Œ

  • Data(contentsOf: url?)์— ๊ด€ํ•œ ๊ณ ๋ฏผ

โ†’ ์ฒ˜์Œ ๋„คํŠธ์›Œํฌ ๊ตฌํ˜„ ์‹œ init(contesntsOf: url)๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ
โ†’ init(contesntsOf: url) ๋ฉ”์†Œ๋“œ๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์ž‘๋™ํ•ด ํ˜„์žฌ ์ž‘์—…์ค‘์ธ ์Šค๋ ˆ๋“œ์˜ ๋ชจ๋“  ์ž‘์—…์„ ํ•ด๋‹น ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์•ˆ ๋ฉˆ์ถ”๊ฒŒํ•  ์œ„ํ—˜์ด ์žˆ์–ด 
  DispatchQueue.global().async๋ฅผ ํ†ตํ•ด ์Šค๋ ˆ๋“œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋„ GCD์˜ ์ œํ•œ๋œ ์ž‘์—…์Šค๋ ˆ๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋ฌถ๋Š” ๊ฒƒ์ด ๋˜์–ด ์ง์ ‘์ ์ด์ง„ ์•Š์•„๋„ 
  ๊ฐ„์ ‘์ ์œผ๋กœ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์–ด ๊ถŒ์žฅํ•˜์ง€ ์•Š์Œ
โ†’ URLSession์—์„œ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜์ธ์ง€, HTTP ์˜ค๋ฅ˜์ธ์ง€, contents ์˜ค๋ฅ˜ ์ธ์ง€ ๋“ฑ์„ ํŒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ˜๋ฉด 
  init(contentsOf:)์—์„œ๋Š” ์ด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Œ
โ†’ URLSession์œผ๋กœ ๋ณ€๊ฒฝ

  • Cell ์žฌ์‚ฌ์šฉ ๋ฌธ์ œ

    • TableView Cell ์žฌ์‚ฌ์šฉ์œผ๋กœ ์ธํ•ด ์Šคํฌ๋กค ์‹œ ์ด๋ฏธ์ง€๊ฐ€ ๋งž์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋ฐœ์ƒ
    • prepareForReuse() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ˆ˜์ •
override func prepareForReuse() {
		profileImageView.image = UIImage(systemName: "person.crop.circle.fill")
}

  • ํ‚ค๋ณด๋“œ ์ต์Šคํ…์…˜ - textDocumentProxy

๋Œ€๋ถ€๋ถ„์˜ ์™ธ๊ตญ์–ด๋Š” ๊ธ€์ž๋ฅผ ์กฐํ•ฉํ•˜๋Š”๊ฒŒ ์•„๋‹Œ ๋‚˜์—ด ํ•˜๋Š” ํ˜•์‹์ด๋‹ค. 
UIInputViewContoller์˜ textDocumentProxy๋Š” ํ‚ค๋ณด๋“œ์˜ ๊ธ€์ž๋ฅผ ์ž…๋ ฅ ๋ฐ›์•„ UIKeyInput ํ”„๋กœํ† ์ฝœ์—์„œ ์ œ๊ณตํ•˜๋Š” inserText ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ €์žฅํ•œ๋‹ค.
์ด ๋•Œ๋ฌธ์— ์ง์ ‘์ ์ธ text์ €์žฅ์†Œ์— ์ ‘๊ทผ์€ ๋ถˆ๊ฐ€ํ•˜๋ฉฐ, ์˜ค๋กœ์ง€ insert ๋˜๋Š” delete๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
๋•Œ๋ฌธ์— ๊ธฐ์กด text๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“  text๋กœ ๋Œ€์ฒดํ•˜๋˜ ๋ฐฉ์‹์˜ ์˜คํ† ๋งˆํƒ€๋กœ keyboard extension์„ ๊ตฌํ˜„ํ•  ๊ฒฝ์šฐ text๊ฐ€ ์ค‘๋ณต๋˜์–ด ์Œ“์ด๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒ ํ–ˆ๋‹ค.

- ํ•ด๊ฒฐ

์˜คํ† ๋งˆํƒ€๋ฅผ ์ด์— ๋งž๊ฒŒ ์ˆ˜์ •ํ•˜์—ฌ ํ‚ค๋ณด๋“œ๋ฅผ ์ž…๋ ฅ ๋ฐ›์„๋•Œ ๋งˆ๋‹ค ์ด์— ๋งž๊ฒŒ ๊ธฐ์กด์— ์žˆ๋Š” ๊ธ€์ž๋ฅผ ์ง€์šฐ๊ณ  ์ƒˆ๋กœ์šด ๊ธ€์ž๋ฅผ ์‚ฝ์ž… ํ•ด์ค„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, 
textDocumentProxt์˜ hasText๋ฅผ ํ†ตํ•ด ๊ธ€์ž๋ฅผ ์ง€์šดํ›„ ์ถœ๋ ฅ ๋˜๋Š” text๋ฅผ ๋‹ค์‹œ ์‚ฝ์ž…ํ•ด์ฃผ๋Š” ๋ฐฉ์‹์„ ์ฑ„ํƒํ–ˆ๋‹ค.
while textDocumentProxy.hasText {
            textDocumentProxy.deleteBackward()
        }

Simulator Screen Recording - iPhone 11 Pro - 2022-07-22 at 17 48 37 Simulator Screen Recording - iPhone 11 Pro - 2022-07-22 at 17 52 29


  • ํ‚ค๋ณด๋“œ ์˜คํ† ๋งˆํƒ€ : ์‚ญ์ œ ๊ธฐ๋Šฅ

์˜คํ† ๋งˆํƒ€์˜ ๊ธฐ์กด ๋ฐฐ์—ด์—์„œ์˜ ์ข…์„ฑ๊ณผ ์ด์ค‘์ข…์„ฑ์„ ๊ตฌ๋ณ„ํ•  ์ˆ˜ ์—†์–ด ์‚ญ์ œ์— ์–ด๋ ค์›€์„ ๊ฒช๊ณ  ์žˆ๋˜ ๋„์ค‘ ๋ชจ๋“  ์Œ์†Œ๋ฅผ ์ €์žฅ ํ•  ๋ฐฐ์—ด์„ ํ•˜๋‚˜ ๋” ์ถ”๊ฐ€ํ•˜์—ฌ
์™„์„ฑ๋œ ํ•œ๊ธ€์„ ๋ถ„ํ•ดํ•˜์—ฌ ๋น„๊ต๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐ ํ•˜์˜€๋‹ค.

[ํ•œ๊ธ€ ์˜คํ† ๋งˆํƒ€ ๊ตฌํ˜„ ์ฝ”๋“œ] https://github.com/ScutiUY/ios-wanted-CustomKeyboard/blob/fix/automata/CustomKeyboard/Hangul/KeyboardMaker.swift



๐Ÿ’ผ ๋ฆฌํŒฉํ† ๋ง

  • ์ด๋ฏธ์ง€๋กœ๋” Data(contentsOf: url?) โ†’ URLsession ์œผ๋กœ ๋ณ€๊ฒฝ
// ๋ณ€๊ฒฝ ์ „
if let data = try? Data(contentsOf: imageUrl) {
                guard let image = UIImage(data: data) else { return }
                self.imageCache.setObject(image, forKey: imageUrl.lastPathComponent as NSString)
                DispatchQueue.main.async {
                    complition(.success(image))
								} else {
                DispatchQueue.main.async {
                    complition(.failure(ImageLoaderError.noImage))
								}
// ๋ณ€๊ฒฝ ํ›„
guard let imageUrl = URL(string: url) else { return }
            let session = URLSession(configuration: .ephemeral)
            let task = session.dataTask(with: imageUrl) { data, response, error in
                if let error = error {
                    completion(.failure(NetworkError.networkError(error)))
                } else {
								guard let httpResponse = response as? HTTPURLResponse else { return }
                guard 200..<300 ~= httpResponse.statusCode else { completion(.failure(SevericeError.noReponseError))
                    return
                }
                if let data = data {
                    guard let image = UIImage(data: data) else { return }
                    ImageLoder.imageCache.setObject(image, forKey: url as NSString)
                    DispatchQueue.main.async {
                        completion(.success(image))
                    }
                } else {
                    DispatchQueue.main.async {
                        completion(.failure(NetworkError.invalidData))
                    }
                }

  • UIImage ๊ด€๋ จ string โ†’ enum Type ์œผ๋กœ ๊ด€๋ฆฌ ๋ฐ ๋ณ€๊ฒฝ
// ๋ณ€๊ฒฝ ์ „
profileImageVIew.image = UIImage(systemName: "person.crop.circle.fill")
// ๋ณ€๊ฒฝ ํ›„
profileImageVIew.image = Icon.personFill.image

  • ๋ฆฌ๋ทฐ ์‹œ๊ฐ„๋ณ€ํ™˜ Cell์—์„œ ๊ตฌํ˜„ โ†’ Class ๊ฐ์ฒด ๋ฐ ๋ฐ์ดํ„ฐ๋ชจ๋ธ์—์„œ ๋ณ€๊ฒฝ
// ๋ณ€๊ฒฝ ์ „
// ReviewTableViewCell.swift
guard let reviewDate = data.createdAt.stringToDate else { return }
        if reviewDate > Date(timeIntervalSinceNow: -86400) {
            timeLabel.text = reviewDate.dateToRelativeTimeString
        } else {
            timeLabel.text = reviewDate.dateToOverTimeString
        }
// ๋ณ€๊ฒฝ ํ›„
// ReviewDateConverter.swift
class ReviewDateConverter {
    
    func convertReviewDate(rawData: String) -> String {
        if rawData.stringToDate ?? Date() > Date(timeIntervalSinceNow: -86400) {
            return rawData.stringToDate?.dateToRelativeTimeString ?? rawData
        } else {
            return rawData.stringToDate?.dateToOverTimeString ?? rawData
        }
    }
}

// ReviewData.swift
let date = try values.decode(String.self, forKey: .createdAt)
createdAt = ReviewDateConverter().convertReviewDate(rawData: date)

customkeyboard's People

Contributors

scutiuy avatar wooooozin avatar

Forkers

wooooozin

customkeyboard's Issues

image caching

๊ธฐ๋Šฅ ์„ค๋ช…

ํ…Œ์ด๋ธ” ๋ทฐ ์ด๋ฏธ์ง€ ์บ์‹ฑ

์™„๋ฃŒ ์กฐ๊ฑด

  • ์บ์‹ฑ

Image Loader

๊ธฐ๋Šฅ ์„ค๋ช…

์ด๋ฏธ์ง€ url์„ ๋ฐ›์•„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ณ  ์บ์‹ฑ์„ ํ•˜๋Š” ๊ธฐ๋Šฅ

์™„๋ฃŒ ์กฐ๊ฑด

  • Image data ํ†ต์‹ 
  • ์บ์‹ฑ

Data Model

๊ธฐ๋Šฅ ์„ค๋ช…

๋””์ฝ”๋”ฉ ํ•  ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ๊ตฌํ˜„

์™„๋ฃŒ ์กฐ๊ฑด

  • ๋ฐ์ดํ„ฐ ๋ชจ๋ธ ๊ตฌํ˜„

๋ฆฌ๋ทฐ ์ž‘์„ฑ ์™„๋ฃŒ

๊ธฐ๋Šฅ ์„ค๋ช…

๋ฆฌ๋ทฐ ์ž‘์„ฑ ์™„๋ฃŒ์‹œ ๋ฐ์ดํ„ฐ ํŒจ์นญ๊ณผ ๋ทฐ reload

์™„๋ฃŒ ์กฐ๊ฑด

  • data fetching
  • tableView update

Create Review Scene

๊ธฐ๋Šฅ ์„ค๋ช…

ํ‚ค๋ณด๋“œ๋ฅผ ๊ตฌํ˜„ํ•  Create Review scene ๊ตฌํ˜„

์™„๋ฃŒ ์กฐ๊ฑด

  • textView ๊ตฌํ˜„
  • ํ‚ค๋ณด๋“œ์—์„œ return ํ‚ค๊ฐ€ ๋ˆŒ๋ ธ์„๋•Œ dissmiss
  • customKeyboardView์™€ ์—ฐ๊ฒฐ

Custom keyboard View์™€ Create Review VC ์—ฐ๊ฒฐ

๊ธฐ๋Šฅ ์„ค๋ช…

view์—์„œ์˜ input๊ณผ ํ•œ๊ธ€ ํ‚ค๋ณด๋“œ ์˜คํ† ๋งˆํƒ€๋ฅผ ํ†ตํ•ด ๋ณ€ํ™˜๋œ String์„ VC์™€ ์—ฐ๊ฒฐ

์™„๋ฃŒ ์กฐ๊ฑด

  • keyboardMaker ์ธ์Šคํ„ด์Šค
  • ์˜คํ† ๋งˆํƒ€ ํ†ตํ•œ String ์ถœ๋ ฅ

ReviewTableView ๊ตฌํ˜„

๊ธฐ๋Šฅ ์„ค๋ช…

Review list๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ํ…Œ์ด๋ธ” ๋ทฐ ๊ตฌํ˜„

์™„๋ฃŒ ์กฐ๊ฑด

  • template cell
  • header cell
  • data fetching
  • modal present
  • cell review Date

Custom keyboard View - layout

๊ธฐ๋Šฅ ์„ค๋ช…

custom keyboard view ๊ตฌํ˜„

์™„๋ฃŒ ์กฐ๊ฑด

  • ํ‚ค๋ณด๋“œ ๋ ˆ์ด์•„์›ƒ ๋ฐฐ์น˜
  • ํ‚ค๋ณด๋“œ ๋ทฐ์™€ ์—ฐ๊ฒฐ ํ›„ ๊ธฐ๋Šฅ ๊ตฌํ˜„

ํ‚ค๋ณด๋“œ ์˜คํ† ๋งˆํƒ€ ๋„์–ด์“ฐ๊ธฐ ํ•œ ํ›„ ์‚ญ์ œ ์‹œ ๊ธฐ๋Šฅ

๊ธฐ๋Šฅ ์„ค๋ช…

ํ‚ค๋ณด๋“œ ์ž…๋ ฅ์ค‘ ๋„์–ด์“ฐ๊ธฐ๊ฐ€ ๋“ค์–ด ์™”์„๋•Œ ์‚ญ์ œ๊ฐ€ ์ž…๋ ฅ ๋˜๋ฉด ์Œ์†Œ๋ฅผ ์ง€์šฐ๋Š”๊ฒŒ ์•„๋‹Œ ๊ธ€์ž ์ „์ฒด๋ฅผ ์ง€์šฐ๋Š” ๊ธฐ๋Šฅ

์™„๋ฃŒ ์กฐ๊ฑด

  • ๊ธฐ๋Šฅ ๊ตฌํ˜„

ํ•œ๊ธ€ custom keyboard ์˜คํ† ๋งˆํƒ€ ๊ตฌํ˜„

๊ธฐ๋Šฅ ์„ค๋ช…

๊ฐ ํ•œ๊ธ€์„ ๋ฐ›์•„ ์œ ๋‹ˆ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์กฐํ•ฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๋Š” ์˜คํ† ๋งˆํƒ€ ๊ตฌํ˜„

์™„๋ฃŒ ์กฐ๊ฑด

  • ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • ๊ธฐ๋Šฅ ํด๋ž˜์Šค ๊ตฌํ˜„

Network ํ†ต์‹  ๊ตฌํ˜„

๊ธฐ๋Šฅ ์„ค๋ช…

์„œ๋ฒ„์™€ ๋ฐ์ดํ„ฐ ํ†ต์‹ ์„ ํ•  ์ˆ˜ ์žˆ๋Š” ๋„คํŠธ์›Œํฌ ๊ตฌํ˜„

์™„๋ฃŒ ์กฐ๊ฑด

  • ๋ ˆ์ด์–ด๋‚˜๋ˆ„๊ธฐ
  • url to Data

Data decoding repository

๊ธฐ๋Šฅ ์„ค๋ช…

ํ†ต์‹ ํ•˜์—ฌ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๋ณด๋‚ผ ๋ฐ์ดํ„ฐ๋ฅผ Decoding

์™„๋ฃŒ ์กฐ๊ฑด

๋ฐ์ดํ„ฐ Decoding

  • Decoding repository ๊ตฌํ˜„

keyboard automata ๊ธฐ๋Šฅ ๋ถ„๋ฆฌ

๊ธฐ๋Šฅ ์„ค๋ช…

๊ธฐ๋Šฅ์„ ๋‚˜๋ˆ„์–ด ๋ฆฌํŒฉํ† ๋ง

์™„๋ฃŒ ์กฐ๊ฑด

  • KeyboardData
  • KeyboardManager
  • Converter
  • IO์ฒ˜๋ฆฌ
  • validator

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.