๊ณต๋ถ€ ์—ฐ์Šต์žฅ :-)

TIL_20180805 ~ 20180812

|

2018.08.05

์ฃผ๋ง

  • RxSwift!!!!!1-3์ฑ•ํ„ฐ ๊ณต๋ถ€ ๋ณต์Šต
  • Letโ€™Swift ์ตœ์™„๋ณต RxSwift

  • ์งˆ๋ฌธ๊ฑฐ๋ฆฌ
    • scrollview์— subview๋กœ ์ด๋ฏธ์ง€๋ฅผ ์ถ”๊ฐ€ํ• ๋•Œ๋„ scrollview์˜ frame.origin๊ณผ ๋˜‘๊ฐ™์ด ์ถ”๊ฐ€ํ•ด์ค˜์•ผํ•˜๋Š”๊ฑด๊ฐ€? ์˜ˆ๋ฅผ๋“ค๋ฉด origin.y๊ฐ€ 0์œผ๋กœ ์„ค์ •๋˜๋ฉด ์Šคํฌ๋กค๋ทฐ ์˜ frame์œ„์น˜์— ๋”ฐ๋ผ์„œ ์œ„์น˜๋˜๋Š”์ง€
  • ์„œ๋ฒ„๊ฐ€ ๋ฌธ๋‹ซ๊ณ ๋‚˜์„œ ์š”์ฒญํ•˜๋ฉด json์œผ๋กœ ํŒŒ์‹ฑ๋˜๊ฒŒํ–ˆ๋Š”๋ฐ๋ฐ timeout์œผ๋กœ ์—๋Ÿฌ๋‚˜๊ณ  dataTask.resume()์š”์ฒญ ๋ณด๋ƒˆ๋‹ค๊ฐ€ ์•ฑ ๋กœ์ง์ด ๋”์ด์ƒ ์ง„ํ–‰๋˜์ง€ ์•Š๋Š”๊ฑธ๋กœ ๋ณด์ด๋‹ค๊ฐ€ ์ผ์ •์‹œ๊ฐ„ ์ง€๋‚˜๊ณ ๋‚˜์„œ error๋ธ”๋Ÿญ์œผ๋กœ ํƒ
  • ๋น„๋™๊ธฐ๋กœ ์š”์ฒญ์„ ์ญ‰ ๋ณด๋‚ด๋†”์„œ timeout๊ธฐ์ค€ ์‹œ๊ฐ„ ์ง€๋‚˜๊ณ  error๋ธ”๋Ÿญ ํƒ„๋“ฏ
  • error๋ธ”๋Ÿญ์—์„œ ์งœ๋†“์€๋Œ€๋กœ ๋กœ์ปฌ์˜ jsonํŒŒ์ผ๋กœ ํ…Œ์ด๋ธ”๋ทฐ์…€์˜ ์ •๋ณด ๋ฐ›์•„์™€์„œ ํ‘œ์‹œํ•˜๋Š” ์ค‘ ๋งˆ์ง€๋ง‰ ์นดํ…Œ๊ณ ๋ฆฌ๊นŒ์ง€ json์œผ๋กœ ํ‘œ์‹œํ•˜๋˜์ค‘(ํ™•์‹ค์น˜์•Š์Œ) ์•ฑ ์ฃฝ์–ด๋ฒ„๋ฆผ
  • ํƒ€์ž„์•„์›ƒ์‹œ๊ฐ„๋™์•ˆ ๊ณ„์† ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ ์žˆ์—ˆ์„๊ฒƒ์œผ๋กœ ์ถ”์ •.
2018-08-02 00:27:16.479396+0900 StoreApp[20099:888781] Task <887E6A12-0A54-4B07-B1F6-6DF0ED0857EF>.<1> finished with error - code: -1001
2018-08-02 00:27:16.493938+0900 StoreApp[20099:888781] Task <D1A56284-7F25-4C01-93AE-90353BC268E2>.<2> finished with error - code: -1001
2018-08-02 00:27:33.895061+0900 StoreApp[20099:888781] Task <28FBBC7F-9930-4104-800C-978099688827>.<3> finished with error - code: -1001
2018-08-02 00:27:33.932263+0900 StoreApp[20099:890156] Task <887E6A12-0A54-4B07-B1F6-6DF0ED0857EF>.<1> HTTP load failed (error code: -999 [1:89])
Network error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x60400025de80 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=http://crong.codesquad.kr:8080/woowa/main, NSErrorFailingURLKey=http://crong.codesquad.kr:8080/woowa/main, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}

