├── 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 |
--------------------------------------------------------------------------------