From 504e12641cfd54928b542db6dcf1a1e62b56db58 Mon Sep 17 00:00:00 2001 From: Hien Quang Tran Date: Mon, 26 Jun 2017 11:59:05 +0700 Subject: [PATCH] Update to Swift 3 syntax for Chapter 6 --- .../Singleton.xcodeproj/project.pbxproj | 4 + .../xcschemes/Singleton.xcscheme | 91 ++++++++++++++++ .../xcschemes/xcschememanagement.plist | 22 ++++ .../Singleton/Singleton/BackupServer.swift | 10 +- Chapter 06/Singleton/Singleton/Logger.swift | 12 +-- Chapter 06/Singleton/Singleton/main.swift | 10 +- .../SportsStore.xcodeproj/project.pbxproj | 6 ++ .../xcschemes/SportsStore.xcscheme | 101 ++++++++++++++++++ .../xcschemes/xcschememanagement.plist | 27 +++++ .../SportsStore/SportsStore/AppDelegate.swift | 12 +-- .../SportsStore/SportsStore/Logger.swift | 22 ++-- .../SportsStore/SportsStore/Product.swift | 14 +-- .../SportsStore/SportsStore/Utils.swift | 8 +- .../SportsStore/ViewController.swift | 76 ++++++------- .../SportsStoreTests/SportsStoreTests.swift | 2 +- 15 files changed, 334 insertions(+), 83 deletions(-) create mode 100644 Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/Singleton.xcscheme create mode 100644 Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/SportsStore.xcscheme create mode 100644 Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/Chapter 06/Singleton/Singleton.xcodeproj/project.pbxproj b/Chapter 06/Singleton/Singleton.xcodeproj/project.pbxproj index f2fb952..05e612f 100644 --- a/Chapter 06/Singleton/Singleton.xcodeproj/project.pbxproj +++ b/Chapter 06/Singleton/Singleton.xcodeproj/project.pbxproj @@ -99,6 +99,7 @@ TargetAttributes = { 667A1AA419F6A7B200060D1B = { CreatedOnToolsVersion = 6.1; + LastSwiftMigration = 0820; }; }; }; @@ -212,6 +213,7 @@ isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -219,6 +221,7 @@ isa = XCBuildConfiguration; buildSettings = { PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -241,6 +244,7 @@ 667A1AAE19F6A7B200060D1B /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/Singleton.xcscheme b/Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/Singleton.xcscheme new file mode 100644 index 0000000..fd4853d --- /dev/null +++ b/Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/Singleton.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist b/Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..366a72e --- /dev/null +++ b/Chapter 06/Singleton/Singleton.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Singleton.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 667A1AA419F6A7B200060D1B + + primary + + + + + diff --git a/Chapter 06/Singleton/Singleton/BackupServer.swift b/Chapter 06/Singleton/Singleton/BackupServer.swift index 71037ae..defba39 100644 --- a/Chapter 06/Singleton/Singleton/BackupServer.swift +++ b/Chapter 06/Singleton/Singleton/BackupServer.swift @@ -18,16 +18,16 @@ class DataItem { final class BackupServer { let name:String; - private var data = [DataItem](); - private let arrayQ = dispatch_queue_create("arrayQ", DISPATCH_QUEUE_SERIAL); + fileprivate var data = [DataItem](); + fileprivate let arrayQ = DispatchQueue(label: "arrayQ", attributes: []); - private init(name:String) { + fileprivate init(name:String) { self.name = name; globalLogger.log("Created new server \(name)"); } - func backup(item:DataItem) { - dispatch_sync(arrayQ, {() in + func backup(_ item:DataItem) { + arrayQ.sync(execute: {() in self.data.append(item); globalLogger.log( "\(self.name) backed up item of type \(item.type.rawValue)"); diff --git a/Chapter 06/Singleton/Singleton/Logger.swift b/Chapter 06/Singleton/Singleton/Logger.swift index 84448f5..eda8ed8 100644 --- a/Chapter 06/Singleton/Singleton/Logger.swift +++ b/Chapter 06/Singleton/Singleton/Logger.swift @@ -3,23 +3,23 @@ import Foundation; let globalLogger = Logger(); final class Logger { - private var data = [String]() - private let arrayQ = dispatch_queue_create("arrayQ", DISPATCH_QUEUE_SERIAL); + fileprivate var data = [String]() + fileprivate let arrayQ = DispatchQueue(label: "arrayQ", attributes: []); - private init() { + fileprivate init() { // do nothing - required to stop instances being // created by code in other files } - func log(msg:String) { - dispatch_sync(arrayQ, {() in + func log(_ msg:String) { + arrayQ.sync(execute: {() in self.data.append(msg); }); } func printLog() { for msg in data { - println("Log: \(msg)"); + print("Log: \(msg)"); } } } diff --git a/Chapter 06/Singleton/Singleton/main.swift b/Chapter 06/Singleton/Singleton/main.swift index 4480571..2f0c9c6 100644 --- a/Chapter 06/Singleton/Singleton/main.swift +++ b/Chapter 06/Singleton/Singleton/main.swift @@ -2,16 +2,16 @@ import Foundation var server = BackupServer.server; -let queue = dispatch_queue_create("workQueue", DISPATCH_QUEUE_CONCURRENT); -let group = dispatch_group_create(); +let queue = DispatchQueue(label: "workQueue", attributes: DispatchQueue.Attributes.concurrent); +let group = DispatchGroup(); for count in 0 ..< 100 { - dispatch_group_async(group, queue, {() in + queue.async(group: group, execute: {() in BackupServer.server.backup(DataItem(type: DataItem.ItemType.Email, data: "bob@example.com")) }); } -dispatch_group_wait(group, DISPATCH_TIME_FOREVER); +group.wait(timeout: DispatchTime.distantFuture); -println("\(server.getData().count) items were backed up"); +print("\(server.getData().count) items were backed up"); diff --git a/Chapter 06/SportsStore/SportsStore.xcodeproj/project.pbxproj b/Chapter 06/SportsStore/SportsStore.xcodeproj/project.pbxproj index a34a8bb..2a93fab 100644 --- a/Chapter 06/SportsStore/SportsStore.xcodeproj/project.pbxproj +++ b/Chapter 06/SportsStore/SportsStore.xcodeproj/project.pbxproj @@ -170,9 +170,11 @@ TargetAttributes = { 6636F77419F65D24002DE278 = { CreatedOnToolsVersion = 6.1; + LastSwiftMigration = 0820; }; 6636F78919F65D24002DE278 = { CreatedOnToolsVersion = 6.1; + LastSwiftMigration = 0820; TestTargetID = 6636F77419F65D24002DE278; }; }; @@ -353,6 +355,7 @@ INFOPLIST_FILE = SportsStore/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -363,6 +366,7 @@ INFOPLIST_FILE = SportsStore/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -381,6 +385,7 @@ INFOPLIST_FILE = SportsStoreTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SportsStore.app/SportsStore"; }; name = Debug; @@ -396,6 +401,7 @@ INFOPLIST_FILE = SportsStoreTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SportsStore.app/SportsStore"; }; name = Release; diff --git a/Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/SportsStore.xcscheme b/Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/SportsStore.xcscheme new file mode 100644 index 0000000..63a7d87 --- /dev/null +++ b/Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/SportsStore.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist b/Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..f640a73 --- /dev/null +++ b/Chapter 06/SportsStore/SportsStore.xcodeproj/xcuserdata/hienquangtran.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + SportsStore.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 6636F77419F65D24002DE278 + + primary + + + 6636F78919F65D24002DE278 + + primary + + + + + diff --git a/Chapter 06/SportsStore/SportsStore/AppDelegate.swift b/Chapter 06/SportsStore/SportsStore/AppDelegate.swift index 165f0cb..8b23f56 100644 --- a/Chapter 06/SportsStore/SportsStore/AppDelegate.swift +++ b/Chapter 06/SportsStore/SportsStore/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // 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. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // 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. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // 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. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/Chapter 06/SportsStore/SportsStore/Logger.swift b/Chapter 06/SportsStore/SportsStore/Logger.swift index 6864751..898db94 100644 --- a/Chapter 06/SportsStore/SportsStore/Logger.swift +++ b/Chapter 06/SportsStore/SportsStore/Logger.swift @@ -1,35 +1,35 @@ import Foundation let productLogger = Logger(callback: {p in - println("Change: \(p.name) \(p.stockLevel) items in stock"); + print("Change: \(p.name) \(p.stockLevel) items in stock"); }); -final class Logger { +final class Logger where T:NSObject, T:NSCopying { var dataItems:[T] = []; var callback:(T) -> Void; - var arrayQ = dispatch_queue_create("arrayQ", DISPATCH_QUEUE_CONCURRENT); - var callbackQ = dispatch_queue_create("callbackQ", DISPATCH_QUEUE_SERIAL); + var arrayQ = DispatchQueue(label: "arrayQ", attributes: DispatchQueue.Attributes.concurrent); + var callbackQ = DispatchQueue(label: "callbackQ", attributes: []); - private init(callback:T -> Void, protect:Bool = true) { + fileprivate init(callback:@escaping (T) -> Void, protect:Bool = true) { self.callback = callback; if (protect) { self.callback = {(item:T) in - dispatch_sync(self.callbackQ, {() in + self.callbackQ.sync(execute: {() in callback(item); }); }; } } - func logItem(item:T) { - dispatch_barrier_async(arrayQ, {() in - self.dataItems.append(item.copy() as T); + func logItem(_ item:T) { + arrayQ.async(flags: .barrier, execute: {() in + self.dataItems.append(item.copy() as! T); self.callback(item); }); } - func processItems(callback:T -> Void) { - dispatch_sync(arrayQ, {() in + func processItems(_ callback:(T) -> Void) { + arrayQ.sync(execute: {() in for item in self.dataItems { callback(item); } diff --git a/Chapter 06/SportsStore/SportsStore/Product.swift b/Chapter 06/SportsStore/SportsStore/Product.swift index 1cafaa4..670d57c 100644 --- a/Chapter 06/SportsStore/SportsStore/Product.swift +++ b/Chapter 06/SportsStore/SportsStore/Product.swift @@ -2,11 +2,11 @@ import Foundation class Product : NSObject, NSCopying { - private(set) var name:String; - private(set) var productDescription:String; - private(set) var category:String; - private var stockLevelBackingValue:Int = 0; - private var priceBackingValue:Double = 0; + fileprivate(set) var name:String; + fileprivate(set) var productDescription:String; + fileprivate(set) var category:String; + fileprivate var stockLevelBackingValue:Int = 0; + fileprivate var priceBackingValue:Double = 0; init(name:String, description:String, category:String, price:Double, stockLevel:Int) { @@ -25,7 +25,7 @@ class Product : NSObject, NSCopying { set { stockLevelBackingValue = max(0, newValue);} } - private(set) var price:Double { + fileprivate(set) var price:Double { get { return priceBackingValue;} set { priceBackingValue = max(1, newValue);} } @@ -36,7 +36,7 @@ class Product : NSObject, NSCopying { } } - func copyWithZone(zone: NSZone) -> AnyObject { + func copy(with zone: NSZone?) -> Any { return Product(name: self.name, description: self.description, category: self.category, price: self.price, stockLevel: self.stockLevel); diff --git a/Chapter 06/SportsStore/SportsStore/Utils.swift b/Chapter 06/SportsStore/SportsStore/Utils.swift index eb3137e..2d504a9 100644 --- a/Chapter 06/SportsStore/SportsStore/Utils.swift +++ b/Chapter 06/SportsStore/SportsStore/Utils.swift @@ -2,9 +2,9 @@ import Foundation; class Utils { - class func currencyStringFromNumber(number:Double) -> String { - let formatter = NSNumberFormatter(); - formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle; - return formatter.stringFromNumber(number) ?? ""; + class func currencyStringFromNumber(_ number:Double) -> String { + let formatter = NumberFormatter(); + formatter.numberStyle = NumberFormatter.Style.currency; + return formatter.string(from: NSNumber(value: number)) ?? "" } } diff --git a/Chapter 06/SportsStore/SportsStore/ViewController.swift b/Chapter 06/SportsStore/SportsStore/ViewController.swift index 3040875..f22f959 100644 --- a/Chapter 06/SportsStore/SportsStore/ViewController.swift +++ b/Chapter 06/SportsStore/SportsStore/ViewController.swift @@ -7,11 +7,11 @@ class ProductTableCell : UITableViewCell { @IBOutlet weak var stockStepper: UIStepper! @IBOutlet weak var stockField: UITextField! - var product:Product?; + var product: Product?; } var handler = { (p:Product) in - println("Change: \(p.name) \(p.stockLevel) items in stock"); + print("Change: \(p.name) \(p.stockLevel) items in stock"); }; class ViewController: UIViewController, UITableViewDataSource { @@ -23,28 +23,28 @@ class ViewController: UIViewController, UITableViewDataSource { var products = [ Product(name:"Kayak", description:"A boat for one person", - category:"Watersports", price:275.0, stockLevel:10), + category:"Watersports", price:275.0, stockLevel:10), Product(name:"Lifejacket", description:"Protective and fashionable", - category:"Watersports", price:48.95, stockLevel:14), + category:"Watersports", price:48.95, stockLevel:14), Product(name:"Soccer Ball", description:"FIFA-approved size and weight", - category:"Soccer", price:19.5, stockLevel:32), + category:"Soccer", price:19.5, stockLevel:32), Product(name:"Corner Flags", - description:"Give your playing field a professional touch", - category:"Soccer", price:34.95, stockLevel:1), + description:"Give your playing field a professional touch", + category:"Soccer", price:34.95, stockLevel:1), Product(name:"Stadium", description:"Flat-packed 35,000-seat stadium", - category:"Soccer", price:79500.0, stockLevel:4), + category:"Soccer", price:79500.0, stockLevel:4), Product(name:"Thinking Cap", - description:"Improve your brain efficiency by 75%", - category:"Chess", price:16.0, stockLevel:8), + description:"Improve your brain efficiency by 75%", + category:"Chess", price:16.0, stockLevel:8), Product(name:"Unsteady Chair", - description:"Secretly give your opponent a disadvantage", - category: "Chess", price: 29.95, stockLevel:3), + description:"Secretly give your opponent a disadvantage", + category: "Chess", price: 29.95, stockLevel:3), Product(name:"Human Chess Board", - description:"A fun game for the family", category:"Chess", - price:75.0, stockLevel:2), + description:"A fun game for the family", category:"Chess", + price:75.0, stockLevel:2), Product(name:"Bling-Bling King", - description:"Gold-plated, diamond-studded King", - category:"Chess", price:1200.0, stockLevel:4)]; + description:"Gold-plated, diamond-studded King", + category:"Chess", price:1200.0, stockLevel:4)]; override func viewDidLoad() { super.viewDidLoad() @@ -55,34 +55,34 @@ class ViewController: UIViewController, UITableViewDataSource { super.didReceiveMemoryWarning() } - func tableView(tableView: UITableView, - numberOfRowsInSection section: Int) -> Int { - return products.count; + func tableView(_ tableView: UITableView, + numberOfRowsInSection section: Int) -> Int { + return products.count; } - func tableView(tableView: UITableView, - cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let product = products[indexPath.row]; - let cell = tableView.dequeueReusableCellWithIdentifier("ProductCell") - as ProductTableCell; - cell.product = products[indexPath.row]; - cell.nameLabel.text = product.name; - cell.descriptionLabel.text = product.productDescription; - cell.stockStepper.value = Double(product.stockLevel); - cell.stockField.text = String(product.stockLevel); - return cell; + func tableView(_ tableView: UITableView, + cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let product = products[indexPath.row]; + let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell") + as! ProductTableCell; + cell.product = products[indexPath.row]; + cell.nameLabel.text = product.name; + cell.descriptionLabel.text = product.productDescription; + cell.stockStepper.value = Double(product.stockLevel); + cell.stockField.text = String(product.stockLevel); + return cell; } - @IBAction func stockLevelDidChange(sender: AnyObject) { + @IBAction func stockLevelDidChange(_ sender: AnyObject) { if var currentCell = sender as? UIView { while (true) { currentCell = currentCell.superview!; if let cell = currentCell as? ProductTableCell { - if let product = cell.product? { + if let product = cell.product { if let stepper = sender as? UIStepper { product.stockLevel = Int(stepper.value); } else if let textfield = sender as? UITextField { - if let newValue = textfield.text.toInt()? { + if let newValue = Int(textfield.text!) { product.stockLevel = newValue; } } @@ -99,11 +99,11 @@ class ViewController: UIViewController, UITableViewDataSource { func displayStockTotal() { let finalTotals:(Int, Double) = products.reduce((0, 0.0), - {(totals, product) -> (Int, Double) in - return ( - totals.0 + product.stockLevel, - totals.1 + product.stockValue - ); + {(totals, product) -> (Int, Double) in + return ( + totals.0 + product.stockLevel, + totals.1 + product.stockValue + ); }); totalStockLabel.text = "\(finalTotals.0) Products in Stock. " diff --git a/Chapter 06/SportsStore/SportsStoreTests/SportsStoreTests.swift b/Chapter 06/SportsStore/SportsStoreTests/SportsStoreTests.swift index 3924604..bc9b295 100644 --- a/Chapter 06/SportsStore/SportsStoreTests/SportsStoreTests.swift +++ b/Chapter 06/SportsStore/SportsStoreTests/SportsStoreTests.swift @@ -28,7 +28,7 @@ class SportsStoreTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock() { + self.measure() { // Put the code you want to measure the time of here. } }