├── README.md ├── BlognoneDemo.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata ├── xcuserdata │ └── suraphan.l.xcuserdatad │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── BlognoneDemo.xcscheme └── project.pbxproj ├── BlognoneDemo ├── Feature │ ├── News.swift │ └── NewListing │ │ ├── NewsListModels.swift │ │ ├── UI │ │ ├── NewsListTableViewCell.swift │ │ ├── NewsList.storyboard │ │ └── NewsListTableViewCell.xib │ │ ├── NewsListWorker.swift │ │ ├── NewsListInteractor.swift │ │ ├── NewsListConfigurator.swift │ │ ├── NewsListPresenter.swift │ │ ├── NewsListRouter.swift │ │ └── NewsListViewController.swift ├── ViewController.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── Base.lproj │ └── LaunchScreen.storyboard └── AppDelegate.swift ├── BlognoneDemoTests ├── Info.plist ├── NewsListWorkerTests.swift ├── NewsListInteractorTests.swift ├── NewsListViewControllerTests.swift └── NewsListPresenterTests.swift └── BlognoneDemoUITests ├── Info.plist └── BlognoneDemoUITests.swift /README.md: -------------------------------------------------------------------------------- 1 | # DemoCleanSwift 2 | Thailand iOS Meetup 10 3 | Slide 4 | https://docs.google.com/presentation/d/17baKwnxMXiiHjBd-ZQaNRhS2MEljuebgZPx386tz-Sk/edit?usp=sharing 5 | -------------------------------------------------------------------------------- /BlognoneDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/News.swift: -------------------------------------------------------------------------------- 1 | // 2 | // News.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright © 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct News { 12 | let title: String 13 | let creator: String 14 | let publishDate: Date 15 | } 16 | -------------------------------------------------------------------------------- /BlognoneDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright © 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /BlognoneDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /BlognoneDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /BlognoneDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/NewsListModels.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListModels.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | import UIKit 13 | 14 | struct NewsList { 15 | struct RequestNewsFeed { 16 | struct Request { 17 | } 18 | 19 | struct Response { 20 | let newsList: [News] 21 | } 22 | 23 | struct ViewModel { 24 | struct NewsFeed { 25 | let title: String 26 | let creator: String 27 | let publishDate: String 28 | } 29 | 30 | let displayNewsFeed: [NewsFeed] 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/UI/NewsListTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListTableViewCell.swift 3 | // myblognone 4 | // 5 | // Created by Kittisak Phetrungnapha on 12/21/2559 BE. 6 | // Copyright © 2559 Kittisak Phetrungnapha. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class NewsListTableViewCell: UITableViewCell { 12 | 13 | @IBOutlet weak var titleLabel: UILabel! 14 | @IBOutlet weak var creatorLabel: UILabel! 15 | @IBOutlet weak var dateTimeLabel: UILabel! 16 | 17 | static let identifier = "NewsListTableViewCell" 18 | 19 | override func awakeFromNib() { 20 | super.awakeFromNib() 21 | } 22 | 23 | func setCell(with viewModel: NewsList.RequestNewsFeed.ViewModel.NewsFeed) { 24 | titleLabel.text = viewModel.title 25 | creatorLabel.text = viewModel.creator 26 | dateTimeLabel.text = viewModel.publishDate 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /BlognoneDemo.xcodeproj/xcuserdata/suraphan.l.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | BlognoneDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3C9F49791EFD4B02008AB676 16 | 17 | primary 18 | 19 | 20 | 3C9F498D1EFD4B02008AB676 21 | 22 | primary 23 | 24 | 25 | 3C9F49981EFD4B02008AB676 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /BlognoneDemoTests/NewsListWorkerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListWorkerTests.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import BlognoneDemo 13 | import XCTest 14 | 15 | class NewsListWorkerTests: XCTestCase { 16 | // MARK: - Subject under test 17 | 18 | var sut: NewsListWorker! 19 | 20 | // MARK: - Test lifecycle 21 | 22 | override func setUp() { 23 | super.setUp() 24 | setupNewsListWorker() 25 | } 26 | 27 | override func tearDown() { 28 | super.tearDown() 29 | } 30 | 31 | // MARK: - Test setup 32 | 33 | func setupNewsListWorker() { 34 | sut = NewsListWorker() 35 | } 36 | 37 | // MARK: - Test doubles 38 | 39 | // MARK: - Tests 40 | 41 | func testSomething() { 42 | // Given 43 | 44 | // When 45 | 46 | // Then 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/NewsListWorker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListWorker.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | import UIKit 13 | 14 | class NewsListWorker { 15 | // MARK: - Business Logic 16 | 17 | func fetchNewsFeed(completionHandler: (_ newsList: [News]) -> Void) { 18 | let news1 = News(title: "อยากเล่นไหม เกมมาริโอแบบ AR แค่สวม HoloLens ก็วิ่งเก็บเหรียญ โหม่งเห็ดเองได้", 19 | creator: "sunnywalker", publishDate: Date()) 20 | 21 | let news2 = News(title: "รัฐขอเข้าถึงข้อมูลของ Diamond Reynolds ผู้ให้บริการเครือข่าย Sprint ยอม แต่ Facebook ไม่ยอม", 22 | creator: "sunnywalker", publishDate: Date()) 23 | 24 | let news3 = News(title: "สัปดาห์สุดท้ายก่อนสิงคโปร์ควบคุม GrabCar/Uber คนสมัคร 39,000 คน รถติดสติกเกอร์แล้ว 27,000 คัน", 25 | creator: "lew", publishDate: Date()) 26 | 27 | completionHandler([news1, news2, news3]) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /BlognoneDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | NewsList 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/NewsListInteractor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListInteractor.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | import UIKit 13 | 14 | protocol NewsListInteractorInput { 15 | func fetchNewsFeed(request: NewsList.RequestNewsFeed.Request) 16 | } 17 | 18 | protocol NewsListInteractorOutput { 19 | func presentRequestNewsFeed(response: NewsList.RequestNewsFeed.Response) 20 | } 21 | 22 | class NewsListInteractor: NewsListInteractorInput { 23 | 24 | var output: NewsListInteractorOutput! 25 | var worker: NewsListWorker! = NewsListWorker() 26 | 27 | // MARK: - Business logic 28 | 29 | func fetchNewsFeed(request: NewsList.RequestNewsFeed.Request) { 30 | // 3 demo fetchNewsFeed 31 | // NOTE: Create some Worker to do the work 32 | worker.fetchNewsFeed {[weak self] (newsList) in 33 | // NOTE: Pass the result to the Presenter 34 | 35 | let response = NewsList.RequestNewsFeed.Response(newsList: newsList) 36 | self?.output.presentRequestNewsFeed(response: response) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /BlognoneDemoUITests/BlognoneDemoUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlognoneDemoUITests.swift 3 | // BlognoneDemoUITests 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright © 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class BlognoneDemoUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/NewsListConfigurator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListConfigurator.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | import UIKit 13 | 14 | // MARK: - Connect View, Interactor, and Presenter 15 | 16 | extension NewsListViewController: NewsListPresenterOutput { 17 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 18 | router.passDataToNextScene(segue: segue) 19 | } 20 | } 21 | 22 | extension NewsListInteractor: NewsListViewControllerOutput { 23 | } 24 | 25 | extension NewsListPresenter: NewsListInteractorOutput { 26 | } 27 | 28 | class NewsListConfigurator { 29 | // MARK: - Object lifecycle 30 | 31 | static let sharedInstance = NewsListConfigurator() 32 | 33 | private init() {} 34 | 35 | // MARK: - Configuration 36 | 37 | func configure(viewController: NewsListViewController) { 38 | let router = NewsListRouter() 39 | router.viewController = viewController 40 | 41 | let presenter = NewsListPresenter() 42 | presenter.output = viewController 43 | 44 | let interactor = NewsListInteractor() 45 | interactor.output = presenter 46 | 47 | viewController.output = interactor 48 | viewController.router = router 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /BlognoneDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/NewsListPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListPresenter.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | import UIKit 13 | 14 | protocol NewsListPresenterInput { 15 | func presentRequestNewsFeed(response: NewsList.RequestNewsFeed.Response) 16 | } 17 | 18 | protocol NewsListPresenterOutput: class { 19 | func displayRequestNewsFeed(viewModel: NewsList.RequestNewsFeed.ViewModel) 20 | } 21 | 22 | class NewsListPresenter: NewsListPresenterInput { 23 | weak var output: NewsListPresenterOutput! 24 | 25 | // MARK: - Presentation logic 26 | 27 | func presentRequestNewsFeed(response: NewsList.RequestNewsFeed.Response) { 28 | // 4 demo presentRequestNewsFeed 29 | // NOTE: Format the response from the Interactor and pass the result back to the View Controller 30 | let myLocale = Locale(identifier: "th_TH") 31 | let dateFormatter = DateFormatter() 32 | dateFormatter.dateStyle = .short 33 | dateFormatter.timeStyle = .none 34 | dateFormatter.locale = myLocale 35 | 36 | let newsFeeds = response.newsList.flatMap { (news) -> NewsList.RequestNewsFeed.ViewModel.NewsFeed in 37 | let stringFromDate = dateFormatter.string(from: news.publishDate) 38 | return NewsList.RequestNewsFeed.ViewModel.NewsFeed(title: news.title, 39 | creator: news.creator, 40 | publishDate: stringFromDate) 41 | } 42 | let viewModel = NewsList.RequestNewsFeed.ViewModel(displayNewsFeed: newsFeeds) 43 | output.displayRequestNewsFeed(viewModel: viewModel) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /BlognoneDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright © 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/NewsListRouter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListRouter.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | import UIKit 13 | 14 | protocol NewsListRouterInput { 15 | func navigateToSomewhere() 16 | } 17 | 18 | class NewsListRouter: NewsListRouterInput { 19 | weak var viewController: NewsListViewController! 20 | 21 | // MARK: - Navigation 22 | 23 | func navigateToSomewhere() { 24 | // NOTE: Teach the router how to navigate to another scene. Some examples follow: 25 | 26 | // 1. Trigger a storyboard segue 27 | // viewController.performSegueWithIdentifier("ShowSomewhereScene", sender: nil) 28 | 29 | // 2. Present another view controller programmatically 30 | // viewController.presentViewController(someWhereViewController, animated: true, completion: nil) 31 | 32 | // 3. Ask the navigation controller to push another view controller onto the stack 33 | // viewController.navigationController?.pushViewController(someWhereViewController, animated: true) 34 | 35 | // 4. Present a view controller from a different storyboard 36 | // let storyboard = UIStoryboard(name: "OtherThanMain", bundle: nil) 37 | // let someWhereViewController = storyboard.instantiateInitialViewController() as! SomeWhereViewController 38 | // viewController.navigationController?.pushViewController(someWhereViewController, animated: true) 39 | } 40 | 41 | // MARK: - Communication 42 | 43 | func passDataToNextScene(segue: UIStoryboardSegue) { 44 | // NOTE: Teach the router which scenes it can communicate with 45 | 46 | if segue.identifier == "ShowSomewhereScene" { 47 | passDataToSomewhereScene(segue: segue) 48 | } 49 | } 50 | 51 | func passDataToSomewhereScene(segue: UIStoryboardSegue) { 52 | // NOTE: Teach the router how to pass data to the next scene 53 | 54 | // let someWhereViewController = segue.destinationViewController as! SomeWhereViewController 55 | // someWhereViewController.output.name = viewController.output.name 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /BlognoneDemoTests/NewsListInteractorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListInteractorTests.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import BlognoneDemo 13 | import XCTest 14 | 15 | class NewsListInteractorTests: XCTestCase { 16 | // MARK: - Subject under test 17 | 18 | var sut: NewsListInteractor! 19 | 20 | // MARK: - Test lifecycle 21 | 22 | override func setUp() { 23 | super.setUp() 24 | setupNewsListInteractor() 25 | } 26 | 27 | override func tearDown() { 28 | super.tearDown() 29 | } 30 | 31 | // MARK: - Test setup 32 | 33 | func setupNewsListInteractor() { 34 | sut = NewsListInteractor() 35 | } 36 | 37 | // MARK: - Test doubles 38 | 39 | // 1 demo NewsListInteractorOutputSpy 40 | class NewsListInteractorOutputSpy: NewsListInteractorOutput { 41 | // MARK: Method call expectations 42 | var presentRequestNewsFeedCalled = false 43 | 44 | // MARK: Spied methods 45 | func presentRequestNewsFeed(response: NewsList.RequestNewsFeed.Response) { 46 | presentRequestNewsFeedCalled = true 47 | } 48 | } 49 | 50 | 51 | // 2 demo NewsListWorkerSpy 52 | 53 | class NewsListWorkerSpy: NewsListWorker { 54 | var fetchNewsFeedCalled = false 55 | override func fetchNewsFeed(completionHandler: ([News]) -> Void) { 56 | fetchNewsFeedCalled = true 57 | completionHandler([]) 58 | } 59 | } 60 | 61 | // MARK: - Tests 62 | 63 | func testFetchNewsFeedShouldAskNewSListWorkerToFetchNewsFeedAndPresenterToFormatResult() { 64 | // 3 demo test Interactor 65 | // Given 66 | let newsListInteractorOutputSpy = NewsListInteractorOutputSpy() 67 | sut.output = newsListInteractorOutputSpy 68 | 69 | let newsListWorkerSpy = NewsListWorkerSpy() 70 | sut.worker = newsListWorkerSpy 71 | 72 | // When 73 | let request = NewsList.RequestNewsFeed.Request() 74 | sut.fetchNewsFeed(request: request) 75 | 76 | // Then 77 | XCTAssert(newsListWorkerSpy.fetchNewsFeedCalled, "FetchNewsFeed() should ask NewsListWorker to fecth NewsFeed") 78 | 79 | XCTAssert(newsListInteractorOutputSpy.presentRequestNewsFeedCalled, "FetchNewsFeed() should ask presenter to format result") 80 | 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/NewsListViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListViewController.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | import UIKit 13 | 14 | protocol NewsListViewControllerInput { 15 | func displayRequestNewsFeed(viewModel: NewsList.RequestNewsFeed.ViewModel) 16 | } 17 | 18 | protocol NewsListViewControllerOutput { 19 | func fetchNewsFeed(request: NewsList.RequestNewsFeed.Request) 20 | } 21 | 22 | class NewsListViewController: UIViewController, NewsListViewControllerInput { 23 | var output: NewsListViewControllerOutput! 24 | var router: NewsListRouter! 25 | 26 | @IBOutlet weak var newsTableView: UITableView! 27 | var displayedNewsFeed: [NewsList.RequestNewsFeed.ViewModel.NewsFeed] = [] 28 | 29 | // MARK: - Object lifecycle 30 | 31 | override func awakeFromNib() { 32 | super.awakeFromNib() 33 | NewsListConfigurator.sharedInstance.configure(viewController: self) 34 | } 35 | 36 | // MARK: - View lifecycle 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | setupTableView() 41 | doSomethingOnLoad() 42 | } 43 | 44 | fileprivate func setupTableView() { 45 | newsTableView.register(UINib(nibName: NewsListTableViewCell.identifier, bundle: Bundle.main), 46 | forCellReuseIdentifier: NewsListTableViewCell.identifier) 47 | newsTableView.estimatedRowHeight = 100 48 | newsTableView.rowHeight = UITableViewAutomaticDimension 49 | 50 | } 51 | 52 | // MARK: - Event handling 53 | 54 | func doSomethingOnLoad() { 55 | // 1 demo viewcontroller doSomethingOnLoad 56 | // NOTE: Ask the Interactor to do some work 57 | let request = NewsList.RequestNewsFeed.Request() 58 | output.fetchNewsFeed(request: request) 59 | } 60 | 61 | // MARK: - Display logic 62 | 63 | func displayRequestNewsFeed(viewModel: NewsList.RequestNewsFeed.ViewModel) { 64 | // 5 demo displayRequestNewsFeed 65 | displayedNewsFeed = viewModel.displayNewsFeed 66 | newsTableView.reloadData() 67 | } 68 | } 69 | 70 | extension NewsListViewController: UITableViewDataSource { 71 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 72 | return displayedNewsFeed.count 73 | } 74 | 75 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 76 | guard let cell = tableView.dequeueReusableCell(withIdentifier: NewsListTableViewCell.identifier, for: indexPath) as? NewsListTableViewCell else { 77 | fatalError("Wrong Cell") 78 | } 79 | let viewModel = displayedNewsFeed[indexPath.row] 80 | cell.setCell(with: viewModel) 81 | return cell 82 | } 83 | 84 | 85 | } 86 | -------------------------------------------------------------------------------- /BlognoneDemoTests/NewsListViewControllerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListViewControllerTests.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import BlognoneDemo 13 | import XCTest 14 | 15 | class NewsListViewControllerTests: XCTestCase { 16 | // MARK: - Subject under test 17 | 18 | var sut: NewsListViewController! 19 | var window: UIWindow! 20 | 21 | // MARK: - Test lifecycle 22 | 23 | override func setUp() { 24 | super.setUp() 25 | window = UIWindow() 26 | setupNewsListViewController() 27 | } 28 | 29 | override func tearDown() { 30 | window = nil 31 | super.tearDown() 32 | } 33 | 34 | // MARK: - Test setup 35 | 36 | func setupNewsListViewController() { 37 | let bundle = Bundle.main 38 | let storyboard = UIStoryboard(name: "NewsList", bundle: bundle) 39 | sut = storyboard.instantiateViewController(withIdentifier: "NewsListViewController") as! NewsListViewController 40 | } 41 | 42 | func loadView() { 43 | window.addSubview(sut.view) 44 | RunLoop.current.run(until: Date()) 45 | } 46 | 47 | // MARK: - Test doubles 48 | // 1 demo NewsListViewControllerOutputSpy 49 | 50 | class NewsListViewControllerOutputSpy: NewsListViewControllerOutput { 51 | 52 | // MARK: Method call expectations 53 | var fetchNewsListCalled = false 54 | 55 | // MARK: Spied methods 56 | func fetchNewsFeed(request: NewsList.RequestNewsFeed.Request) { 57 | fetchNewsListCalled = true 58 | } 59 | } 60 | 61 | // 2 demo TableViewSpy 62 | class TableViewSpy: UITableView { 63 | // MARK: Method call expectations 64 | var reloadDataCalled = false 65 | 66 | // MARK: Spied methods 67 | override func reloadData() { 68 | reloadDataCalled = true 69 | } 70 | } 71 | 72 | // MARK: - Tests 73 | 74 | func testShouldFetchNewsListWhenViewIsLoaded() { 75 | // 3 demo FetchNewsListWhenViewIsLoaded 76 | 77 | // Given 78 | let newsListViewControllerOutputSpy = NewsListViewControllerOutputSpy() 79 | sut.output = newsListViewControllerOutputSpy 80 | 81 | // When 82 | loadView() 83 | 84 | // Then 85 | XCTAssert(newsListViewControllerOutputSpy.fetchNewsListCalled, "Should fetch NewsList when the view is loaded") 86 | } 87 | 88 | func testShouldDisplayFetchedNewsList() { 89 | // 4 demo ShouldDisplayFetchedNewsList 90 | // Given 91 | let tableViewSpy = TableViewSpy() 92 | sut.newsTableView = tableViewSpy 93 | 94 | let displayedNewsList = [NewsList.RequestNewsFeed.ViewModel.NewsFeed(title: "Title", creator: "Creator", publishDate: "6/29/60")] 95 | let viewModel = NewsList.RequestNewsFeed.ViewModel(displayNewsFeed: displayedNewsList) 96 | 97 | // When 98 | sut.displayRequestNewsFeed(viewModel: viewModel) 99 | 100 | // Then 101 | XCTAssert(tableViewSpy.reloadDataCalled, "Displaying fetched orders should reload the table view") 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /BlognoneDemoTests/NewsListPresenterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NewsListPresenterTests.swift 3 | // BlognoneDemo 4 | // 5 | // Created by Suraphan 'Rawd' Laokondee on 6/23/2560 BE. 6 | // Copyright (c) 2560 Suraphan 'Rawd' Laokondee. All rights reserved. 7 | // 8 | // This file was generated by the Clean Swift Xcode Templates so you can apply 9 | // clean architecture to your iOS and Mac projects, see http://clean-swift.com 10 | // 11 | 12 | @testable import BlognoneDemo 13 | import XCTest 14 | 15 | class NewsListPresenterTests: XCTestCase { 16 | // MARK: - Subject under test 17 | 18 | var sut: NewsListPresenter! 19 | 20 | // MARK: - Test lifecycle 21 | 22 | override func setUp() { 23 | super.setUp() 24 | setupNewsListPresenter() 25 | } 26 | 27 | override func tearDown() { 28 | super.tearDown() 29 | } 30 | 31 | // MARK: - Test setup 32 | 33 | func setupNewsListPresenter() { 34 | sut = NewsListPresenter() 35 | } 36 | 37 | // MARK: - Test doubles 38 | 39 | // 1 demo NewsListPresenterOutputSpy 40 | 41 | class NewsListPresenterOutputSpy: NewsListPresenterOutput { 42 | // MARK: Method call expectations 43 | var displayFetchNewsFeedCalled = false 44 | 45 | // MARK: Argument expectations 46 | var viewModel: NewsList.RequestNewsFeed.ViewModel! 47 | 48 | // MARK: Spied methods 49 | func displayRequestNewsFeed(viewModel: NewsList.RequestNewsFeed.ViewModel) { 50 | displayFetchNewsFeedCalled = true 51 | self.viewModel = viewModel 52 | } 53 | } 54 | 55 | // MARK: - Tests 56 | 57 | func testPresentFetchedNewsListShouldFormatFetchedNewsListForDisplay() { 58 | // 2 demo test presenter format 59 | 60 | // Given 61 | let newsListPresenterOutputSpy = NewsListPresenterOutputSpy() 62 | sut.output = newsListPresenterOutputSpy 63 | 64 | var dateComponents = DateComponents() 65 | dateComponents.year = 2007 66 | dateComponents.month = 6 67 | dateComponents.day = 29 68 | 69 | let date = Calendar.current.date(from: dateComponents)! 70 | let news = News(title: "Title", creator: "Creator", publishDate: date) 71 | let response = NewsList.RequestNewsFeed.Response(newsList: [news]) 72 | 73 | // When 74 | sut.presentRequestNewsFeed(response: response) 75 | 76 | // Then 77 | 78 | let displayedNewsFeeds = newsListPresenterOutputSpy.viewModel.displayNewsFeed 79 | let viewModel = displayedNewsFeeds.first! 80 | XCTAssertEqual(viewModel.title, "Title") 81 | XCTAssertEqual(viewModel.creator, "Creator") 82 | XCTAssertEqual(viewModel.publishDate, "29/6/50") 83 | } 84 | 85 | func testPresentFetchedNewsListShouldAskViewControllerToDisplayFetchedNewsList() { 86 | // 3 demo test Present display 87 | 88 | // Given 89 | let newsListPresenterOutputSpy = NewsListPresenterOutputSpy() 90 | sut.output = newsListPresenterOutputSpy 91 | 92 | let news = News(title: "Title", creator: "Creator", publishDate: Date()) 93 | let response = NewsList.RequestNewsFeed.Response(newsList: [news]) 94 | 95 | // When 96 | sut.presentRequestNewsFeed(response: response) 97 | 98 | // Then 99 | 100 | XCTAssert(newsListPresenterOutputSpy.displayFetchNewsFeedCalled, "Presenting fetched NewsList should ask view controller to display them") 101 | } 102 | } 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /BlognoneDemo.xcodeproj/xcuserdata/suraphan.l.xcuserdatad/xcschemes/BlognoneDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/UI/NewsList.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /BlognoneDemo/Feature/NewListing/UI/NewsListTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 35 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /BlognoneDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3C9F497E1EFD4B02008AB676 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F497D1EFD4B02008AB676 /* AppDelegate.swift */; }; 11 | 3C9F49801EFD4B02008AB676 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F497F1EFD4B02008AB676 /* ViewController.swift */; }; 12 | 3C9F49851EFD4B02008AB676 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3C9F49841EFD4B02008AB676 /* Assets.xcassets */; }; 13 | 3C9F49881EFD4B02008AB676 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3C9F49861EFD4B02008AB676 /* LaunchScreen.storyboard */; }; 14 | 3C9F499E1EFD4B02008AB676 /* BlognoneDemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F499D1EFD4B02008AB676 /* BlognoneDemoUITests.swift */; }; 15 | 3C9F49C21EFD4B80008AB676 /* NewsListConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49BB1EFD4B80008AB676 /* NewsListConfigurator.swift */; }; 16 | 3C9F49C31EFD4B80008AB676 /* NewsListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49BC1EFD4B80008AB676 /* NewsListInteractor.swift */; }; 17 | 3C9F49C41EFD4B80008AB676 /* NewsListModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49BD1EFD4B80008AB676 /* NewsListModels.swift */; }; 18 | 3C9F49C51EFD4B80008AB676 /* NewsListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49BE1EFD4B80008AB676 /* NewsListPresenter.swift */; }; 19 | 3C9F49C61EFD4B80008AB676 /* NewsListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49BF1EFD4B80008AB676 /* NewsListRouter.swift */; }; 20 | 3C9F49C71EFD4B80008AB676 /* NewsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49C01EFD4B80008AB676 /* NewsListViewController.swift */; }; 21 | 3C9F49C81EFD4B80008AB676 /* NewsListWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49C11EFD4B80008AB676 /* NewsListWorker.swift */; }; 22 | 3C9F49CE1EFD4BBD008AB676 /* NewsList.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3C9F49CA1EFD4BBD008AB676 /* NewsList.storyboard */; }; 23 | 3C9F49CF1EFD4BBD008AB676 /* NewsListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49CB1EFD4BBD008AB676 /* NewsListTableViewCell.swift */; }; 24 | 3C9F49D01EFD4BBD008AB676 /* NewsListTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3C9F49CC1EFD4BBD008AB676 /* NewsListTableViewCell.xib */; }; 25 | 3C9F49D31EFD51FA008AB676 /* News.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49D21EFD51FA008AB676 /* News.swift */; }; 26 | 3C9F49D81EFD7129008AB676 /* NewsListInteractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49D41EFD7129008AB676 /* NewsListInteractorTests.swift */; }; 27 | 3C9F49D91EFD7129008AB676 /* NewsListPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49D51EFD7129008AB676 /* NewsListPresenterTests.swift */; }; 28 | 3C9F49DA1EFD7129008AB676 /* NewsListViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49D61EFD7129008AB676 /* NewsListViewControllerTests.swift */; }; 29 | 3C9F49DB1EFD7129008AB676 /* NewsListWorkerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C9F49D71EFD7129008AB676 /* NewsListWorkerTests.swift */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | 3C9F498F1EFD4B02008AB676 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = 3C9F49721EFD4B02008AB676 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = 3C9F49791EFD4B02008AB676; 38 | remoteInfo = BlognoneDemo; 39 | }; 40 | 3C9F499A1EFD4B02008AB676 /* PBXContainerItemProxy */ = { 41 | isa = PBXContainerItemProxy; 42 | containerPortal = 3C9F49721EFD4B02008AB676 /* Project object */; 43 | proxyType = 1; 44 | remoteGlobalIDString = 3C9F49791EFD4B02008AB676; 45 | remoteInfo = BlognoneDemo; 46 | }; 47 | /* End PBXContainerItemProxy section */ 48 | 49 | /* Begin PBXFileReference section */ 50 | 3C9F497A1EFD4B02008AB676 /* BlognoneDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BlognoneDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 3C9F497D1EFD4B02008AB676 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 52 | 3C9F497F1EFD4B02008AB676 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 53 | 3C9F49841EFD4B02008AB676 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 3C9F49871EFD4B02008AB676 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 3C9F49891EFD4B02008AB676 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | 3C9F498E1EFD4B02008AB676 /* BlognoneDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BlognoneDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 3C9F49941EFD4B02008AB676 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 58 | 3C9F49991EFD4B02008AB676 /* BlognoneDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BlognoneDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 3C9F499D1EFD4B02008AB676 /* BlognoneDemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlognoneDemoUITests.swift; sourceTree = ""; }; 60 | 3C9F499F1EFD4B02008AB676 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 3C9F49BB1EFD4B80008AB676 /* NewsListConfigurator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListConfigurator.swift; sourceTree = ""; }; 62 | 3C9F49BC1EFD4B80008AB676 /* NewsListInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListInteractor.swift; sourceTree = ""; }; 63 | 3C9F49BD1EFD4B80008AB676 /* NewsListModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListModels.swift; sourceTree = ""; }; 64 | 3C9F49BE1EFD4B80008AB676 /* NewsListPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListPresenter.swift; sourceTree = ""; }; 65 | 3C9F49BF1EFD4B80008AB676 /* NewsListRouter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListRouter.swift; sourceTree = ""; }; 66 | 3C9F49C01EFD4B80008AB676 /* NewsListViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListViewController.swift; sourceTree = ""; }; 67 | 3C9F49C11EFD4B80008AB676 /* NewsListWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListWorker.swift; sourceTree = ""; }; 68 | 3C9F49CA1EFD4BBD008AB676 /* NewsList.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NewsList.storyboard; sourceTree = ""; }; 69 | 3C9F49CB1EFD4BBD008AB676 /* NewsListTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListTableViewCell.swift; sourceTree = ""; }; 70 | 3C9F49CC1EFD4BBD008AB676 /* NewsListTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NewsListTableViewCell.xib; sourceTree = ""; }; 71 | 3C9F49D21EFD51FA008AB676 /* News.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = News.swift; sourceTree = ""; }; 72 | 3C9F49D41EFD7129008AB676 /* NewsListInteractorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListInteractorTests.swift; sourceTree = ""; }; 73 | 3C9F49D51EFD7129008AB676 /* NewsListPresenterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListPresenterTests.swift; sourceTree = ""; }; 74 | 3C9F49D61EFD7129008AB676 /* NewsListViewControllerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListViewControllerTests.swift; sourceTree = ""; }; 75 | 3C9F49D71EFD7129008AB676 /* NewsListWorkerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsListWorkerTests.swift; sourceTree = ""; }; 76 | /* End PBXFileReference section */ 77 | 78 | /* Begin PBXFrameworksBuildPhase section */ 79 | 3C9F49771EFD4B02008AB676 /* Frameworks */ = { 80 | isa = PBXFrameworksBuildPhase; 81 | buildActionMask = 2147483647; 82 | files = ( 83 | ); 84 | runOnlyForDeploymentPostprocessing = 0; 85 | }; 86 | 3C9F498B1EFD4B02008AB676 /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | ); 91 | runOnlyForDeploymentPostprocessing = 0; 92 | }; 93 | 3C9F49961EFD4B02008AB676 /* Frameworks */ = { 94 | isa = PBXFrameworksBuildPhase; 95 | buildActionMask = 2147483647; 96 | files = ( 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | /* End PBXFrameworksBuildPhase section */ 101 | 102 | /* Begin PBXGroup section */ 103 | 3C9F49711EFD4B02008AB676 = { 104 | isa = PBXGroup; 105 | children = ( 106 | 3C9F497C1EFD4B02008AB676 /* BlognoneDemo */, 107 | 3C9F49911EFD4B02008AB676 /* BlognoneDemoTests */, 108 | 3C9F499C1EFD4B02008AB676 /* BlognoneDemoUITests */, 109 | 3C9F497B1EFD4B02008AB676 /* Products */, 110 | ); 111 | sourceTree = ""; 112 | }; 113 | 3C9F497B1EFD4B02008AB676 /* Products */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 3C9F497A1EFD4B02008AB676 /* BlognoneDemo.app */, 117 | 3C9F498E1EFD4B02008AB676 /* BlognoneDemoTests.xctest */, 118 | 3C9F49991EFD4B02008AB676 /* BlognoneDemoUITests.xctest */, 119 | ); 120 | name = Products; 121 | sourceTree = ""; 122 | }; 123 | 3C9F497C1EFD4B02008AB676 /* BlognoneDemo */ = { 124 | isa = PBXGroup; 125 | children = ( 126 | 3C9F49AB1EFD4B30008AB676 /* Feature */, 127 | 3C9F497D1EFD4B02008AB676 /* AppDelegate.swift */, 128 | 3C9F497F1EFD4B02008AB676 /* ViewController.swift */, 129 | 3C9F49841EFD4B02008AB676 /* Assets.xcassets */, 130 | 3C9F49861EFD4B02008AB676 /* LaunchScreen.storyboard */, 131 | 3C9F49891EFD4B02008AB676 /* Info.plist */, 132 | ); 133 | path = BlognoneDemo; 134 | sourceTree = ""; 135 | }; 136 | 3C9F49911EFD4B02008AB676 /* BlognoneDemoTests */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 3C9F49941EFD4B02008AB676 /* Info.plist */, 140 | 3C9F49D41EFD7129008AB676 /* NewsListInteractorTests.swift */, 141 | 3C9F49D51EFD7129008AB676 /* NewsListPresenterTests.swift */, 142 | 3C9F49D61EFD7129008AB676 /* NewsListViewControllerTests.swift */, 143 | 3C9F49D71EFD7129008AB676 /* NewsListWorkerTests.swift */, 144 | ); 145 | path = BlognoneDemoTests; 146 | sourceTree = ""; 147 | }; 148 | 3C9F499C1EFD4B02008AB676 /* BlognoneDemoUITests */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 3C9F499D1EFD4B02008AB676 /* BlognoneDemoUITests.swift */, 152 | 3C9F499F1EFD4B02008AB676 /* Info.plist */, 153 | ); 154 | path = BlognoneDemoUITests; 155 | sourceTree = ""; 156 | }; 157 | 3C9F49AB1EFD4B30008AB676 /* Feature */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 3C9F49AC1EFD4B30008AB676 /* NewsList */, 161 | 3C9F49D21EFD51FA008AB676 /* News.swift */, 162 | ); 163 | path = Feature; 164 | sourceTree = ""; 165 | }; 166 | 3C9F49AC1EFD4B30008AB676 /* NewsList */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 3C9F49C91EFD4BAA008AB676 /* UI */, 170 | 3C9F49BB1EFD4B80008AB676 /* NewsListConfigurator.swift */, 171 | 3C9F49BC1EFD4B80008AB676 /* NewsListInteractor.swift */, 172 | 3C9F49BD1EFD4B80008AB676 /* NewsListModels.swift */, 173 | 3C9F49BE1EFD4B80008AB676 /* NewsListPresenter.swift */, 174 | 3C9F49BF1EFD4B80008AB676 /* NewsListRouter.swift */, 175 | 3C9F49C01EFD4B80008AB676 /* NewsListViewController.swift */, 176 | 3C9F49C11EFD4B80008AB676 /* NewsListWorker.swift */, 177 | ); 178 | name = NewsList; 179 | path = NewListing; 180 | sourceTree = ""; 181 | }; 182 | 3C9F49C91EFD4BAA008AB676 /* UI */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 3C9F49CA1EFD4BBD008AB676 /* NewsList.storyboard */, 186 | 3C9F49CB1EFD4BBD008AB676 /* NewsListTableViewCell.swift */, 187 | 3C9F49CC1EFD4BBD008AB676 /* NewsListTableViewCell.xib */, 188 | ); 189 | path = UI; 190 | sourceTree = ""; 191 | }; 192 | /* End PBXGroup section */ 193 | 194 | /* Begin PBXNativeTarget section */ 195 | 3C9F49791EFD4B02008AB676 /* BlognoneDemo */ = { 196 | isa = PBXNativeTarget; 197 | buildConfigurationList = 3C9F49A21EFD4B02008AB676 /* Build configuration list for PBXNativeTarget "BlognoneDemo" */; 198 | buildPhases = ( 199 | 3C9F49761EFD4B02008AB676 /* Sources */, 200 | 3C9F49771EFD4B02008AB676 /* Frameworks */, 201 | 3C9F49781EFD4B02008AB676 /* Resources */, 202 | ); 203 | buildRules = ( 204 | ); 205 | dependencies = ( 206 | ); 207 | name = BlognoneDemo; 208 | productName = BlognoneDemo; 209 | productReference = 3C9F497A1EFD4B02008AB676 /* BlognoneDemo.app */; 210 | productType = "com.apple.product-type.application"; 211 | }; 212 | 3C9F498D1EFD4B02008AB676 /* BlognoneDemoTests */ = { 213 | isa = PBXNativeTarget; 214 | buildConfigurationList = 3C9F49A51EFD4B02008AB676 /* Build configuration list for PBXNativeTarget "BlognoneDemoTests" */; 215 | buildPhases = ( 216 | 3C9F498A1EFD4B02008AB676 /* Sources */, 217 | 3C9F498B1EFD4B02008AB676 /* Frameworks */, 218 | 3C9F498C1EFD4B02008AB676 /* Resources */, 219 | ); 220 | buildRules = ( 221 | ); 222 | dependencies = ( 223 | 3C9F49901EFD4B02008AB676 /* PBXTargetDependency */, 224 | ); 225 | name = BlognoneDemoTests; 226 | productName = BlognoneDemoTests; 227 | productReference = 3C9F498E1EFD4B02008AB676 /* BlognoneDemoTests.xctest */; 228 | productType = "com.apple.product-type.bundle.unit-test"; 229 | }; 230 | 3C9F49981EFD4B02008AB676 /* BlognoneDemoUITests */ = { 231 | isa = PBXNativeTarget; 232 | buildConfigurationList = 3C9F49A81EFD4B02008AB676 /* Build configuration list for PBXNativeTarget "BlognoneDemoUITests" */; 233 | buildPhases = ( 234 | 3C9F49951EFD4B02008AB676 /* Sources */, 235 | 3C9F49961EFD4B02008AB676 /* Frameworks */, 236 | 3C9F49971EFD4B02008AB676 /* Resources */, 237 | ); 238 | buildRules = ( 239 | ); 240 | dependencies = ( 241 | 3C9F499B1EFD4B02008AB676 /* PBXTargetDependency */, 242 | ); 243 | name = BlognoneDemoUITests; 244 | productName = BlognoneDemoUITests; 245 | productReference = 3C9F49991EFD4B02008AB676 /* BlognoneDemoUITests.xctest */; 246 | productType = "com.apple.product-type.bundle.ui-testing"; 247 | }; 248 | /* End PBXNativeTarget section */ 249 | 250 | /* Begin PBXProject section */ 251 | 3C9F49721EFD4B02008AB676 /* Project object */ = { 252 | isa = PBXProject; 253 | attributes = { 254 | LastSwiftUpdateCheck = 0830; 255 | LastUpgradeCheck = 0830; 256 | ORGANIZATIONNAME = "Suraphan 'Rawd' Laokondee"; 257 | TargetAttributes = { 258 | 3C9F49791EFD4B02008AB676 = { 259 | CreatedOnToolsVersion = 8.3.2; 260 | DevelopmentTeam = F86DW2R66C; 261 | ProvisioningStyle = Automatic; 262 | }; 263 | 3C9F498D1EFD4B02008AB676 = { 264 | CreatedOnToolsVersion = 8.3.2; 265 | DevelopmentTeam = F86DW2R66C; 266 | ProvisioningStyle = Automatic; 267 | TestTargetID = 3C9F49791EFD4B02008AB676; 268 | }; 269 | 3C9F49981EFD4B02008AB676 = { 270 | CreatedOnToolsVersion = 8.3.2; 271 | DevelopmentTeam = F86DW2R66C; 272 | ProvisioningStyle = Automatic; 273 | TestTargetID = 3C9F49791EFD4B02008AB676; 274 | }; 275 | }; 276 | }; 277 | buildConfigurationList = 3C9F49751EFD4B02008AB676 /* Build configuration list for PBXProject "BlognoneDemo" */; 278 | compatibilityVersion = "Xcode 3.2"; 279 | developmentRegion = English; 280 | hasScannedForEncodings = 0; 281 | knownRegions = ( 282 | en, 283 | Base, 284 | ); 285 | mainGroup = 3C9F49711EFD4B02008AB676; 286 | productRefGroup = 3C9F497B1EFD4B02008AB676 /* Products */; 287 | projectDirPath = ""; 288 | projectRoot = ""; 289 | targets = ( 290 | 3C9F49791EFD4B02008AB676 /* BlognoneDemo */, 291 | 3C9F498D1EFD4B02008AB676 /* BlognoneDemoTests */, 292 | 3C9F49981EFD4B02008AB676 /* BlognoneDemoUITests */, 293 | ); 294 | }; 295 | /* End PBXProject section */ 296 | 297 | /* Begin PBXResourcesBuildPhase section */ 298 | 3C9F49781EFD4B02008AB676 /* Resources */ = { 299 | isa = PBXResourcesBuildPhase; 300 | buildActionMask = 2147483647; 301 | files = ( 302 | 3C9F49D01EFD4BBD008AB676 /* NewsListTableViewCell.xib in Resources */, 303 | 3C9F49881EFD4B02008AB676 /* LaunchScreen.storyboard in Resources */, 304 | 3C9F49851EFD4B02008AB676 /* Assets.xcassets in Resources */, 305 | 3C9F49CE1EFD4BBD008AB676 /* NewsList.storyboard in Resources */, 306 | ); 307 | runOnlyForDeploymentPostprocessing = 0; 308 | }; 309 | 3C9F498C1EFD4B02008AB676 /* Resources */ = { 310 | isa = PBXResourcesBuildPhase; 311 | buildActionMask = 2147483647; 312 | files = ( 313 | ); 314 | runOnlyForDeploymentPostprocessing = 0; 315 | }; 316 | 3C9F49971EFD4B02008AB676 /* Resources */ = { 317 | isa = PBXResourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | /* End PBXResourcesBuildPhase section */ 324 | 325 | /* Begin PBXSourcesBuildPhase section */ 326 | 3C9F49761EFD4B02008AB676 /* Sources */ = { 327 | isa = PBXSourcesBuildPhase; 328 | buildActionMask = 2147483647; 329 | files = ( 330 | 3C9F49C21EFD4B80008AB676 /* NewsListConfigurator.swift in Sources */, 331 | 3C9F49C81EFD4B80008AB676 /* NewsListWorker.swift in Sources */, 332 | 3C9F49801EFD4B02008AB676 /* ViewController.swift in Sources */, 333 | 3C9F49C61EFD4B80008AB676 /* NewsListRouter.swift in Sources */, 334 | 3C9F497E1EFD4B02008AB676 /* AppDelegate.swift in Sources */, 335 | 3C9F49C31EFD4B80008AB676 /* NewsListInteractor.swift in Sources */, 336 | 3C9F49D31EFD51FA008AB676 /* News.swift in Sources */, 337 | 3C9F49CF1EFD4BBD008AB676 /* NewsListTableViewCell.swift in Sources */, 338 | 3C9F49C41EFD4B80008AB676 /* NewsListModels.swift in Sources */, 339 | 3C9F49C51EFD4B80008AB676 /* NewsListPresenter.swift in Sources */, 340 | 3C9F49C71EFD4B80008AB676 /* NewsListViewController.swift in Sources */, 341 | ); 342 | runOnlyForDeploymentPostprocessing = 0; 343 | }; 344 | 3C9F498A1EFD4B02008AB676 /* Sources */ = { 345 | isa = PBXSourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | 3C9F49DA1EFD7129008AB676 /* NewsListViewControllerTests.swift in Sources */, 349 | 3C9F49D91EFD7129008AB676 /* NewsListPresenterTests.swift in Sources */, 350 | 3C9F49DB1EFD7129008AB676 /* NewsListWorkerTests.swift in Sources */, 351 | 3C9F49D81EFD7129008AB676 /* NewsListInteractorTests.swift in Sources */, 352 | ); 353 | runOnlyForDeploymentPostprocessing = 0; 354 | }; 355 | 3C9F49951EFD4B02008AB676 /* Sources */ = { 356 | isa = PBXSourcesBuildPhase; 357 | buildActionMask = 2147483647; 358 | files = ( 359 | 3C9F499E1EFD4B02008AB676 /* BlognoneDemoUITests.swift in Sources */, 360 | ); 361 | runOnlyForDeploymentPostprocessing = 0; 362 | }; 363 | /* End PBXSourcesBuildPhase section */ 364 | 365 | /* Begin PBXTargetDependency section */ 366 | 3C9F49901EFD4B02008AB676 /* PBXTargetDependency */ = { 367 | isa = PBXTargetDependency; 368 | target = 3C9F49791EFD4B02008AB676 /* BlognoneDemo */; 369 | targetProxy = 3C9F498F1EFD4B02008AB676 /* PBXContainerItemProxy */; 370 | }; 371 | 3C9F499B1EFD4B02008AB676 /* PBXTargetDependency */ = { 372 | isa = PBXTargetDependency; 373 | target = 3C9F49791EFD4B02008AB676 /* BlognoneDemo */; 374 | targetProxy = 3C9F499A1EFD4B02008AB676 /* PBXContainerItemProxy */; 375 | }; 376 | /* End PBXTargetDependency section */ 377 | 378 | /* Begin PBXVariantGroup section */ 379 | 3C9F49861EFD4B02008AB676 /* LaunchScreen.storyboard */ = { 380 | isa = PBXVariantGroup; 381 | children = ( 382 | 3C9F49871EFD4B02008AB676 /* Base */, 383 | ); 384 | name = LaunchScreen.storyboard; 385 | sourceTree = ""; 386 | }; 387 | /* End PBXVariantGroup section */ 388 | 389 | /* Begin XCBuildConfiguration section */ 390 | 3C9F49A01EFD4B02008AB676 /* Debug */ = { 391 | isa = XCBuildConfiguration; 392 | buildSettings = { 393 | ALWAYS_SEARCH_USER_PATHS = NO; 394 | CLANG_ANALYZER_NONNULL = YES; 395 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 396 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 397 | CLANG_CXX_LIBRARY = "libc++"; 398 | CLANG_ENABLE_MODULES = YES; 399 | CLANG_ENABLE_OBJC_ARC = YES; 400 | CLANG_WARN_BOOL_CONVERSION = YES; 401 | CLANG_WARN_CONSTANT_CONVERSION = YES; 402 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 403 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 404 | CLANG_WARN_EMPTY_BODY = YES; 405 | CLANG_WARN_ENUM_CONVERSION = YES; 406 | CLANG_WARN_INFINITE_RECURSION = YES; 407 | CLANG_WARN_INT_CONVERSION = YES; 408 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 409 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 410 | CLANG_WARN_UNREACHABLE_CODE = YES; 411 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 412 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 413 | COPY_PHASE_STRIP = NO; 414 | DEBUG_INFORMATION_FORMAT = dwarf; 415 | ENABLE_STRICT_OBJC_MSGSEND = YES; 416 | ENABLE_TESTABILITY = YES; 417 | GCC_C_LANGUAGE_STANDARD = gnu99; 418 | GCC_DYNAMIC_NO_PIC = NO; 419 | GCC_NO_COMMON_BLOCKS = YES; 420 | GCC_OPTIMIZATION_LEVEL = 0; 421 | GCC_PREPROCESSOR_DEFINITIONS = ( 422 | "DEBUG=1", 423 | "$(inherited)", 424 | ); 425 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 426 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 427 | GCC_WARN_UNDECLARED_SELECTOR = YES; 428 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 429 | GCC_WARN_UNUSED_FUNCTION = YES; 430 | GCC_WARN_UNUSED_VARIABLE = YES; 431 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 432 | MTL_ENABLE_DEBUG_INFO = YES; 433 | ONLY_ACTIVE_ARCH = YES; 434 | SDKROOT = iphoneos; 435 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 436 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 437 | }; 438 | name = Debug; 439 | }; 440 | 3C9F49A11EFD4B02008AB676 /* Release */ = { 441 | isa = XCBuildConfiguration; 442 | buildSettings = { 443 | ALWAYS_SEARCH_USER_PATHS = NO; 444 | CLANG_ANALYZER_NONNULL = YES; 445 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 446 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 447 | CLANG_CXX_LIBRARY = "libc++"; 448 | CLANG_ENABLE_MODULES = YES; 449 | CLANG_ENABLE_OBJC_ARC = YES; 450 | CLANG_WARN_BOOL_CONVERSION = YES; 451 | CLANG_WARN_CONSTANT_CONVERSION = YES; 452 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 453 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 454 | CLANG_WARN_EMPTY_BODY = YES; 455 | CLANG_WARN_ENUM_CONVERSION = YES; 456 | CLANG_WARN_INFINITE_RECURSION = YES; 457 | CLANG_WARN_INT_CONVERSION = YES; 458 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 459 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 460 | CLANG_WARN_UNREACHABLE_CODE = YES; 461 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 462 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 463 | COPY_PHASE_STRIP = NO; 464 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 465 | ENABLE_NS_ASSERTIONS = NO; 466 | ENABLE_STRICT_OBJC_MSGSEND = YES; 467 | GCC_C_LANGUAGE_STANDARD = gnu99; 468 | GCC_NO_COMMON_BLOCKS = YES; 469 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 470 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 471 | GCC_WARN_UNDECLARED_SELECTOR = YES; 472 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 473 | GCC_WARN_UNUSED_FUNCTION = YES; 474 | GCC_WARN_UNUSED_VARIABLE = YES; 475 | IPHONEOS_DEPLOYMENT_TARGET = 10.3; 476 | MTL_ENABLE_DEBUG_INFO = NO; 477 | SDKROOT = iphoneos; 478 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 479 | VALIDATE_PRODUCT = YES; 480 | }; 481 | name = Release; 482 | }; 483 | 3C9F49A31EFD4B02008AB676 /* Debug */ = { 484 | isa = XCBuildConfiguration; 485 | buildSettings = { 486 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 487 | DEVELOPMENT_TEAM = F86DW2R66C; 488 | INFOPLIST_FILE = BlognoneDemo/Info.plist; 489 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 490 | PRODUCT_BUNDLE_IDENTIFIER = com.rawd.BlognoneDemo; 491 | PRODUCT_NAME = "$(TARGET_NAME)"; 492 | SWIFT_VERSION = 3.0; 493 | }; 494 | name = Debug; 495 | }; 496 | 3C9F49A41EFD4B02008AB676 /* Release */ = { 497 | isa = XCBuildConfiguration; 498 | buildSettings = { 499 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 500 | DEVELOPMENT_TEAM = F86DW2R66C; 501 | INFOPLIST_FILE = BlognoneDemo/Info.plist; 502 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 503 | PRODUCT_BUNDLE_IDENTIFIER = com.rawd.BlognoneDemo; 504 | PRODUCT_NAME = "$(TARGET_NAME)"; 505 | SWIFT_VERSION = 3.0; 506 | }; 507 | name = Release; 508 | }; 509 | 3C9F49A61EFD4B02008AB676 /* Debug */ = { 510 | isa = XCBuildConfiguration; 511 | buildSettings = { 512 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 513 | BUNDLE_LOADER = "$(TEST_HOST)"; 514 | DEVELOPMENT_TEAM = F86DW2R66C; 515 | INFOPLIST_FILE = BlognoneDemoTests/Info.plist; 516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 517 | PRODUCT_BUNDLE_IDENTIFIER = com.rawd.BlognoneDemoTests; 518 | PRODUCT_NAME = "$(TARGET_NAME)"; 519 | SWIFT_VERSION = 3.0; 520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BlognoneDemo.app/BlognoneDemo"; 521 | }; 522 | name = Debug; 523 | }; 524 | 3C9F49A71EFD4B02008AB676 /* Release */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 528 | BUNDLE_LOADER = "$(TEST_HOST)"; 529 | DEVELOPMENT_TEAM = F86DW2R66C; 530 | INFOPLIST_FILE = BlognoneDemoTests/Info.plist; 531 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 532 | PRODUCT_BUNDLE_IDENTIFIER = com.rawd.BlognoneDemoTests; 533 | PRODUCT_NAME = "$(TARGET_NAME)"; 534 | SWIFT_VERSION = 3.0; 535 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/BlognoneDemo.app/BlognoneDemo"; 536 | }; 537 | name = Release; 538 | }; 539 | 3C9F49A91EFD4B02008AB676 /* Debug */ = { 540 | isa = XCBuildConfiguration; 541 | buildSettings = { 542 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 543 | DEVELOPMENT_TEAM = F86DW2R66C; 544 | INFOPLIST_FILE = BlognoneDemoUITests/Info.plist; 545 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 546 | PRODUCT_BUNDLE_IDENTIFIER = com.rawd.BlognoneDemoUITests; 547 | PRODUCT_NAME = "$(TARGET_NAME)"; 548 | SWIFT_VERSION = 3.0; 549 | TEST_TARGET_NAME = BlognoneDemo; 550 | }; 551 | name = Debug; 552 | }; 553 | 3C9F49AA1EFD4B02008AB676 /* Release */ = { 554 | isa = XCBuildConfiguration; 555 | buildSettings = { 556 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 557 | DEVELOPMENT_TEAM = F86DW2R66C; 558 | INFOPLIST_FILE = BlognoneDemoUITests/Info.plist; 559 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 560 | PRODUCT_BUNDLE_IDENTIFIER = com.rawd.BlognoneDemoUITests; 561 | PRODUCT_NAME = "$(TARGET_NAME)"; 562 | SWIFT_VERSION = 3.0; 563 | TEST_TARGET_NAME = BlognoneDemo; 564 | }; 565 | name = Release; 566 | }; 567 | /* End XCBuildConfiguration section */ 568 | 569 | /* Begin XCConfigurationList section */ 570 | 3C9F49751EFD4B02008AB676 /* Build configuration list for PBXProject "BlognoneDemo" */ = { 571 | isa = XCConfigurationList; 572 | buildConfigurations = ( 573 | 3C9F49A01EFD4B02008AB676 /* Debug */, 574 | 3C9F49A11EFD4B02008AB676 /* Release */, 575 | ); 576 | defaultConfigurationIsVisible = 0; 577 | defaultConfigurationName = Release; 578 | }; 579 | 3C9F49A21EFD4B02008AB676 /* Build configuration list for PBXNativeTarget "BlognoneDemo" */ = { 580 | isa = XCConfigurationList; 581 | buildConfigurations = ( 582 | 3C9F49A31EFD4B02008AB676 /* Debug */, 583 | 3C9F49A41EFD4B02008AB676 /* Release */, 584 | ); 585 | defaultConfigurationIsVisible = 0; 586 | }; 587 | 3C9F49A51EFD4B02008AB676 /* Build configuration list for PBXNativeTarget "BlognoneDemoTests" */ = { 588 | isa = XCConfigurationList; 589 | buildConfigurations = ( 590 | 3C9F49A61EFD4B02008AB676 /* Debug */, 591 | 3C9F49A71EFD4B02008AB676 /* Release */, 592 | ); 593 | defaultConfigurationIsVisible = 0; 594 | }; 595 | 3C9F49A81EFD4B02008AB676 /* Build configuration list for PBXNativeTarget "BlognoneDemoUITests" */ = { 596 | isa = XCConfigurationList; 597 | buildConfigurations = ( 598 | 3C9F49A91EFD4B02008AB676 /* Debug */, 599 | 3C9F49AA1EFD4B02008AB676 /* Release */, 600 | ); 601 | defaultConfigurationIsVisible = 0; 602 | }; 603 | /* End XCConfigurationList section */ 604 | }; 605 | rootObject = 3C9F49721EFD4B02008AB676 /* Project object */; 606 | } 607 | --------------------------------------------------------------------------------