Dev Seminar 2018

Dev Seminar, 2018 리뷰


RxSwift

키워드

실습

// 가장 인상 깊었던 코드 조각...🙏🏻
func bind() {
        addButton.rx.tap.asObservable()
            .flatMap { [weak self] _ in
                ColorViewController.rx.create(parent: self)
                    .flatMap({ (cv: ColorViewController) -> Observable<UIColor> in
                        cv.rx.selectedColor
                    }).take(1) //take(1) 하면 observable이 complete 됨
            }.subscribe(onNext: { [weak self] (color: UIColor) in
                guard let `self` = self else { return }
                var colors = self.dataSource.value
                colors.append(color)
                self.dataSource.accept(colors)
            }).disposed(by: disposeBag)
        
        dataSource.bind(to: self.collectionView.rx.items(cellIdentifier: "colorCell", cellType: UICollectionViewCell.self)) { (index, color, cell) in
            cell.contentView.backgroundColor = color
            }.disposed(by: disposeBag)
        
        collectionView.rx.itemSelected.asObservable()
            .subscribe(onNext: { [weak self] (indexPath) in
                guard let `self` = self else { return }
                var colors = self.dataSource.value
                colors.remove(at: indexPath.item)
                self.dataSource.accept(colors)
            }).disposed(by: disposeBag)
        
    }


오토레이아웃

오토레이아웃 디버깅

🧐 View 에 이름 붙여서 찾아내기

🧐 레이아웃 비주얼 디버거에서 포인터 주소로 검색하기

🧐 symbolic breakpoint로 오토레이아웃 오류 시점에 앱 죽이기

po $r15
< UIView: 0x7f910ef169f0; frame = (0 0; 375 812); autoresize = W+H; layer = <CALayer: 0x60400022e2e0>>
po $rbx
< __NSArrayM 0x600000252510>(
< NSLayoutConstraint:0x60400028a5a0 UIView:0x7f910ec003d0.width == 150   (active)>,
< NSAutoresizingMaskLayoutConstraint:0x60000028f3c0 h=--& v=--& UIView:0x7f910ec003d0.width == 100   (active)>
)
po $r14
po [[UIWindow KeyWindow] autolayoutTrace]

오토레이아웃 오픈소스

실습


TDD

Test Coverage

목표

단축키

iOS Runtime Header

실습

// 가장 인상 깊었던 코드 조각...🙏🏻
func testJoinButton_push() {
    //Given
    let navi = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController() as! UINavigationController
    let viewController = navi.topViewController as! LoginViewController
    UIApplication.shared.keyWindow?.rootViewController = navi
    
    //When
    _ = viewController.view // load view
    print(viewController.value(forKey: "storyboardSegueTemplates"))
    let segueTemplates = viewController.value(forKey: "storyboardSegueTemplates") as? [AnyObject]
    let template = segueTemplates?.first as? AnyObject
    let targetActions = viewController.joinButton.value(forKey: "_targetActions") as? [AnyObject]
    let buttonTarget = targetActions?.first?.value(forKey: "_target") as? AnyObject
    print(targetActions)
    
    //XCTAssert(NSStringFromClass(type(of: template!))) ===
    XCTAssert(template === buttonTarget)
    viewController.joinButton.sendActions(for: .touchUpInside)
    
    //Wait
    let expectation = XCTestExpectation()
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: expectation.fulfill
    )
    XCTWaiter().wait(for: [expectation], timeout: 1)
    
    //Then
    XCTAssertEqual(navi.viewControllers.count, 2)
    XCTAssertEqual(navi.topViewController?.title, "Create Account")
}
func testWelcomeLabel_displayUsernameWhenFetchError() {
    //GIVEN
    let storyboard = UIStoryboard(name: "Profile", bundle: nil)
    let navi = storyboard.instantiateInitialViewController() as? UINavigationController
    let viewController = navi?.topViewController as! ProfileViewController
    
    let userService = StubUserService()
    userService.stubbedResult = .failure(NSError())
    viewController.userService = userService
    
    //WHEN
    _ = viewController.view // load view
    
    //THEN
    XCTAssertEqual(viewController.welcomeLabel.text, "Error!")
    //XCTAssertEqual(viewController.welcomeLabel.text?.lowercased(), "error")
    //XCTAssrt(viewController.priceLabel.text.contains("1,342")
}



강사님 프로필