2018-08-02 00:27:34.709532+0900 StoreApp[20099:890156] Task <D1A56284-7F25-4C01-93AE-90353BC268E2>.<2> HTTP load failed (error code: -999 [1:89])
2018-08-02 00:27:34.713188+0900 StoreApp[20099:890156] Task <28FBBC7F-9930-4104-800C-978099688827>.<3> HTTP load failed (error code: -999 [1:89])
DataTask error: response

2018-08-02 00:27:47.118190+0900 StoreApp[20099:888727] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.54.4/UITableView.m:2012
2018-08-02 00:27:47.128271+0900 StoreApp[20099:888727] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (8) must be equal to the number of rows contained in that section before the update (8), plus or minus the number of rows inserted or deleted from that section (8 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack:
(
	0   CoreFoundation                      0x000000010605b1e6 __exceptionPreprocess + 294
	1   libobjc.A.dylib                     0x0000000102168031 objc_exception_throw + 48
	2   CoreFoundation                      0x0000000106060472 +[NSException raise:format:arguments:] + 98
	3   Foundation                          0x0000000101c0b652 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
	4   UIKit                               0x000000010323ad9b -[UITableView _endCellAnimationsWithContext:] + 19031
	5   UIKit                               0x0000000103254787 -[UITableView endUpdates] + 75
	6   StoreApp                            0x00000001017babff _T08StoreApp0A14ViewControllerC010resetTableC033_5C3AD717C85DC9604A7179854EE8731CLLySay10Foundation9IndexPathVG10indexPaths_tFyycfU_ + 1391
	7   StoreApp                            0x00000001017be031 _T08StoreApp0A14ViewControllerC010resetTableC033_5C3AD717C85DC9604A7179854EE8731CLLySay10Foundation9IndexPathVG10indexPaths_tFyycfU_TA + 17
	8   StoreApp                            0x00000001017bac5d _T0Ig_IyB_TR + 45
	9   libdispatch.dylib                   0x000000010787b7ec _dispatch_client_callout + 8
	10  libdispatch.dylib                   0x0000000107888642 _dispatch_sync_thread_bound_invoke + 386
	11  libdispatch.dylib                   0x000000010787b7ec _dispatch_client_callout + 8
	12  libdispatch.dylib                   0x00000001078868cf _dispatch_main_queue_callback_4CF + 628
	13  CoreFoundation                      0x000000010601dc99 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
	14  CoreFoundation                      0x0000000105fe1ea6 __CFRunLoopRun + 2342
	15  CoreFoundation                      0x0000000105fe130b CFRunLoopRunSpecific + 635
	16  GraphicsServices                    0x0000000109d8aa73 GSEventRunModal + 62
	17  UIKit                               0x0000000103119057 UIApplicationMain + 159
	18  StoreApp                            0x00000001017bedd7 main + 55
	19  libdyld.dylib                       0x00000001078f8955 start + 1
	20  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

2018.08.06

  • ์ด๊ฑฐ ์งˆ๋ฌธํ•˜๊ธฐ
    • ์งˆ๋ฌธ๊ฑฐ๋ฆฌ
      1. Create a session configuration
      2. Create a session (with delegate)
      3. Create Task object with URL
      4. Send request with closure
      5. Wait for response (background)
      6. Wait and receive for data
      7. Finish or Error by closure

session() - 1,2,3 task๋งŒ๋“ค๊ณ  sessionํ•จ์ˆ˜ ์ข…๋ฃŒ task.resume() - 4,5?? viewDidLoad์ข…๋ฃŒ sessionํ•จ์ˆ˜์˜ taskํด๋กœ์ €์‹คํ–‰- ๋‹ค๋ฅธ thread์—์„œ..-6,7? (mainthread์—์„œ๋Š” viewdidLoadํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ๋์œผ๋ฏ€๋กœ ์•„๋ฌด ์ผ๋„ ์ผ์–ด๋‚˜์ง€์•Š๋Š”์ค‘) ํด๋กœ์ €์˜ response๋ฐ›๊ณ  ViewController์˜ storeItems ๊ฐ์ฒด์— ๊ฐ’์ด ํ• ๋‹น๋˜๋Š” ๋ธ”๋Ÿญ์—์„œ handler()์‹คํ–‰ ์ด ์ƒํƒœ์—์„œ viewdidLoad๋๋‚˜๋ฉด ๋นˆ ํ…Œ์ด๋ธ”๋ทฐ๋กœ ์ด๋ฏธ ๊ทธ๋ ค์กŒ๊ณ ๊ธฐ๋‹ค๋ฆฌ๋Š”์ค‘์ธ๊ฑด๊ฐ€?

  • viewDidLoad๊ฐ€๋๋‚˜๋ฉด storeItems๊ฐ€ ์—†๋Š” ์ƒํƒœ์—์„œ ํ…Œ์ด๋ธ”๋ทฐ ๊ทธ๋ฆผ
  • ์„ธ์…˜์œผ๋กœ๋ถ€ํ„ฐ storeItems๋ฅผ ๋ฐ›์Œ

  • ๋„ค๋น„๊ฒŒ์ด์…˜ ์ปจํŠธ๋กค๋Ÿฌ์— embed๋œ ์ƒํƒœ์—์„œ segue๋ฅผ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ๋งŒ๋“ค๊ณ  ์—ฐ๊ฒฐํ•ด์ฃผ๋ฉด ์ฝ”๋“œ๋กœ perform segue๋ฅผ ์•ˆํ•ด๋„ ๋ฌด์กฐ๊ฑด ํ•œ๋ฒˆ ๋œฌ๋‹ค!
  • segue๋ฅผ ์Šคํ† ๋ฆฌ๋ณด๋“œ์—์„œ ๋งŒ๋“ค๊ณ  performsegueํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ํ•ด๋‹นํ•˜๋Š” segue์˜ identifier๊ฐ’์„ ๊ฐ€์ง€๊ณ  prepareํ• ๋•Œ ๋™์ž‘์„ ๊ตฌ๋ถ„ํ• ๋•Œ์— ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ž„
  • ์กฐ๊ฑด์—๋”ฐ๋ผ์„œ segue๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ์‹คํ–‰ํ•˜์ง€ ์•Š์œผ๋ ค๊ณ  ํ•œ๋‹ค๋ฉด segue๋Š” ์ฝ”๋“œ๋กœ ๋งŒ๋“ค์–ด์„œ ์‹คํ–‰ํ•ด์•ผํ•œ๋‹ค.

2018.08.07

  • ํ…Œ์ด๋ธ”๋ทฐ ๋ฐ์ดํ„ฐ์™€ ๋ทฐ ๋กœ๋“œ์ค‘์˜ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ์งˆ๋ฌธ
    • ๋น„๋™๊ธฐ์™€ ๋™๊ธฐ์—๋”ฐ๋ฅธ ์—๋Ÿฌ ์›์ธ ๊ตฌ๋ถ„
  • ์Šคํ† ์–ด์•ฑ Step8 PR๋ณด๋ƒ„
  • statusbar ์Šคํƒ€์ผ ๋ณ€๊ฒฝ appdelegate์—์„œํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ์—์…‹ ์นดํƒˆ๋กœ๊ทธ์— color์—์…‹ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉ. ํ”„๋กœ์ ํŠธ ๋‚ด์—์„œ ์ž์ฃผ ์“ฐ๋Š” ์ƒ‰๊น”์€ UIColor(named: "์—์…‹์ด๋ฆ„")์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์งฑํŽธํ•จ! (์ฐธ๊ณ ๋งํฌ)
  • UITableView reloadSections๊ณผ IndexSet

๋น„๋™๊ธฐ

DataSetter์˜ tryDownload()ํ•จ์ˆ˜ ์ถ”๊ฐ€ํ›„ ์—๋Ÿฌ

์—๋Ÿฌ ์ƒํ™ฉ 1.

// ํ…Œ์ด๋ธ”๋ทฐ๊ฐ€ ๋œจ๊ธฐ๋„์ „์— ์—๋Ÿฌ
private func resetTableView(indexPaths: [IndexPath]) {
	 DispatchQueue.main.sync { [weak self] in
		 self?.tableView.beginUpdates()
		 self?.tableView.insertRows(at: indexPaths, with: .automatic)
		 self?.tableView.endUpdates()
	 }
 }
  • ๊ด€๋ จ์—๋Ÿฌ Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
  • ๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ๋™๊ธฐ๋กœ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ๋•Œ๋ฌธ์— ๋ฐ๋“œ๋ฝ ๊ฑธ๋ฆผ
  • ์›๋ž˜ DataSetter๊ฐ™์€ ๊ฐ์ฒด์—์„œ ๋ฐ”๋กœ URLSession.shared.dataTask๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋•Œ๋ฌธ์— ํ•ด๋‹น ์ฝ”๋“œ์— ์žˆ๋Š” ํด๋กœ์ €๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ณณ์ด main์ด ์•„๋‹Œ ๋‹ค๋ฅธ์Šค๋ ˆ๋“œ์˜€๊ธฐ๋•Œ๋ฌธ์—

์—๋Ÿฌ ์ƒํ™ฉ 2.

// ํ…Œ์ด๋ธ”๋ทฐ๊ฐ€ ๋œจ์ง€๋งŒ ์ด๋ฏธ์ง€๋Š” ๋œจ์ง€ ์•Š๊ณ  UIApplicationMain
private func resetTableView(indexPaths: [IndexPath]) {
		DispatchQueue.main.async { [weak self] in
				self?.tableView.beginUpdates()
				self?.tableView.insertRows(at: indexPaths, with: .automatic)
				self?.tableView.endUpdates()
		}
}
  • ๊ด€๋ จ ์—๋Ÿฌ
  • ์„น์…˜์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์‹œ์ ์ด ๋ชจ๋ธ ์—…๋ฐ์ดํŠธ ์‹œ์ ๊ณผ ๋งž์ง€ ์•Š์Œ (async)
    *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3698.54.4/UITableView.m:2012
    2018-08-06 20:44:29.940777+0900 StoreApp[70331:4708122] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (8) must be equal to the number of rows contained in that section before the update (8), plus or minus the number of rows inserted or deleted from that section (8 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
    

ํ•ด๊ฒฐ !

// ํ…Œ์ด๋ธ”๋ทฐ๊ฐ€ ๋œจ๊ณ  ์—๋Ÿฌ๋„ ์•ˆ๋‚จ
private func resetTableView() {
		DispatchQueue.main.async { [unowned self] in
				self.tableView.reloadData()  // ์ดํ›„์— reloadSections๋กœ ๋ฐ”๊ฟˆ
		}
}
  • ์ƒˆ๋กญ๊ฒŒ ์ถ”๊ฐ€๋˜์–ด์„œ ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ ๋™์ž‘ํ•˜๋Š” tryDownload()๋•Œ๋ฌธ์— ๊ธฐ์กด์˜ ์—๋Ÿฌ์ƒํ™ฉ1 ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ๋จ
  • ๋”ฐ๋ผ์„œ ํ•œ๋ฒˆ์— ๋ชจ๋“  ํ…Œ์ด๋ธ”๋ทฐ๋ฅผ ์ „์ฒด ๋‹ค reloadํ•ด๋ฒ„๋ฆฌ๋Š” ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋™์ž‘์ด ๋˜๋Š”์ง€ ํ™•์ธํ•จ

storeItems.Swift


    func set(with category: Category) {
        DataSetter.tryDownload(url: category) { items in
            self.update(key: items.keys.first!, value: items.values.first!)
            if let firstKey = items.firstKey {
                let indexPaths = Array(0..<self.storeItem[firstKey]!.count).map {IndexPath(row: $0, section: firstKey.sectionNumber)}
                NotificationCenter.default.post(name: .sectionSetComplete,
                                                object: self,
                                                userInfo: [Keyword.sectionPath : firstKey])//indexPaths])
            }
        }
//        DataSetter.set(with: category) { items in
//            self.update(key: items.keys.first!, value: items.values.first!)
//            if let firstKey = items.firstKey {
//                let indexPaths = Array(0..<self.storeItem[firstKey]!.count).map {IndexPath(row: $0, section: firstKey.sectionNumber)}
//                NotificationCenter.default.post(name: .sectionSetComplete,
//                                                object: self,
//                                                userInfo: [Keyword.sectionPath : indexPaths])
//            }
//        }
    }
  • insertRows๊ฐ€ ์•„๋‹Œ reloadSection์œผ๋กœ ๋ฐ”๊พธ๋ฉด์„œ category๋งŒ ๋„˜๊ฒจ์ฃผ๋ฉด ๋จ

RootViewController

class StoreViewController: UIViewController {
    @IBOutlet weak var tableView: UITableView!

    let rowHeightForCell: CGFloat = 100
    let rowHeightForHeader: CGFloat = 60

    var storeItems = StoreItems()

    override func viewDidLoad() {
        super.viewDidLoad()
        #if DEBUG
        self.deleteCache()
        #endif
        NotificationCenter.default.addObserver(self, selector: #selector(dataReload), name: .reachabilityChanged, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(setComplete(notification:)),name: .sectionSetComplete,object: nil)
        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = rowHeightForCell
        StoreItems.categories.forEach { (category) in
            self.storeItems.set(with: category)
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @objc func dataReload() {
        if NetworkManager.shared.reachable {
            StoreItems.categories.forEach { (category) in
                self.storeItems.set(with: category)
            }
        } else {
            print("RootView - dataReload. Not reachable")
        }
    }

    private func resetTableView(indexPaths: Category) {
        DispatchQueue.main.async { [weak self] in
//            self?.tableView.reloadData()
            self?.tableView.reloadSections(IndexSet(0..<(self?.storeItems.storeItem.keys.count)!), with: .automatic)
        }
//        DispatchQueue.main.sync { [weak self] in
//            self?.tableView.beginUpdates()
//            self?.tableView.insertRows(at: indexPaths, with: .automatic)
//            self?.tableView.endUpdates()
//        }
    }

    @objc func setComplete(notification: Notification) {
        guard let userInfo = notification.userInfo else { return }
        guard let section = userInfo[Keyword.sectionPath] else { return }
//        guard let sectionNumber = section as? [IndexPath] else { return }
        guard let category = section as? Category else { return }
        self.resetTableView(indexPaths: category)
    }


2018.08.07



#if DEBUG
// self.deleteCache()
#endif


    // DEBUG
    private func deleteCache() {
        let cacheURL = ImageSetter.fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first!
        do {
            let fileNames = try ImageSetter.fileManager.contentsOfDirectory(atPath: cacheURL.path)
            for file in fileNames {
                let imageSavingPath = cacheURL.appendingPathComponent(file)
                if (file.hasSuffix(".jpg")) {
                    try ImageSetter.fileManager.removeItem(atPath: imageSavingPath.path)
                }
                let files = try ImageSetter.fileManager.contentsOfDirectory(atPath: cacheURL.path)
            }
        } catch {
            print("Could not clear temp folder: \(error)")
        }
    }

  • NSKeyValueOperator ์ด๊ฒŒ๋ญ์ง€โ€ฆ
  • value(forKey:)
  • NSKeyValueCoding
    • A mechanism by which you can access the properties of an object indirectly by name or keyโ€ฆโ€ฆโ€ฆโ€ฆโ€ฆ..what?
  • JKํ”ผ๋“œ๋ฐฑ: ViewController ๊ฐ€ .reachabilityChanged ์ƒํƒœ๋ฅผ ์˜ต์ €๋น™ ํ•ด์•ผ ํ•˜๋Š”๊ฑธ๊นŒ์š”? ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ๊ฐ์‹œํ•  ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์ด ๋ฐ”๋€Œ์—ˆ๋Š”์ง€๋งŒ ๊ฐ์‹œํ•˜๋ฉด ๋˜๋Š”๊ฑฐ ์•„๋‹๊นŒ์š”?
    • ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ: ์„น์…˜๋ณ„ ๋ชจ๋ธ StoreItems.set()ํ˜ธ์ถœ - setํ•˜๋Š” datasetter.trydownloadํ•จ์ˆ˜๊ฐ€ ๋น„๋™๊ธฐ๋ผ์„œ noti๋ฅผ ๋„ฃ์Œ
    • ๊ฒฐ๊ตญ ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ set()ํ•˜๋ผ๊ณ  ์‹œํ‚ค๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ์…‹์„ ์™„๋ฃŒํ–ˆ๋‹ค๊ณ  ์•Œ๋ ค์ฃผ๋Š”๊ฑฐ์ง€, ๋ฐ์ดํ„ฐ๊ฐ€ ๋„คํŠธ์›Œํฌ ์ƒํ™ฉ์—๋”ฐ๋ผ ์•Œ์•„์„œ ๋‹ค์šด๋กœ๋“œ๋˜๋Š”๊ฒŒ ์•„๋‹ˆ๊ธฐ๋•Œ๋ฌธ์— reachabilityChanged ๋…ธํ‹ฐํ”ผ์ผ€์ด์…˜ ์˜ต์ €๋ฒ„๋ฅผ ์ง€์šฐ๋ฉด ํŠธ๋ž™ํ‚น์ด์•ˆ๋จโ€ฆ
    • JK: ViewController๊ฐ€ ๋„คํŠธ์›Œํฌ ์ƒํƒœ์— ๋”ฐ๋ผ ๋ชจ๋ธ์„ ๋‹ค๋ฅด๊ฒŒ ์ ‘๊ทผํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ๋„คํŠธ์›Œํฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ณ„์ธต์ด ์–ด๋””์—์„œ ๋™์ž‘ํ• ์ง€ ๊ณ ๋ฏผํ•ด๋ณด๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค. ViewController๋Š” ์ƒํƒœ๋ฅผ ๋ชจ๋ฅด๊ณ , ๋ชจ๋ธ์—์„œ ๊ฐ’์ด ์˜ฌ๋•Œ๋งˆ๋‹ค ๋ทฐ์— ๋ฐ˜์˜ํ•˜๋„๋ก ๋‹จ์ˆœํ•˜๊ฒŒ ์ž‘์„ฑํ•˜๋Š” ๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค. VC โ€“> Network Manager โ€“> ์ƒํƒœํ™•์ธํ›„ Request ๋˜๋Š” ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ โ€“> ๋ชจ๋ธ ๋ณ€๊ฒฝ โ€“> ๋…ธํ‹ฐ โ€“> VC ํ™”๋ฉด ๋ณ€๊ฒฝ ํ๋ฆ„์„ ์ƒ์ƒํ•ด๋ดค์Šต๋‹ˆ๋‹ค.
    • ViewController๊ฐ€ ์–ด์จŒ๋“  Controller์—ญํ• ์„ ํ•˜๋Š”๊ฑฐ๋‹ˆ๊นŒ ์ง€๊ธˆ ํ๋ฆ„์ฒ˜๋Ÿผ ๋ทฐ์— ํ•„์š”ํ•œ ๋ชจ๋ธ(StoreItems๊ฐ์ฒด)์„ ์„ธํŒ…ํ•˜๋Š” ๋™์ž‘์„ ํ˜ธ์ถœํ•˜๋Š”๊ฒŒ ์–ด์ƒ‰ํ•˜์ง„ ์•Š์€ ๊ฒƒ ๊ฐ™์€๋ฐ, ์—ฐ๊ฒฐ์„ฑ์„ ํ™•์ธํ•˜๋Š” ๊ฐ์ฒด๊ฐ€ ์žˆ์œผ๋‹ˆ NetworkManager๊ฐ€ ์ƒํ™ฉ์—๋”ฐ๋ผ ๋ชจ๋ธ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์—ญํ• ์„ ํ•˜๋Š”๊ฒŒ ๋งž๋‚˜์š”?
    • viewDidLoad์—์„œ ์ฒ˜์Œ set - DataSetter์—์„œ ๋„คํŠธ์›Œํฌ ์ƒํ™ฉ์—๋”ฐ๋ผ ๋ชจ๋ธ ์„ธํŒ… - noti๋กœ ์™„๋ฃŒ๋˜๋ฉด viewํ‘œ์‹œ reloadSections
    • (์™€์ดํŒŒ์ด ์ƒํƒœ๋ผ๊ณ  ์ƒํƒœ๋ฐ”๊ฐ€ ํ‘œ์‹œ๋˜์–ด๋„ detailhash๊ฐ’์€ nil์ด๋ผ(๋งจ์ฒ˜์Œ์— reachable์ด false์˜€๊ธฐ๋•Œ๋ฌธ์—) ์ƒํ’ˆ์ƒ์„ธํŽ˜์ด์ง€ํ™”๋ฉด์ด ํ‘œ์‹œ ์•ˆ๋˜๋Š” ๋ฌธ์ œ)

    func notifyListener(_ flags: SCNetworkReachabilityFlags) { guard previousFlags != flags else { return } previousFlags = flags

       listener?(networkReachabilityStatusForFlags(flags))    }
    

2018.08.09

  • JKํ”ผ๋“œ๋ฐฑ์ •๋ฆฌ
  • RxSwiftโ€ฆ
  • KVO์ •๋ฆฌ/์งˆ๋ฌธ
  • NSKeyValueCoding ์•„๋ž˜ ๋‚ด์šฉ ํฌ์ŠคํŒ…ํ•˜๊ธฐ
      var statusBarView: UIView? {
          return value(forKey: "statusBar") as? UIView
      }
    
  • NSKeyValueCoding ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ ์ธํ•ด ๊ฐ์ฒด์˜ ์†์„ฑ์— ์ ‘๊ทผํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜
  • ๊ฐ์ฒด ์†์„ฑ์ด ๋”•์…”๋„ˆ๋ฆฌ์— ์ €์žฅ๋˜์–ด์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๊ณ , key๋ฅผ ์ฃผ๋ฉด value๋ฅผ ์ฃผ๋Š” ๋ฐฉ์‹
  • (Typically, by convention, the key representing a property is the name of the property itself as it appears in code.)
  • value(forKey:) ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๊ฐ์ฒด์˜ ์†์„ฑ์˜ ์ด๋ฆ„์ด๋‚˜ ํ‚ค๊ฐ’์œผ๋กœ ์ฐพ์•„์„œ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, privateํ•œ ์†์„ฑ๊นŒ์ง€ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๊ด€๋ จ๋˜์–ด Stackoverflow์˜ ๋‹ต๋ณ€์—์„œ๋Š” ์ด ๋ฐฉ๋ฒ•์ด privateํ•œ ์†์„ฑ๊นŒ์ง€ ์ ‘๊ทผํ•ด์„œ ์“ฐ๋Š”๊ฑฐ๊ธฐ๋•Œ๋ฌธ์— ์•ˆ์ข‹๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ, ๋งค์ปค๋‹ˆ์ฆ˜์— ์˜ํ•ด์„œ privateํ•œ ์†์„ฑ์— ์ ‘๊ทผํ•ด์„œ ๋ฐ”๊ฟ”๋ฒ„๋ฆฌ๋Š”๊ฑฐ๊ธฐ๋•Œ๋ฌธ์— ๋ณ„๋กœ ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋‹Œ๋“ฏ.
  • ์˜ˆ์‹œ๋กœ statusBar๋Š” ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์ ‘๊ทผํ•ด์„œ ๋ฐ”๊พธ๋Š”๊ฒŒ ๊ถŒ์žฅ๋˜๊ณ  ์žˆ๊ณ  ์˜ˆ์ „์—๋Š” statusBar์— ๋‹ค๋ฅธ๊ณณ์—์„œ ์ ‘๊ทผํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์• ํ”Œ์ด rejectํ•˜๊ธฐ๋„ ํ–ˆ๋‹ค๊ณ  ํ•œ๋‹ค.
  • ๋˜ ์ž๋ฃŒ๋ฅผ ์ฐพ์•„๋ณผ๋•Œ info.plist์˜ key-value๋ชฉ๋ก์ฒ˜๋Ÿผ ์ฐธ๊ณ  ์ž๋ฃŒ๊ฐ€ ์žˆ์„ ์ค„ ์•Œ์•˜๋Š”๋ฐ ์ฐพ๊ณ ์ฐพ์•„๋„ ์—†๋Š” ์ด์œ ๊ฐ€ privateํ•œ ์†์„ฑ์˜ ์ด๋ฆ„๋“ค์„๋‹ค ์ด key๋กœ์“ฐ๋ผ๊ณ  ์•Œ๋ ค์ค„ ์ˆ˜ ์—†์œผ๋‹ˆ๊นŒ(์“ฐ๋ผ๊ณ  ๊ณต๊ฐœํ•˜๋Š”๊ฑฐ ์ž์ฒด๊ฐ€ ์ด์ƒํ•จ) ๊ทธ๋Ÿฐ๋“ฏ.
  • ์ปดํŒŒ์ผํƒ€์ž„์ด ์•„๋‹Œ ๋Ÿฐํƒ€์ž„์‹œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ง€์ •ํ•œ๋‹ค.
    • value(forKey:)์— ๋“ค์–ด๊ฐ€๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋Ÿฐํƒ€์ž„์‹œ์— ๋ณ€๊ฒฝ๋  ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๋œป.
    • (๋ญ..์–ต์ง€์Šค๋Ÿฌ์šด ์ƒํ™ฉ์ผ ์ˆ˜ ์žˆ์ง€๋งŒ A button์„ ๋ˆ„๋ฅด๋ฉด โ€œstatusBarโ€๊ฐ€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด๊ฐ€๊ฑฐ๋‚˜, B button์„ ๋ˆ„๋ฅด๋ฉด โ€œnavigationBarโ€๊ฐ€ ๋„˜์–ด๊ฐ„๋‹ค๊ฑฐ๋‚˜โ€ฆ)
  • ๊ฐ์ฒด๋‚˜ ์†์„ฑ์„ ๋‚ด๊ฐ€ ์ •ํ•œ key๋กœ ์ ‘๊ทผํ•˜๋„๋ก key๋ฅผ ์„ธํŒ…ํ•  ์ˆ˜ ์žˆ๋‹ค. setValue(\_:forKey:)

2018.08.10

  • ๋งˆํŠธ์•ฑ ๊ฐœ๋ฐœํ•ญ๋ชฉ ์ •ํ•˜๊ธฐ
  • ์ฃผ๋ง ๊ณ„ํš์„ธ์šฐ๊ธฐ: ์ž์†Œ์„œ, ๋ธ”๋กœ๊ทธ์™€ ๊นƒํ—™์ •๋ฆฌ, ๊ธฐ์ดˆ๋ฉด์ ‘์งˆ๋ฌธ์ค€๋น„๋“ค

2018.08.11

2018.08.12

  • BranchTableViewCell์˜ setCell() starbutton์„ ์„ธํŒ…ํ•˜๋Š”๋ฐ ์ฒ˜์Œ ํ•œ๋ฒˆ ๋–ด์„๋•Œ ์„ธํŒ…์ด ๋˜์ง„์•Š๊ณ  ์…€์ด ํ™”๋ฉด์—์„œ ๋ฒ—์–ด๋‚ฌ๋‹ค๊ฐ€ ๋‹ค์‹œ ๋‚˜ํƒ€๋‚ ๋•Œ๋งŒ ์„ธํŒ…์ด๋จ. ์‹ฌ์ง€์–ด ์—„์ฒญ ๋Š๋ฆฌ๊ณ  ๋š๋š๋Š๊น€โ€ฆ. ๋ฒ„ํŠผ ์ด๋ฏธ์ง€ ์„ธํŒ…ํ•˜๋Š”๊ฑด ๊ฐ„๋‹จํ•œ ์ž‘์—…์ด๋ผ ์˜ค๋ž˜ ๊ฑธ๋ฆด ๊ฒƒ ๊ฐ™์ง€ ์•Š์•„์„œ ๋ญ๊ฐ€ ๋ฌธ์ œ์ง€ ํ•˜๊ณ  ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ GCD๋กœ main.async๋กœ ์ž‘์—…ํ•˜๊ฒŒ ๋Œ๋ฆฌ๋‹ˆ๊นŒ ๋นจ๋ผ์ง..!

Comments