Repository: danielpi/Swift-Playgrounds
Branch: master
Commit: eae601fb7a63
Files: 139
Total size: 265.8 KB
Directory structure:
gitextract_qixja4zh/
├── .gitignore
├── LICENSE
├── README.md
├── Swift-Playgrounds/
│ ├── Blogs/
│ │ ├── 2014-08-08-LockingInSwift.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── NSHipster/
│ │ │ └── 2014-08-18-SwiftLiteralConvertibles.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ └── Swift Blog/
│ │ ├── 2014-07-23-AccessControl.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── 2014-07-28-InteractingWithCPointers.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── 2014-08-05-Boolean.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── 2014-08-15-ValueAndReferenceTypes.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ └── 2014-08-27-OptionalCaseStudy-valuesForKeys.playground/
│ │ ├── contents.xcplayground
│ │ ├── section-1.swift
│ │ └── timeline.xctimeline
│ ├── Info.plist
│ ├── Others/
│ │ ├── 2014-08-11-SwiftOperators.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── Cheryls-Birthday-Alternative-1.playground/
│ │ │ ├── Contents.swift
│ │ │ ├── Sources/
│ │ │ │ └── SupportCode.swift
│ │ │ └── contents.xcplayground
│ │ ├── Cheryls-Birthday.playground/
│ │ │ ├── Contents.swift
│ │ │ ├── Sources/
│ │ │ │ └── SupportCode.swift
│ │ │ └── contents.xcplayground
│ │ └── WritingSwiftClassesWithObjectiveCBehaviour.playground/
│ │ ├── contents.xcplayground
│ │ ├── section-1.swift
│ │ └── timeline.xctimeline
│ ├── Specific Technologies/
│ │ └── SpriteKit/
│ │ ├── GameDevUniversity.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ └── SpriteKitTestbed.playground/
│ │ ├── Contents.swift
│ │ ├── Sources/
│ │ │ └── SupportCode.swift
│ │ └── contents.xcplayground
│ ├── Swift Stanard Library/
│ │ ├── Array.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── Dictionary.playground/
│ │ │ ├── contents.xcplayground
│ │ │ └── section-1.swift
│ │ ├── FreeFunctions.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── NumericTypes.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── Protocols.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── String.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ └── Undocumented.playground/
│ │ ├── contents.xcplayground
│ │ ├── section-1.swift
│ │ └── timeline.xctimeline
│ ├── The Swift Programming Language/
│ │ ├── ASwiftTour.playground/
│ │ │ ├── Contents.swift
│ │ │ ├── contents.xcplayground
│ │ │ └── timeline.xctimeline
│ │ └── LanguageGuide/
│ │ ├── 01-TheBasics.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 02-BasicOperators.playground/
│ │ │ ├── Contents.swift
│ │ │ ├── contents.xcplayground
│ │ │ └── timeline.xctimeline
│ │ ├── 03-StringsAndCharacters.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 04-CollectionTypes.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 05-ControlFlow.playground/
│ │ │ ├── Contents.swift
│ │ │ ├── contents.xcplayground
│ │ │ └── timeline.xctimeline
│ │ ├── 06-Functions.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 07-Closures.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 08-Enumerations.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 09-ClassesAndStructures.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 10-Properties.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 11-Methods.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 12-Subscripts.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 13-Inheritance.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 14-Initialization.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 15-Deinitialization.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 16-AutomaticReferenceCounting.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 17-OptionalChaining.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 18-ErrorHandling.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 19-TypeCasting.playground/
│ │ │ ├── contents.xcplayground
│ │ │ └── section-1.swift
│ │ ├── 20-NestedTypes.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 21-Extensions.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 22-Protocols.playground/
│ │ │ ├── contents.xcplayground
│ │ │ └── section-1.swift
│ │ ├── 23-Generics.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ ├── 24-AccessControl.playground/
│ │ │ ├── Contents.swift
│ │ │ └── contents.xcplayground
│ │ └── 25-AdvancedOperators.playground/
│ │ ├── contents.xcplayground
│ │ ├── section-1.swift
│ │ └── timeline.xctimeline
│ ├── Using Swift With Cocoa And Objective-C/
│ │ ├── AdoptingCocoaDesignPatterns.playground/
│ │ │ ├── contents.xcplayground
│ │ │ └── section-1.swift
│ │ ├── BasicSetup.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── InteractingWithC-APIs.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ ├── InteractingWithObjective-C-APIs.playground/
│ │ │ ├── contents.xcplayground
│ │ │ └── section-1.swift
│ │ ├── Mix&Match.playground/
│ │ │ ├── contents.xcplayground
│ │ │ ├── section-1.swift
│ │ │ └── timeline.xctimeline
│ │ └── WorkingWithCocoaDataTypes.playground/
│ │ ├── contents.xcplayground
│ │ └── section-1.swift
│ ├── WWDC/
│ │ └── 2014/
│ │ └── AdvancedSwift.playground/
│ │ ├── Contents.swift
│ │ └── contents.xcplayground
│ └── main.swift
├── Swift-Playgrounds.xcodeproj/
│ └── project.pbxproj
└── Thoughts-Questions.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Xcode
.DS_Store
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
*.moved-aside
DerivedData
.idea/
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 Daniel Pink
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Swift Playgrounds
Some experiments with Playgrounds in XCode 8.2 using the Swift programming language.
## The Swift Programming Language Book
I have been working through all the examples in the book Apple Inc. “The Swift Programming Language.” iBooks. https://itunes.apple.com/au/book/swift-programming-language/id881256329?mt=11. Each .playground file in the project relates to a chapter from the Swift Programming Language book.
I have implemented this as a single XCode project that contains a playground file for each chapter of the language reference book. I'm finding it quite useful to have this project open when I am writing Swift code as I can use the project wide search functionality to lookup any Swift features or syntax that I am unsure about (so long as I can remember the words to look for)
Below is a list of each of the files within the project (this is also a list of the chapters of the book that I have worked through).
- **A Swift Tour** contains the code from the "Swift Tour" chapter. It touches on most of the unusual features of the language and is easy to search through to find examples. It is a large file and does tend to give the swift interpreter a rather hard time.
Chapters from the Language guide. Each chapter goes into depth about its particular subject.
- **The Basics** This chapter covers basic value types like Strings, Ints, Bools and floats. The notation for exponent values in float literals is interesting. Comments are covered (nested /* */ comment blocks). TypeAlias is covered as are tuples. Optionals are touched on and assertions are mentioned.
- **Basic Operators** Arithmetic, remainder, increment, decrement, comparison, unary, ternary, range (closed and half-closed) and logical operators. There are examples of all of them.
- **Strings And Characters** Some details about Unicode literals (multi-byte characters). The countElements() function for finding the length of a string. Concatenating strings, Comparing strings and Interpolating strings (not much on splitting or parsing strings).
- **Collection Types**
- **ControlFlow**
- **Functions**
- **Closures**
- **Enumerations**
- **Classes And Structures**
- **Properties**
- **Methods**
- **Subscripts**
- **Inheritance**
- **Initialization**
- **Deinitialization**
- **Automatic Reference Counting**
- **Optional Chaining**
- **Type Casting**
- **Nested Types**
- **Extensions**
- **Protocols**
- **Generics**
- **Advanced Operators**
## Using Swift with Cocoa and Objective-C Book
There are six playground files that work through the code in the “Using Swift with Cocoa and Objective-C.” iBook. https://itunes.apple.com/au/book/using-swift-cocoa-objective/id888894773?mt=11. They are listed below. The example from this book didn't translate as well to the playgrounds as the previous book examples did.
- **Basic Setup**
- **Interacting With Objective-C-**
- **Writing Classes With Objective C Behaviour**
- **Working With Cocoa Data Types**
- **Adopting Cocoa Design Patterns**
- **InteractingWith C**
## Swift Standard Library
The documentation for the Swift Standard Library can be found at the following link https://developer.apple.com/library/prerelease/ios/documentation/General/Reference/SwiftStandardLibraryReference/. There is a wealth of information contained in the standard library doc and it is nicely organised so that it is easy to experiment with in a playground environment. I have attempted to extend the examples somewhat to try and show off some of the other features of the standard library.
- **String**
- **Array**
- **Dictionary**
- **NumericTypes**
- **Protocols**
- **FreeFunctions**
- **Undocumented**
## Swift Blog
The Swift blog contains several articles detailing interesting information about the developing language.
- **2014-08-15 Value and Reference Types**
- **2014-08-05 Boolean**
- **2014-07-28 Interacting with C Pointers**
- **2014-07-23 Access Control**
## NSHipster
Lots of great articles delving into the finer points of Cocoa programming. The recent articles on Swift are always interesting to go through
- **2014-08-08 Swift Literal Convertibles** Shows how you can create types of your own that can be written as literals when you use them.
# What next?
Here are some links to other projects around the web that I would also like to implement
- **Peter Norvig** has some great posts that delve into various programming topics. Mostly they are in Python though so it would be interesting to implement them in Swift.
- http://norvig.com/spell-correct.html http://airspeedvelocity.net/2015/05/02/spelling/
- http://nbviewer.ipython.org/url/norvig.com/ipython/TSPv3.ipynb
- **Erica Sandun** Has a book out and also publishes a lot of information about Swift Playgrounds. In particular she is able to get impressive graphics, windows and user inputs to work, which is something that I haven't figured out yet.
- http://ericasadun.com/2015/05/04/swift-using-functions-to-initialize-view-types/
================================================
FILE: Swift-Playgrounds/Blogs/2014-08-08-LockingInSwift.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Blogs/2014-08-08-LockingInSwift.playground/section-1.swift
================================================
// Locking in Swift blog post by John Gallagher
// http://www.bignerdranch.com/blog/locking-in-swift-helping-protect-me-from-myself/
import Cocoa
import Foundation
import dispatch
// The Setup
// Writing a class that includes an array of things and a timestamp of when the array was last modified.
/*
class ArrayTracker {
private var things: [T] = []
private var lastModified: NSDate? // Why is this optional?
func appendToThings(item: T) -> (NSDate, Int) {
things.append(item)
lastModified = NSDate.date()
return (lastModified!, things.count)
}
func lastModifiedDate() -> NSDate? {
return lastModified
}
}
var a: ArrayTracker = ArrayTracker()
let (l1, c1) = a.appendToThings(1234)
l1
c1
a.appendToThings(5678)
a.appendToThings(4)
*/
/*
// The Lock
// We want a readers-writer lock. Multiple readers can access the lock concurrently but only a single writer can have access at a time.
protocol ReadWriteLock {
// Get a shared reader lock, run the given block, and unlock
mutating func withReadLock(block: () -> ())
// get an exclusive writer lock, run the given block, and unlock
mutating func withWriteLock(block: () -> ())
}
struct MyLock: ReadWriteLock {
let queue = dispatch_queue_create("readWriteLock", dispatch.DISPATCH_QUEUE_CONCURRENT)
mutating func withReadLock(block: () -> ()) {
dispatch_async(queue, block)
}
mutating func withWriteLock(block: () -> ()) {
dispatch_barrier_async(queue, block)
}
}
class ArrayTracker {
private var things: [T] = []
private var lock: ReadWriteLock = MyLock()
private var lastModified: NSDate?
func lastModifiedDate() -> NSDate? {
var date: NSDate?
// withReadLock runs the block its given synchronously, so we don't need to capture self - use unowned
lock.withReadLock { [unowned self] in
date = self.lastModified
}
return date
}
func appendToThings(item: T) -> (NSDate, Int) {
var date: NSDate!
var count: Int!
lock.withWriteLock { [unowned self] in
self.things.append(item)
self.lastModified = NSDate.date()
date = self.lastModified
count = self.things.count
}
return (date, count)
}
}
*/
let address = 0xFFFE
address % 0xFFFF
protocol ReadWriteLock {
// Get a shared reader lock, run the given block, unlock, and return whatever the block returned
mutating func withReadLock(block: () -> T) -> T
// Get an exclusive writer lock, run the given block, unlock, and return whatever the block returned
mutating func withWriteLock(block: () -> T) -> T
}
/*
struct MyLock: ReadWriteLock {
let queue = dispatch_queue_create("readWriteLock", dispatch.DISPATCH_QUEUE_CONCURRENT)
mutating func withReadLock(block: () -> T) -> T {
var result: T
dispatch_sync(queue) {
result = block()
}
return result
}
mutating func withWriteLock(block: () -> T) -> T {
var result: T
dispatch_barrier_sync(queue) {
result = block()
}
return result
}
}
class ArrayTracker {
private var things: [T] = []
private var lock: ReadWriteLock = MyLock()
private var lastModified: NSDate?
func lastModifiedDate() -> NSDate? {
// return the result of the call to withReadLock...
return lock.withReadLock { [unowned self] in
// ... which is the date that we want
return self.lastModified
}
}
func appendToThings(item: T) -> (NSDate, Int) {
return lock.withWriteLock { [unowned self] in
self.things.append(item)
self.lastModified = NSDate.date()
return (self.lastModified!, self.things.count)
}
}
}
*/
================================================
FILE: Swift-Playgrounds/Blogs/2014-08-08-LockingInSwift.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Blogs/NSHipster/2014-08-18-SwiftLiteralConvertibles.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Blogs/NSHipster/2014-08-18-SwiftLiteralConvertibles.playground/section-1.swift
================================================
// Swift Literal Convertibles from NSHipster http://nshipster.com/swift-literal-convertible/
import Foundation
/*
enum Optional : Reflectable, NilLiteralConvertible {
case None
case Some(T)
init()
init(_ some: T)
var hasValue: Bool { get }
func map(f: (T) -> U) -> U?
func getMirror() -> MirrorType
static func convertFromNilLiteral() -> T?
}
*/ // Doesn't seem to work
struct Regex {
let pattern: String
let options: NSRegularExpressionOptions!
private var matcher: NSRegularExpression {
return NSRegularExpression(pattern: self.pattern, options: self.options, error: nil)
}
init(pattern: String, options: NSRegularExpressionOptions = nil) {
self.pattern = pattern
self.options = options
}
func match(string: String, options: NSMatchingOptions = nil) -> Bool {
return self.matcher.numberOfMatchesInString(string, options: options, range: NSMakeRange(0, string.utf16Count)) != 0
}
}
extension Regex: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType
static func convertFromExtendedGraphemeClusterLiteral(value: ExtendedGraphemeClusterLiteralType) -> Regex {
return self(pattern: value)
}
static func convertFromStringLiteral(value: StringLiteralType) -> Regex {
return self(pattern: value)
}
}
let string: String = "foo bar baz"
let regex: Regex = "foo"
regex.match(string)
"foo".match(string)
// ArrayLiteralConvertible and Sets
struct Set {
typealias Index = T
private var dictionary: [T: Bool]
init() {
self.dictionary = [T: Bool]()
}
var count: Int {
return self.dictionary.count
}
var isEmpty: Bool {
return self.dictionary.isEmpty
}
func contains(element: T) -> Bool {
return self.dictionary[element] ?? false
}
mutating func put(element: T) {
self.dictionary[element] = true
}
mutating func remove(element: T) -> Bool {
if self.contains(element) {
self.dictionary.removeValueForKey(element)
return true
} else {
return false
}
}
}
var basicSet: Set = Set()
basicSet.put(1)
basicSet.put(2)
basicSet.put(3)
basicSet.contains(1)
basicSet.count
extension Set: ArrayLiteralConvertible {
static func convertFromArrayLiteral(elements: T...) -> Set {
var set = Set()
for element in elements {
set.put(element)
}
return set
}
}
let set: Set = [1, 2, 3]
set.contains(1)
set.count
// StringLitralConvertible and URLs
extension NSURL: StringLiteralConvertible {
public class func convertFromExtendedGraphemeClusterLiteral(value: String) -> Self {
return self(string: value)
}
public class func convertFromStringLiteral(value: String) -> Self {
return self(string: value)
}
}
"http://nshipster.com/".host
================================================
FILE: Swift-Playgrounds/Blogs/NSHipster/2014-08-18-SwiftLiteralConvertibles.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-07-23-AccessControl.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-07-23-AccessControl.playground/section-1.swift
================================================
// Playground - noun: a place where people can play
import Cocoa
import Foundation
public class ListItem {
// Public properties.
public var text: String
public var isComplete: Bool
// Readable throughout the module, but only writable from within this file.
private(set) var UUID: NSUUID
public init(text: String, completed: Bool, UUID: NSUUID) {
self.text = text
self.isComplete = completed
self.UUID = UUID
}
// Usable within the framework target, but not by other targets.
func refreshIdentity() {
self.UUID = NSUUID()
}
public func isEqual(object: AnyObject?) -> Bool {
if let item = object as? ListItem {
return self.UUID == item.UUID
}
return false
}
}
let item1 = ListItem(text: "Item 1", completed: false, UUID: NSUUID())
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-07-23-AccessControl.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-07-28-InteractingWithCPointers.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-07-28-InteractingWithCPointers.playground/section-1.swift
================================================
// Playground - noun: a place where people can play
import Cocoa
import CoreGraphics
import XCPlayground
import Accelerate
var color = NSColor.magentaColor()
var r: CGFloat = 0, g: CGFloat = 0, b: CGFloat = 0, a: CGFloat = 0
color.getRed(&r, green: &g, blue: &b, alpha: &a)
var maybeError: NSError?
if let contents = NSFileManager.defaultManager().contentsOfDirectoryAtPath("/usr/bin", error: &maybeError) {
println("\(contents)")
} else if let error = maybeError {
println("\(error)")
}
let x: [Float] = [1, 2, 3, 4]
let y: [Float] = [0.5, 0.25, 0.125, 0.0625]
var result:[Float] = [0, 0, 0, 0]
vDSP_vadd(x, 1, y, 1, &result, 1, 4)
result
puts("Hello fromlibc")
let fd = open("/tmp/scratch.txt", O_WRONLY|O_CREAT, 0o666)
if fd < 0 {
perror("could not open /tmp/scratch.txt")
} else {
let text = "Hello World"
write(fd, text, strlen(text))
close(fd)
}
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-07-28-InteractingWithCPointers.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-05-Boolean.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-05-Boolean.playground/section-1.swift
================================================
// Playground - noun: a place where people can play
import Cocoa
enum MyBool {
case myTrue, myFalse
}
var a: MyBool = MyBool.myTrue
extension MyBool {
init() { self = .myFalse }
}
var b: MyBool = MyBool()
extension MyBool : BooleanLiteralConvertible {
static func convertFromBooleanLiteral(value: Bool) -> MyBool {
return value ? myTrue : myFalse
}
}
var c: MyBool = true
extension MyBool : BooleanType {
var boolValue: Bool {
get {
switch self {
case .myTrue: return true
case .myFalse: return false
}
}
}
}
if a { println("a is true") }
extension MyBool {
//MyBool can be constructed from BooleanType
init(_ v : BooleanType) {
if v.boolValue {
self = .myTrue
} else {
self = .myFalse
}
}
}
var basicBool:Bool = false
a = MyBool(basicBool)
if a { println("a is true") } else { println("a is false") }
/*
// Simple enums that have no associated data (like MyBool) are automatically made Equatable by the compiler, so no additional code is required.
extension MyBool : Equatable {
}
func ==(lhs: MyBool, rhs: MyBool) -> Bool {
switch (lhs, rhs) {
case (.myTrue, .myTrue), (.myFalse, .myFalse):
return true
default:
return false
}
}
*/
if a == a { println("a == a") }
if a != a { } else { println("!(a != a)") }
// Binary operations
func &(lhs:MyBool, rhs: MyBool) -> MyBool {
if lhs {
return rhs
}
return false
}
func |(lhs: MyBool, rhs: MyBool) -> MyBool {
if lhs {
return true
}
return rhs
}
func ^(lhs: MyBool, rhs: MyBool) -> MyBool {
return MyBool(lhs != rhs)
}
a & b
b | c
c ^ a
prefix func !(a: MyBool) -> MyBool {
return a ^ true
}
// Compound assignment (with bitwise and)
func &=(inout lhs: MyBool, rhs: MyBool) {
lhs = lhs & rhs
}
!a
a &= b
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-05-Boolean.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-15-ValueAndReferenceTypes.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-15-ValueAndReferenceTypes.playground/section-1.swift
================================================
// Value and Reference Types
import Foundation
// Value type example
struct S { var data: Int = -1 }
var a = S()
var b = a // a is copied to b
a.data = 42 // Changes a, not b
println("\(a.data), \(b.data)")
// Reference type example
class C { var data: Int = -1 }
var x = C()
var y = x // x is copied to y
x.data = 42 // changes the instance referred to by x (and y)
println("\(x.data), \(y.data)")
// Use a value type when:
// - Comparing instance data with == makes sense
// - You want copies to have independent state
// - The data will be used in code across multiple threads
// Use a reference type when:
// - Comparing instance identity with === makes sense
// - You want to create shared, mutable state
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-15-ValueAndReferenceTypes.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-27-OptionalCaseStudy-valuesForKeys.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-27-OptionalCaseStudy-valuesForKeys.playground/section-1.swift
================================================
// Optional Case Study: valuesForKeys
import Foundation
/*
extension Dictionary {
func valuesForKeys(keys: [K], notFoundMarkery: V) -> [V] {
// to be implemented
}
}
*/
/* Beta 6 seems to report that .reserve doesn't exist?
extension Dictionary {
func valuesForKeys(keys: [Key]) -> [Value?] {
var result = [Value?]()
result.reserve(keys.count)
for key in keys {
result.append(self[key])
}
return result
}
}
*/
extension Dictionary {
func valuesForKeys(keys: [Key]) -> [Value?] {
return keys.map { self[$0] }
}
}
let dict = ["A": "Amir", "B": "Bertha", "C": "Ching"]
dict.valuesForKeys(["A", "C"])
dict.valuesForKeys(["B", "D"])
// Nested Optionals
dict.valuesForKeys(["A", "C"]).last
dict.valuesForKeys(["B", "D"]).last
dict.valuesForKeys([]).last
// Providing a Default
extension Dictionary {
func valuesForKeys(keys: [Key], notFoundMarker: Value) -> [Value] {
return self.valuesForKeys(keys).map { $0 ?? notFoundMarker }
}
}
dict.valuesForKeys(["B", "D"], notFoundMarker: "Anonymous")
================================================
FILE: Swift-Playgrounds/Blogs/Swift Blog/2014-08-27-OptionalCaseStudy-valuesForKeys.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Info.plist
================================================
CFBundleDevelopmentRegion
en
CFBundleExecutable
${EXECUTABLE_NAME}
CFBundleIconFile
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
${PRODUCT_NAME}
CFBundlePackageType
APPL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
LSMinimumSystemVersion
${MACOSX_DEPLOYMENT_TARGET}
NSHumanReadableCopyright
Copyright © 2014 Electronic Innovations. All rights reserved.
NSMainNibFile
MainMenu
NSPrincipalClass
NSApplication
================================================
FILE: Swift-Playgrounds/Others/2014-08-11-SwiftOperators.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Others/2014-08-11-SwiftOperators.playground/section-1.swift
================================================
// Swift Operators - http://nshipster.com/swift-operators/
import Cocoa
// Overloading
func * (left: String, right: Int) -> String {
if right <= 0 {
return ""
}
var result = left
for _ in 1.. [Double] {
var sum = [Double](count: left.count, repeatedValue: 0.0)
for (i, _) in enumerate(left) {
sum[i] = left[i] + right[i]
}
return sum
}
println("\([1, 2] + [3, 4])")
func +(left: [Int], right: [Int]) -> [Int] {
var sum = [Int](count: left.count, repeatedValue: 0)
for (i, _) in enumerate(left) {
sum[i] = left[i] + right[i]
}
return sum
}
println("\([1, 2] + [3, 4])")
// I'm specifically concerned about the semantics of array operators, as demonstrated in the previous example. My 2 cents: arrays should forego the + and - operators in lieu of <<:
func << (inout left: [T], right: [T]) -> [T] {
//left.extend(right)
return left
}
func << (inout left: [T], right: T) -> [T] {
//left.append(right)
return left
}
//[1,2,3,4]<<[5,6]
//[1,2,3,4]<<5
// Custom Operators
infix operator ** { associativity left precedence 160 }
func ** (left: Double, right: Double) -> Double {
return pow(left, right)
}
2 ** 3 // 8
// When creating custom operators, make sure to also create the corresponding assignment operator, if appropriate:
infix operator **= { associativity right precedence 90 }
func **= (inout left: Double, right: Double) {
left = left ** right
}
// Custom Operators with Protocol and Method
// First, a RegularExpressionMatchable protocol is declared, with a single method for matching regular expressions.
protocol RegularExpressionMatchable {
func match(pattern: String, options: NSRegularExpressionOptions) -> Bool
}
// Next, an extension adding conformance to this protocol to String is declared, with a provided implementation of match, using NSRegularExpression.
extension String: RegularExpressionMatchable {
func match(pattern: String, options: NSRegularExpressionOptions = nil) -> Bool {
let regex = NSRegularExpression(pattern: pattern, options: nil, error: nil)
return regex.numberOfMatchesInString(self, options: nil, range: NSMakeRange(0, self.utf16Count)) != 0
}
}
// Finally, the =~ operator is declared and implemented on a generic type conforming to RegularExpressionMatchable.
infix operator =~ { associativity left precedence 130 }
func =~ (left: T, right: String) -> Bool {
return left.match(right, options: nil)
}
// By doing this, a user has the option to use the match function instead of the operator. It also has the added benefit of greater flexibility in what options are passed into the method.
// Use of Mathematical Symbols
prefix operator √ {}
prefix func √ (number: Double) -> Double {
return sqrt(number)
}
√16
√2
infix operator ± { associativity left precedence 140 }
func ± (left: Double, right: Double) -> (Double, Double) {
return (left + right, left - right)
}
prefix operator ± {}
prefix func ± (value: Double) -> (Double, Double) {
return 0 ± value
}
2 ± 3
±4
// Guidelines for Swift Operators
// Don't create an operator unless its meaning is obvious and undisputed. Seek out any potential conflicts to ensure semantic consistency.
// Custom operators should only be provided as a convenience. Complex functionality should always be implemented in a function, preferably one specified as a generic using a custom protocol.
// Pay attention to the precedence and associativity of custom operators. Find the closest existing class of operators and use the appropriate precedence value.
// If it makes sense, be sure to implement assignment shorthand for a custom operator (e.g. += for +).
================================================
FILE: Swift-Playgrounds/Others/2014-08-11-SwiftOperators.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Others/Cheryls-Birthday-Alternative-1.playground/Contents.swift
================================================
// When is Cheryl's Birthday
// adapted from Peter Norvig's code in http://nbviewer.ipython.org/url/norvig.com/ipython/Cheryl.ipynb
import Cocoa
// 1. Albert and Bernard just became friends with Cheryl, and they want to know when her birthday is. Cheryl gave them a list of 10 possible dates:
// May 15 May 16 May 19
// June 17 June 18
// July 14 July 16
// August 14 August 15 August 17
// 2. Cheryl then tells Albert and Bernard seperately the month and day of the birthday respectively.
// 3. Albert : I don't know when Cheryl's birthday is, but I know that Bernard does not know too.
// 4. Bernard : At first I don't know when Cheryl's birthday is, but I know now.
// 5. Albert : Then I also know when Cheryls birthday is.
// So when is Cheryl's Birthday?
let dates = ["May 15", "May 16", "May 19",
"June 17", "June 18",
"July 14", "July 16",
"August 14", "August 15", "August 17"]
func Month(date: String) -> String {
return date.componentsSeparatedByString(" ")[0]
}
Month("May 15")
func Day(date: String) -> String {
return date.componentsSeparatedByString(" ")[1]
}
Day("May 15")
func tell(part: String, possibleDates: [String]) -> [String] {
return possibleDates.filter(){ $0.rangeOfString(part) != nil }
}
tell("May", possibleDates: dates)
tell("15", possibleDates: dates)
tell("18", possibleDates: dates)
func know(possibleDates: [String]) -> Bool {
return possibleDates.count == 1
}
know(tell("15", possibleDates: dates))
// Overall Strategy
// When Cheryl tells Albert "May" then he knows there are three possibilities, but we (the puzzle solvers) don't, because we don't know what Cheryl said. So what can we do? We will consider all of the possible dates, one at a time. For example, first consider "May 15". Cheryl tells Albert "May" and Bernard "15", giving them the lists of possible birthdates shown above. We can then check whether statements 3 through 5 are true in this scenario. If they are, then "May 15" is a solution to the puzzle. Repeat the process for each of the possible dates. If all goes well, there should be exactly one solution.
func not(value: Bool) -> Bool { return !value }
// Bernard: I don't know when Cheryl's birthday is.
// Albert: I don't know when Cheryl's birthday is, but I know that Bernard doesn't know too [because he just said so].
// Bernard: At first I didn't know when Cheryl's birthday is, but I know now.
// Albert: Then I also know when Cheryl's birthday is.
// Bernard: I don't know when Cheryl's birthday is.
func statement2(date: String) -> Bool {
let bernardPossibleDates = tell(Day(date), possibleDates: dates)
return not(know(bernardPossibleDates))
}
let statementTwo = dates.filter(statement2)
/// Albert: I don't know when Cheryl's birthday is, but I know that Bernard doesn't know too [because he just said so].
func statement3(date: String) -> Bool {
let albertPossibleDates = tell(Month(date), possibleDates: dates)
return not(know(albertPossibleDates)) && not(know(albertPossibleDates.filter(statement2)))}
let statementThree = dates.filter(statement3)
// Bernard: At first I didn't know when Cheryl's birthday is, but I know now.
func statement4(date: String) -> Bool {
let atFirst = tell(Day(date), possibleDates: dates)
//println("\(not(know(atFirst))),\(know(filter(atFirst, statement3)))")
return not(know(atFirst)) && know(atFirst.filter(statement3))
}
let statementFour = dates.filter(statement4)
// The dates which satisfy both statement 3 and 4 are
//let statementThreeAndFour = filter(statementThree, statement4)
// Albert: Then I also know when Cheryl's birthday is
func statement5(date: String) -> Bool {
let months = tell(Month(date), possibleDates: dates)
return know(months.filter(statement4))
}
let statementFive = dates.filter(statement5)
func statements3to5(date: String) -> Bool {
return statement2(date) && statement3(date) && statement4(date) && statement5(date)
}
func cherylsBirthday(possibleDates: [String]) -> [String]
================================================
FILE: Swift-Playgrounds/Others/Cheryls-Birthday-Alternative-1.playground/Sources/SupportCode.swift
================================================
//
// This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to Cheryls-Birthday-Alternative-1.playground.
//
================================================
FILE: Swift-Playgrounds/Others/Cheryls-Birthday-Alternative-1.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Others/Cheryls-Birthday.playground/Contents.swift
================================================
// When is Cheryl's Birthday
// adapted from Peter Norvig's code in http://nbviewer.ipython.org/url/norvig.com/ipython/Cheryl.ipynb
import Cocoa
// 1. Albert and Bernard just became friends with Cheryl, and they want to know when her birthday is. Cheryl gave them a list of 10 possible dates:
// May 15 May 16 May 19
// June 17 June 18
// July 14 July 16
// August 14 August 15 August 17
// 2. Cheryl then tells Albert and Bernard seperately the month and day of the birthday respectively.
// 3. Albert : I don't know when Cheryl's birthday is, but I know that Bernard does not know too.
// 4. Bernard : At first I don't know when Cheryl's birthday is, but I know now.
// 5. Albert : Then I also know when Cheryls birthday is.
// So when is Cheryl's Birthday?
let dates = ["May 15", "May 16", "May 19",
"June 17", "June 18",
"July 14", "July 16",
"August 14", "August 15", "August 17"]
func Month(date: String) -> String {
return date.componentsSeparatedByString(" ")[0]
}
Month("May 15")
func Day(date: String) -> String {
return date.componentsSeparatedByString(" ")[1]
}
Day("May 15")
func tell(part: String, possibleDates: [String]) -> [String] {
return possibleDates.filter(){ $0.rangeOfString(part) != nil }
}
tell("May", possibleDates: dates)
tell("15", possibleDates: dates)
func know(possibleDates: [String]) -> Bool {
return possibleDates.count == 1
}
know(tell("15", possibleDates: dates))
// Overall Strategy
// When Cheryl tells Albert "May" then he knows there are three possibilities, but we (the puzzle solvers) don't, because we don't know what Cheryl said. So what can we do? We will consider all of the possible dates, one at a time. For example, first consider "May 15". Cheryl tells Albert "May" and Bernard "15", giving them the lists of possible birthdates shown above. We can then check whether statements 3 through 5 are true in this scenario. If they are, then "May 15" is a solution to the puzzle. Repeat the process for each of the possible dates. If all goes well, there should be exactly one solution.
func not(value: Bool) -> Bool { return !value }
// Albert: After Cheryl told me the month of her birthdate, I didn't know her birthday. I don't know which day Cheryl told Bernard, but I know that for all of the possible dates, if Bernard is told that day, he wouldn't know the birthdate.
func statement3(date: String) -> Bool {
let albertPossibleDates = tell(Month(date), possibleDates: dates)
var result = not(know(albertPossibleDates)) // Confirm that Albert doesn't know the date
for d in albertPossibleDates {
result = result && not(know(tell(Day(d), dates)))
}
return result
}
statement3("May 15")
let statementThree = dates.filter(statement3)
print("Dates satisfied by Statement 3: \(statementThree)")
// Bernard: At first Cheryl told me the day, and I didn't know. Then I considered just the dates for which Albert's statement3 is true, and now I know.
func statement4(date: String) -> Bool {
let atFirst = tell(Day(date), possibleDates: dates)
return not(know(atFirst)) && know(atFirst.filter(statement3))
}
// The dates which satisfy both statement 3 and 4 are
let statementThreeAndFour = statementThree.filter(statement4)
print("Dates satisfied by Statement 3 & 4: \(statementThreeAndFour)")
// Albert: Then I also know when Cheryl's birthday is
func statement5(date: String) -> Bool {
let months = tell(Month(date), possibleDates: dates)
return know(months.filter(statement4))
}
statement5("May 15")
let statementFive = dates.filter(statement5)
print("Dates satisfied by Statement 5: \(statementFive)")
func statements3to5(date: String) -> Bool {
return statement3(date) && statement4(date) && statement5(date)
}
func cherylsBirthday(possibleDates: [String]) -> [String] {
return possibleDates.filter
================================================
FILE: Swift-Playgrounds/Others/Cheryls-Birthday.playground/Sources/SupportCode.swift
================================================
//
// This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to Cheryls-Birthday.playground.
//
================================================
FILE: Swift-Playgrounds/Others/Cheryls-Birthday.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Others/WritingSwiftClassesWithObjectiveCBehaviour.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Others/WritingSwiftClassesWithObjectiveCBehaviour.playground/section-1.swift
================================================
// Writing Swift Classes with Objective-C Behaviour
// You can
// - subclass Objective-C classes,
// - adopt Objective-C protocols,
// - take advantage of other Objective-C functionality
// when writing a Swift class.
// Inheriting from Objecive-C Classes
import UIKit
class MySwiftViewController: UIViewController {
}
// Adopting Protocols
/*
class AnotherSwiftViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
}
*/
// Interacting with Interface Builder
// Working with Oulets and Actions
//
// When you declare an outlet in Swift,
// - the compiler automatically converts the type to a weak implicitly unwrapped optional
// - assigns it an initial value of nil
// The compiler replaces @IBOutlet var name: Type with @IBOutlet weak var name: Type! = nil.
// The compiler converts the type to an implicitly unwrapped optional so that you aren’t required to assign a value in an initializer. It is implicitly unwrapped because after your class is initialized from a storyboard or xib file, you can assume that the outlet has been connected. Outlets are weak by default because the outlets you create usually have weak relationships.
class YetAnotherSwiftViewController: UIViewController {
@IBOutlet var button: UIButton!
//@IBOutlet var textFields: [UITextField]
@IBAction func buttonTapped(_: AnyObject) {
print("button tapped!")
}
}
// Live Rendering
// @IBDesignable, allows for live rendering of a custom view in IB
// When you create a custom view that inherits from UIView or NSView, you can add the @IBDesignable attribute just before the class declaration. After you add the custom view to Interface Builder (by setting the custom class of the view in the inspector pane), Interface Builder renders your view in the canvas.
// @IBInspectable, allows you to change property values of your custom classes from IB
// You can also add the @IBInspectable attribute to properties with types compatible with user defined runtime attributes. After you add your custom view to Interface Builder, you can edit these properties in the inspector.
@IBDesignable
class DesignableCustomView: UIView {
@IBInspectable var textColor: UIColor = UIColor(hue: 0.0, saturation: 0.9, brightness: 0.8, alpha: 1.0)
@IBInspectable var iconHeight: CGFloat = 0.0
}
// Specifying Property Attributes
// Swift properties are strong by default. Use the weak keyword if required. Weak properties must be optional class types.
// There are no readwrite and readonly attributes in swift. Use let for read only and var for read/write properties.
// In Swift, the Objective-C copy property attribute translates to @NSCopying.
// Implementing Core Data Managed Object Subclasses
// “Add the @NSManaged attribute before each property definition in your managed object subclass that corresponds to an attribute or relationship in your Core Data model. Like the @dynamic attribute in Objective-C, the @NSManaged attribute informs the Swift compiler that the storage and implementation of a property will be provided at runtime.
var textColor: UIColor = UIColor(hue: 0.0, saturation: 0.9, brightness: 0.8, alpha: 1.0)
var textColorArray: [UIColor] = []
for i in 0..<10 {
let sat = 0.1 * Float(i)
var textColor: UIColor = UIColor(hue: CGFloat(sat), saturation: 0.7, brightness: 0.5, alpha: 0.9)
textColorArray.append(textColor)
}
textColorArray
================================================
FILE: Swift-Playgrounds/Others/WritingSwiftClassesWithObjectiveCBehaviour.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Specific Technologies/SpriteKit/GameDevUniversity.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Specific Technologies/SpriteKit/GameDevUniversity.playground/section-1.swift
================================================
// Example from http://gamedevuniversity.com/swift-playground-spritekit/
// Import SpriteKit API and XCPlayground
import SpriteKit
import XCPlayground
// Extend the SKScene to create a new Scene
class GameScene:SKScene {
required init(coder: NSCoder!) {
super.init(coder: coder)
}
override init(size: CGSize) {
super.init(size: size)
}
override func didMoveToView(view: SKView!) {
// Create an Array of SKSprite
var monsters = [SKSpriteNode]()
// Load SKSprite to the array
// Append is similar to Array push()
// Note that resources in Playground are imported using their full path
// Creative Commons – Attribution (CC BY 3.0) Monster designed by Ana Lourenço from the Noun Project
// http://thenounproject.com/term/monster/56811/
monsters.append(SKSpriteNode(imageNamed: "/Users/danielpi/repos/Swift-Playgrounds/Swift-Playgrounds/SpriteKit/icon_56811.png"))
monsters.append(SKSpriteNode(imageNamed: "/Users/danielpi/repos/Swift-Playgrounds/Swift-Playgrounds/SpriteKit/icon_56811.png"))
monsters.append(SKSpriteNode(imageNamed: "/Users/danielpi/repos/Swift-Playgrounds/Swift-Playgrounds/SpriteKit/icon_56811.png"))
// Loop through SKSprite array
for var i=0; i<3; i++ {
var monster = monsters[i]
// Position the Sprite randomly
var xPos = CGFloat(UInt(arc4random()) % (500 - UInt(monster.size.width)) + UInt(monster.size.width) / 2)
var yPos = CGFloat(UInt(arc4random()) % (500 - UInt(monster.size.height)) + UInt(monster.size.height) / 2)
monster.position = CGPoint(x: xPos, y: yPos)
// Add Sprite to Scene
self.addChild(monster)
}
}
override func update(currentTime: NSTimeInterval) {
}
}
// Create a new instance of GameScene (created above)
let scene = GameScene(size: CGSize(width: 500, height: 500))
// Create a view
let view = SKView(frame: NSRect(x: 0, y: 0, width: 500, height: 500))
// Present the Scene using our view
view.presentScene(scene)
// Use this method to render the final scene
XCPShowView("result", view)
================================================
FILE: Swift-Playgrounds/Specific Technologies/SpriteKit/GameDevUniversity.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Specific Technologies/SpriteKit/SpriteKitTestbed.playground/Contents.swift
================================================
import Cocoa
import SpriteKit
import XCPlayground
// Credit to http://ericasadun.com/2015/04/22/swift-simple-spritekit-experimentation/
// Build scene and view
let sceneSize = CGSizeMake(400.0, 300.0)
let view = SKView(frame: CGRect(origin: CGPointZero, size: sceneSize))
var scene = SKScene(size: sceneSize)
scene.backgroundColor = SKColor.lightGrayColor()
XCPShowView("Scene", view: view)
view.presentScene(scene)
var shape1 = SKShapeNode(circleOfRadius: 20.0)
shape1.fillColor = SKColor.redColor()
scene.addChild(shape1)
shape1.position = CGPointMake(200.0, 150.0)
var action = SKAction.repeatActionForever(SKAction.moveBy(CGVectorMake(0.02, 0.1), duration: 0.01))
shape1.runAction(ac
================================================
FILE: Swift-Playgrounds/Specific Technologies/SpriteKit/SpriteKitTestbed.playground/Sources/SupportCode.swift
================================================
//
// This file (and all other Swift source files in the Sources directory of this playground) will be precompiled into a framework which is automatically made available to SpriteKitTestbed.playground.
//
================================================
FILE: Swift-Playgrounds/Specific Technologies/SpriteKit/SpriteKitTestbed.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Array.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Array.playground/section-1.swift
================================================
// Swift Standard Library - Types - Array
// An Array is a generic type that manages an ordered collection of items, all of which must be of the same underlying type.
// Creating and Array
var emptyArray = Array()
var equivilentEmptyArray = [Int]()
let numericArray = Array(count: 3, repeatedValue: 42)
let stringArray = Array(count: 2, repeatedValue: "Hello")
// Accessing Array Elements
var subscriptableArray = ["zero", "one", "two", "three"]
let zero = subscriptableArray[0]
let three = subscriptableArray[3]
subscriptableArray[0] = "nothing"
subscriptableArray[3] = "three items"
subscriptableArray
// It is not possible to insert additional items into the array using subscripting:
// subscriptableArray[4] = "new item"
// Fatal erro: Array Index out of range
// Instead use append() or +=
// You also can't modify the contents of an array that was initialised using let
let constantArray = ["zero", "one", "two", "three"]
//constantArray[0] = "nothing"
subscriptableArray = ["zero", "one", "two", "three"]
let subRange = subscriptableArray[1...3]
subscriptableArray[1...2] = ["oneone", "twotwo"]
subscriptableArray
subscriptableArray[1...2] = []
subscriptableArray
// It is not possible to insert additional items into the array using subscripting
//subscriptableArray[4...5] = ["four", "five"]
// Adding and Removing Elements
var array = [0, 1]
array.append(2)
array
array.append(3)
array
// You can only append to an array that has been initialised with the var keyword.
//constantArray.append("another")
array = [1, 2, 3]
array.insert(0, atIndex: 0)
array
// The index must be less than or equal to the number of items in the collection
//array.insert(6, atIndex: 6)
// You can't insert into an array that was initialised with let
let removed = array.removeAtIndex(0)
array
// The index must be valid
// You can't remove from an array that was created with let
let lastRemoved = array.removeLast()
array
// There must be at least one element in the array
// You can't removeLast() from a constant array
array = [0, 1, 2, 3]
array.removeAll()
let count = array.count
array
// Unless you specify otherwise, the underlying backing storage will be cleared
array = [0, 1, 2, 3]
array.removeAll(keepCapacity: true)
array
array.reserveCapacity(10)
// Ensures that the underlying storage can hold the given total number of elements
// Querying an array
var arrayToCount = ["zero", "one", "two"]
let firstCount = arrayToCount.count
arrayToCount += ["three"]
let secondCount = arrayToCount.count
let firstIsEmpty = arrayToCount.isEmpty
arrayToCount.removeAll()
let secondIsEmpty = arrayToCount.isEmpty
var capacity = arrayToCount.capacity
arrayToCount.reserveCapacity(1000)
capacity = arrayToCount.capacity
// Algorithms
// Sort
// The closure that you supply for isOrderedBefore should return a Boolean value to indicate whether one element should be before (true) or after (false) another element:
var arrayToSort = [3, 2, 5, 1, 4]
arrayToSort.sort { $0 < $1 }
arrayToSort
arrayToSort.sort { $1 < $0 }
arrayToSort
// You can only sort an array inplace if it was declared with var
arrayToSort = [3, 2, 5, 1, 4]
let sortedArray = arrayToSort.sorted { $0 < $1 }
sortedArray
let descendingArray = arrayToSort.sorted { $1 < $0 }
descendingArray
sortedArray
let reversedArray = sortedArray.reverse()
reversedArray
let filteredArray = sortedArray.filter { $0 % 2 == 0 }
filteredArray
let multipliedArray = sortedArray.map { $0 * 2 }
multipliedArray
let describedArray = sortedArray.map { "Number: \($0)" }
describedArray
let addResult = sortedArray.reduce(0) { $0 + $1 }
addResult
let multipliedResult = sortedArray.reduce(0) { $0 * $1 }
multipliedResult
// Operators
var operatorArray = [0, 1, 2]
operatorArray += [3]
operatorArray += [4, 5, 6]
// The type of elements must match
// You can only add new elements to an array that has been declared with var
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Array.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Dictionary.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Dictionary.playground/section-1.swift
================================================
// Swift Standard Library - Types - Dictionary
var emptyDictionary = Dictionary()
var equivilentEmptyDictionary = [String: Int]()
var anotherEmptyDictionary = Dictionary(minimumCapacity: 10)
var literalDictionary = ["a":1]
// Accessing and Changing Dictionary Elements
var dictionary = ["one": 1, "two": 2, "three": 3]
let value = dictionary["two"]
if let unwrappedValue = dictionary["three"] {
print("The integer value for \"three\" was: \(unwrappedValue)")
unwrappedValue
}
dictionary["three"] = 33
dictionary
// You can add to a dictionary using subscripting
dictionary["four"] = 4
dictionary
// you can remove a value for a key by setting it to nil
dictionary["three"] = nil
dictionary
// You can't change, add or remove elements to a constant dictionary
dictionary = ["one": 1, "two": 2, "three": 3]
let previousValue = dictionary.updateValue(22, forKey: "two")
dictionary
if let unwrappedPreviousValue = dictionary.updateValue(33, forKey: "three") {
print("Replaced the previous value: \(unwrappedPreviousValue)")
} else {
print("Added a new value")
}
dictionary = ["one": 1, "two": 2, "three": 3]
let prevValue = dictionary.removeValue(forKey: "two")
if let unwrappedPreviousValue = dictionary.removeValue(forKey: "three") {
print("Removed the old value: \(unwrappedPreviousValue)")
} else {
print("Didn't find a value for the given key to delete")
}
dictionary.removeAll()
dictionary
// Querying a Dictionary
dictionary = ["one": 1, "two": 2, "three": 3]
let elementCount = dictionary.count
for key in dictionary.keys {
print("Key: \(key)")
}
let keysArray = Array(dictionary.keys)
for value in dictionary.values {
print("Value: \(value)")
}
let valuesArray = Array(dictionary.values)
// Operators
let dictionary1 = ["one": 1, "two": 2]
var dictionary2 = ["one": 1]
dictionary2["two"] = 2
let result = dictionary1 == dictionary2
dictionary2 = ["one": 1]
let secondResult = dictionary1 != dictionary2
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/FreeFunctions.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/FreeFunctions.playground/section-1.swift
================================================
// Swift Standard Library - Free Functions
print("Hello, world!\n")
println("Hello, world!")
var array = [5, 1, 6, 4, 2, 3]
sort(&array)
array
// You can't sort a constant array because sort mutates the array it operates on.
array = [5, 1, 6, 4, 2, 3]
var result = sorted(array)
array = [5, 1, 6, 4, 2, 3]
sort(&array) { $0 > $1 }
array
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/FreeFunctions.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/NumericTypes.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/NumericTypes.playground/section-1.swift
================================================
// Swift Standard Library - Types - Numeric Types
// Boolean
var aBool: Bool
aBool = true
aBool = false
!aBool
aBool.description
aBool.getMirror()
aBool.hashValue
// Int
// The primary integer type in Swift is Int, which is word-sized. This means that it holds 32 bits on 32-bit platforms, and 64 bits on 64-bit platforms.
// For the majority of use cases, you should use the base Int type.
var anInt = Int()
anInt.advancedBy(3)
anInt.advancedBy(5) // I don't understand this one
anInt
anInt = -10
anInt.distanceTo(20)
anInt.encode()
anInt.getMirror()
anInt.predecessor()
anInt.successor()
// Int is 64 bit on my Mac OS X system
Int.min
Int.max
UInt.min
let maxUInt = UInt.max
println("Max UInt = \(maxUInt)")
Int8.min
Int8.max
Int16.min
Int16.max
Int32.min
Int32.max
Int64.min
Int64.max
UInt8.min
UInt8.max
UInt16.min
UInt16.max
UInt32.min
UInt32.max
UInt64.min
UInt64.max
// Floating Point
// The primary floating-point type in Swift is Double, which uses 64 bits. If you do not require 64-bit precision, Swift also includes a 32-bit Float type.
var aDouble = Double()
aDouble.advancedBy(5)
aDouble.description
aDouble.isFinite
aDouble.isInfinite
aDouble.isNaN
aDouble.isNormal
aDouble.isSignaling
aDouble.isSignMinus
aDouble.isSubnormal
aDouble.isZero
aDouble = 1.0 / 0.0
aDouble.isInfinite
aDouble.isNaN
aDouble = Double.NaN
aDouble.isNaN
aDouble = Double.abs(-7.3)
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/NumericTypes.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Protocols.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Protocols.playground/section-1.swift
================================================
// Swift Standard Library - Protocols
// Equatable
// The Equatable protocol makes it possible to determine whether two values of the same type are considered to be equal.
struct MyEquatableStruct: Equatable {
var name = "Untitled"
}
func == (lhs: MyEquatableStruct, rhs: MyEquatableStruct) -> Bool {
return lhs.name == rhs.name
}
let value1 = MyEquatableStruct()
var value2 = MyEquatableStruct()
let firstCheck = value1 == value2
value2.name = "A New Name"
let secondCheck = value1 == value2
// Comparable
// The Comparable protocol makes it possible to compare two values of the same type
// There is one required operator overload defined in the protocol (<) as well as one defined in the inherited Equatable protocol (==). You get >, <= and >= for free.
struct MyComparableStruct: Comparable {
var name = "Untitled"
}
func == (lhs: MyComparableStruct, rhs: MyComparableStruct) -> Bool {
return lhs.name == rhs.name
}
func < (lhs: MyComparableStruct, rhs: MyComparableStruct) -> Bool {
return lhs.name < rhs.name
}
let value3 = MyComparableStruct()
var value4 = MyComparableStruct()
let thirdCheck = value3 < value4
value4.name = "A New Name"
let fourthCheck = value4 < value3
let fifthCheck = value4 > value3
let sixthCheck = value4 <= value3
let seventhCheck = value4 >= value3
// Printable
// The Printable protocol allows you to customize the textual representation of any type ready for printing (for example, to Standard Out).
struct MyPrintableStruct: Printable {
var name = "Untitled"
var description: String {
return "MyType: \(name)"
}
}
let value = MyPrintableStruct()
println("Created a \(value)") // Not working in Beta-3
// Sequence Protocol
// https://medium.com/swift-programming/sequence-beyond-primitive-iterations-in-swift-80bc2507d8cc
class TodoItem {
var name:String
var priority:Int
init(name:String, priority:Int) {
self.name = name
self.priority = priority
}
}
struct GenericGenerator: GeneratorType {
var items:[T]
mutating func next() -> T? {
return items.isEmpty ? .None : items.removeAtIndex(0)
}
}
class TodoItemRepository : SequenceType {
var items:[TodoItem] = [];
func addItem(item:TodoItem) {
items += [item]
}
func generate() -> GenericGenerator {
return GenericGenerator(items: items)
}
}
var repo = TodoItemRepository()
repo.addItem(TodoItem(name: "One", priority: 5))
repo.addItem(TodoItem(name: "Two", priority: 2))
repo.addItem(TodoItem(name: "Three", priority: 6))
repo.addItem(TodoItem(name: "Four", priority: 0))
repo.items.count
for item in repo {
println("\(item.name) has a priority of \(item.priority)")
}
repo.items.count
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Protocols.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/String.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/String.playground/section-1.swift
================================================
// Swift Standard Library - Types - String
// A String represents an ordered collection of characters.
// Creating a String
let emptyString = String()
let equivilentString = ""
let repeatedString = String(count: 5, repeatedValue: Character("a"))
// Querying a String
var string = "Hello, world!"
let firstCheck = string.isEmpty
string = ""
let secondCheck = string.isEmpty
string = "Hello, world!"
let hasPrefixFirstCheck = string.hasPrefix("Hello")
let hasPrefixSecondCheck = string.hasPrefix("hello")
let hasSuffixFirstCheck = string.hasSuffix("world!")
let hasSuffixSecondCheck = string.hasSuffix("World!")
// Changing and Converting Strings
string = "42"
if let number = Int(string) {
print("Got the number: \(number)")
} else {
print("Couldn't convert to a number")
}
// Operators
// Concatinate +
let combination = "Hello " + "world"
// You can use the + operator with two strings as shown in the combination example, or with a string and a character in either order:
let exclamationPoint: Character = "!"
var charCombo = combination
charCombo.append(exclamationPoint)
//var extremeCombo: String = exclamationPoint
//extremeCombo.append(charCombo)
// Append +=
string = "Hello "
string += "world"
string.append(exclamationPoint)
string
// Equality ==
let string1 = "Hello world!"
let string2 = "Hello" + " " + "world" + "!"
let equality = string1 == string2
// Less than <
let stringGreater = "Number 3"
let stringLesser = "Number 2"
let resulNotLessThan = stringGreater < stringLesser
let resultIsLessThan = stringLesser < stringGreater
// What is missing from this chapter?
// - How does the less than operator work?
"abc" < "def"
"def" < "abc"
"Number 2" < "number 1"
// It just looks at the ordinal valu of the first character???
// - Does the greater than symbol work?
"abc" > "def"
"def" > "abc"
"Number 2" > "number 1"
// - How do you access the rodinal values of Characters?
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/String.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Undocumented.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Undocumented.playground/section-1.swift
================================================
// http://practicalswift.com/2014/06/14/the-swift-standard-library-list-of-built-in-functions/
import Cocoa
abs(-1)
abs(42)
var languages = ["Swift", "Objective-C"]
contains(languages, "Swift")
contains(languages, "Java")
contains([29, 85, 42, 96, 75], 42)
var oldLanguagees = dropFirst(languages)
languages
languages = ["Swift", "Objective-C"]
var newLanguages = dropLast(languages)
languages
languages = ["Swift", "Objective-C"]
dump(languages)
equal(languages, ["Swift", "Objective-C"])
for i in filter(1...100, { $0 % 10 == 0 }) {
println(i)
}
find(languages, "Swift")
indices([29, 85, 42])
join(":", ["A", "B", "C"])
map(1...3, { $0 * 5 })
for i in map(1...10, { $0 * 10 }) {
println(i)
assert(contains([10, 20, 30, 40, 50, 60, 70, 80, 90, 100],i))
}
max(1, 3, 8, 2)
maxElement(1...10)
maxElement(languages)
minElement(1...10)
minElement(languages)
let reducedLanguages = reduce(languages, "", { $0 + $1 })
reducedLanguages
let reducedArray = reduce([10, 20, 5], 1, { $0 * $1 })
reducedArray
reverse([1,2,3])
startsWith("foobar", "foo")
startsWith(10..<100, 10..<15)
startsWith(languages, ["Swift"])
/*
abs(...)
advance(...)
alignof(...)
alignofValue(...)
assert(...)
bridgeFromObjectiveC(...)
bridgeFromObjectiveCUnconditional(...)
bridgeToObjectiveC(...)
bridgeToObjectiveCUnconditional(...)
c_malloc_size(...)
c_memcpy(...)
c_putchar(...)
contains(...)
count(...)
countElements(...)
countLeadingZeros(...)
debugPrint(...)
debugPrintln(...)
distance(...)
dropFirst(...)
dropLast(...)
dump(...)
encodeBitsAsWords(...)
enumerate(...)
equal(...)
filter(...)
find(...)
getBridgedObjectiveCType(...)
getVaList(...)
indices(...)
insertionSort(...)
isBridgedToObjectiveC(...)
isBridgedVerbatimToObjectiveC(...)
isUniquelyReferenced(...)
join(...)
lexicographicalCompare(...)
map(...)
max(...)
maxElement(...)
min(...)
minElement(...)
numericCast(...)
partition(...)
posix_read(...)
posix_write(...)
print(...)
println(...)
quickSort(...)
reduce(...)
reflect(...)
reinterpretCast(...)
reverse(...)
roundUpToAlignment(...)
sizeof(...)
sizeofValue(...)
sort(...)
split(...)
startsWith(...)
strideof(...)
strideofValue(...)
swap(...)
swift_MagicMirrorData_summaryImpl(...)
swift_bufferAllocate(...)
swift_keepAlive(...)
toString(...)
transcode(...)
underestimateCount(...)
unsafeReflect(...)
withExtendedLifetime(...)
withObjectAtPlusZero(...)
withUnsafePointer(...)
withUnsafePointerToObject(...)
withUnsafePointers(...)
withVaList(...)
*/
================================================
FILE: Swift-Playgrounds/Swift Stanard Library/Undocumented.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/ASwiftTour.playground/Contents.swift
================================================
// Playground - noun: a place where people can play
import Cocoa
var str = "Hello, world!"
// Simple Values
var myVariable = 42
myVariable = 50
let myConstant = 42
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
// Experiment - Create a constant with an explicit type of Float and a value of 4.
let explicitFloat: Float = 4
// Values are never implicitly converted to another type.
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
// Experiment - Try removing the conversion to String from the last line. What error do you get?
// let widthLabel2 = label + width // Binary operation '+' cannot be applied to operands of type 'String and 'Int'
let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples"
let fruitSummary = "I have \(apples + oranges) pieces of fruit"
// Experiment - Use \() to include a floating-point calculation in a string and to include someone’s name in a greeting.
let π: Float = 3.14
let name = "Peter Pie"
let piePy = "\(name) likes the number \(π)"
let quotation = """
I said "I have \(apples) apples."
And then I said "I have \(apples + oranges) pieces of fruit."
"""
// Arrays and Dictionaries
var shoppingList = ["catfish", "water", "tulips"]
shoppingList[1] = "bottle of water"
shoppingList
var occupations = [
"Malcom": "Captain",
"Kaylee": "Mechanic",
]
occupations["Jayne"] = "Public Relations"
occupations
// Arrays automatically grow as you add elements
shoppingList.append("Blue paint")
print(shoppingList)
// Initialising an empty array or dict
let emptyArray: [String] = []
var emptyDictionary: [String: Float] = [:]
shoppingList = []
occupations = [:]
// Control Flow
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
teamScore
// Optionals
// Normal values cannot be nil. They must have a valid value. Sometimes you may not have
// a valid value. In this case you can use an optional type. They are values that can either
// hold a valid value or nil.
var optionalString: String? = "Hello"
optionalString == nil
var optionalName: String? = "John Appleseed"
//optionalName = nil
var greeting = "Hello!"
if let name = optionalName {
greeting += ", \(name)"
} else {
greeting
}
let nickName: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting: String = "Hi \(nickName ?? fullName)"
// Switches
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}
// if default: is removed we get the error "Switch must be exhaustive". This means that every
// possible option must be included in the switch/case statement so that the result cannot be
// undefined.
// for-in loop (Also tuples)
let interestingNumbers = [
"Prime": [2,3,5,7,11,13],
"Fibonacci": [1,1,2,3,5,8],
"Square": [1,4,9,16,25],
]
var largest = 0
var largestKind = ""
for (kind, numbers) in interestingNumbers {
for number in numbers {
if number > largest {
largest = number
largestKind = kind
}
}
}
largest
largestKind
// while and do-while loops
var n = 2
while n < 100 {
n = n * 2
}
n
var m = 2
repeat {
m = m * 2
} while m < 100
m
// Indexes in loops and the Range operators
var total = 0
for i in 0..<4 {
total += i
}
total
// Functions and Closures
func greet(person: String, day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet(person: "Bob", day: "Tuesday")
//Experiment - Remove the day parameter. Add a parameter to include today’s lunch special in the greeting.
func greet(person: String, special: String) -> String {
return "Hello \(person), todays lunch special is: \(special)"
}
greet(person: "Bob", special:"Chicken Parmigiana")
func greet(_ person: String, on day: String) -> String {
return "Hello \(person), today is \(day)."
}
greet("John", on: "Wednesday")
// Use a tuple to make a compound value - for example, to return multiple values from a function. The elements of a tuple can be referred to either by name or by number
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores {
if score > max {
max = score
} else if score < min {
min = score
}
sum += score
}
return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
statistics.sum
statistics.2
// Functions can be nested
func returnFifteen() -> Int {
var y = 10
func add() {
y = y + 5
}
add()
return y
}
returnFifteen()
// Functions are a first-class type. This means that a function can return another function as its value.
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
// A function can take another function as one of its arguments.
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [20, 19, 7, 12]
hasAnyMatches(list: numbers, condition: lessThanTen)
// Closures
// Use the keyword "in" to seperate the parameters from the body
numbers.map({ (number: Int) -> Int in
let result = 3 * number
return result
})
// Experiment - Rewrite the closure to return zero for all odd numbers.
numbers.map({ (number:Int) -> Int in
if number % 2 == 1 {
return 0
}
return number
})
// Single statement closures implicitly return the value of their only statement
let mappedNumbers = numbers.map({ number in 3 * number})
mappedNumbers
// A closure passed as the last argument to a function can appear immediately after the parentheses
let sortedNumbers = numbers.sorted { $0 > $1 }
sortedNumbers
// Objects and Classes
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
//Experiment - Add a constant property with let, and add another method that takes an argument.
extension Shape {
//let solid = true
func blah(a: Int) -> Int {
return a * numberOfSides
}
}
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(name: String) {
self.name = name
}
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
// Every property needs a value assigned - either in its declaration (as with numberOfSides) or in the initialiser (as with name). Note the use of self to differentiate between the name property and the name argument.
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name: name)
numberOfSides = 4
}
func area() -> Double {
return sideLength * sideLength
}
override func simpleDescription() -> String {
return "A square with sides of length \(sideLength)."
}
}
let test = Square(sideLength:5.2, name:"My test square")
test.area()
test.simpleDescription()
// Experiment - Make another subclass of NamedShape called Circle that takes a radius and a name as arguments to its initializer. Implement an area() and a simpleDescription() method on the Circle class.
class Circle: NamedShape {
var radius: Double
init(radius: Double, name: String) {
self.radius = radius
super.init(name: name)
numberOfSides = 1
}
func area() -> Double {
return 3.14 * radius * radius
}
override func simpleDescription() -> String {
return "A circle with radius \(radius)"
}
}
let testCircle = Circle(radius:2.4, name:"my test circle")
testCircle.area()
testCircle.simpleDescription()
class EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, name: String) {
self.sideLength = sideLength
super.init(name:name)
numberOfSides = 3
}
var perimeter: Double {
get {
return 3.0 * sideLength
}
set (newPerimeter){
sideLength = newPerimeter / 3.0
}
}
override func simpleDescription() -> String {
return "An equilateral tringle with sides of length \(sideLength)."
}
}
var triangle = EquilateralTriangle(sideLength:3.1, name:"my test triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength
class TriangleAndSquare {
var triangle:EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: Double, name: String) {
square = Square(sideLength: size, name: name)
triangle = EquilateralTriangle(sideLength: size, name:name)
}
}
var triangleAndSquare = TriangleAndSquare(size:10, name:"another test shape")
triangleAndSquare.square.sideLength
triangleAndSquare.triangle.sideLength
triangleAndSquare.square = Square(sideLength:50, name:"larger square")
triangleAndSquare.triangle.sideLength
// Optionals
// For methods, properties and subscripts you can write a ? afterwards and everything after the question mark will be ignored if the object is nil.
var optionalSquare: Square? = Square(sideLength: 2.5, name:"optional square")
var sideLength = optionalSquare?.sideLength
// let sideLength2 = optionalSquare.sideLength Doesn't work because optionalSquare has a type of Square? not Square. This is what the unwrapping is refering to.
optionalSquare = nil
sideLength = optionalSquare?.sideLength
// Enumerations and Structures
enum Rank: Int {
case ace = 1
case two, three, four, five, six, seven, eight, nine, ten
case jack, queen, king
func simpleDescription() -> String {
switch self {
case .ace:
return "ace"
case .jack:
return "jack"
case .queen:
return "queen"
case .king:
return "king"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.ace
let aceRawValue = ace.rawValue
ace.simpleDescription()
let two = Rank.two
two.simpleDescription()
two.rawValue
// Experiment - Write a function that compares two Rank values by comparing their raw values.
func compare(rank: Rank, toRank: Rank) -> Bool {
return rank.rawValue == toRank.rawValue
}
compare(rank: ace, toRank: two)
compare(rank: ace, toRank: ace)
if let convertedRank = Rank(rawValue: 3) {
let _ = convertedRank.simpleDescription()
}
// enums don't need to be backed by a raw value if they don't make sense. You can also use Int, Double or String as the raw backing type
enum Suit {
case spades, hearts, diamonds, clubs
func simpleDescription() -> String {
switch self {
case .spades:
return "spades"
case .hearts:
return "hearts"
case .diamonds:
return "diamonds"
case .clubs:
return "clubs"
}
}
}
extension Suit {
func color() -> String {
switch self {
case .spades, .clubs:
return "black"
case .hearts, .diamonds:
return "red"
}
}
}
let hearts = Suit.hearts
let heartsDescription = hearts.simpleDescription()
// hearts.toRaw() // This is an error because Suit doesnt have a raw backing type.
let heartsColor = hearts.color()
// Enumerations
enum ServerResponse {
case Result(String, String)
case Error(String)
}
let success = ServerResponse.Result("6:00am", "8.09pm")
let failure = ServerResponse.Error("Out of cheese")
switch failure {
case let .Result(sunrise, sunset):
let _ = "Sunrise is at \(sunrise) and sunset is at \(sunset)"
case let .Error(error):
let _ = "Failure... \(error)"
}
// Experiment - Add a third case to ServerResponse and to the switch
// Structures
// Structures are very similar to classes. They can both have methods and initialisers. One key difference is that structures are always copied when they are passed around in code. Classes are passed by reference.
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
}
// Experiment - Add a method to Card that creates a full deck of cards, with one card of each combination of rank and suit
extension Card {
func createFullDeck() -> [Card] {
var deck: [Card] = []
func appendFullRank(suit: Suit) {
for rawRank in 1...13 {
let card = Card(rank:Rank(rawValue:rawRank)!, suit:suit)
deck.append(card)
}
}
for suit in [Suit.hearts, Suit.diamonds, Suit.spades, Suit.clubs] {
appendFullRank(suit: suit)
}
return deck
}
}
let threeOfSpades = Card(rank: .three, suit:.spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
let aFullDeck = threeOfSpades.createFullDeck()
aFullDeck.map({ card in card.simpleDescription() })
// Protocols and Extensions
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class."
var anotherProperty: Int = 69105
func adjust() {
simpleDescription += " Now 100% adjusted."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: ExampleProtocol {
var simpleDescription: String = "A simple structure"
mutating func adjust() {
simpleDescription += " (adjusted)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
// Experiment - Write an enumeration that conforms to this protocol
enum SimpleEnum: Int, ExampleProtocol {
case A = 1, B, C, D, E
var simpleDescription: String {
get {
return "A simple enum \(self.rawValue)"
}
}
mutating func adjust() {
self = SimpleEnum(rawValue:(self.rawValue + 1))!
}
}
var c = SimpleEnum.A
c.adjust()
let cDescription = c.simpleDescription
// Extensions
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
7.simpleDescription
// The 7 above is a literal constant not a variable. Therefore you can't mutate it with adjust.
var someInt = 4
someInt.adjust()
someInt
// Experiment - Write an extension for the Double type that adds an absoluteValue property.
extension Double {
var absoluteValue: Double {
return self > 0 ? self : -self
}
}
var aDouble = -7.0
aDouble.absoluteValue
4.absoluteValue
(-6.0).absoluteValue
let neg = -6.0
neg.absoluteValue
let absNeg = (-6.0.absoluteValue)
let protocolValue: ExampleProtocol = a
protocolValue.simpleDescription
// protocolValue.anotherProperty // Uncomment to see the error
// Error Handling
// You represent errors using any type that adopts the Error protocol
enum PrinterError: Error {
case outOfPaper
case noToner
case onFire
}
func send(job: Int, toPrinter printerName: String) throws -> String {
if printerName == "Never Has Toner" {
throw PrinterError.noToner
}
return "Job sent"
}
do {
let printerResponse = try send(job: 1040, toPrinter: "Bi Sheng")
printerResponse
} catch {
error
}
// Experiment
do {
let printerResponse2 = try send(job: 1040, toPrinter: "Never Has Toner")
printerResponse2
} catch {
error
}
// You can provide multiple catch blocks to handle specific errors
do {
let printerResponse = try send(job: 1440, toPrinter: "Gutenberg")
printerResponse
} catch PrinterError.onFire {
print("I'll just put this over here, with the rest of the fire")
} catch let printerError as PrinterError {
print("Printer error: \(printerError).")
} catch {
print(error)
}
// Experiment
let printerSuccess = try? send(job: 1884, toPrinter: "Mergenthaler")
let printerFailure = try? send(job: 1885, toPrinter: "Never Has Toner")
// Defer
var fridgeIsOpen: Bool = false
let fridgeContent = ["milk", "eggs", "leftovers"]
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
}
fridgeContains("banana")
fridgeIsOpen
// Generics
func makeArray- (repeating item: Item, numberOfTimes: Int) -> [Item] {
var result = [Item]()
for _ in 0.. {
case none
case some(Wrapped)
}
var possibleInteger: OptionalValue = .none
possibleInteger = .some(100)
func anyCommonElements (_ lhs: T, _ rhs: U) -> Bool
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1,2,3], [3])
anyCommonElements([1,2,3], [6])
anyCommonElements([1,2,3], [3.0])
// Experiment - Modify the anyCommonElements(_:_:) function to make a function that returns an array of the elements that any two sequences have in common.
func returnAnyCommonElements (_ lhs: T, _ rhs: U) -> [T.Iterator.Element]
where T.Iterator.Element: Equatable, T.Iterator.Element == U.Iterator.Element {
var commonElements: [T.Iterator.Element] = []
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
commonElements.append(lhsItem)
}
}
}
return commonElements
}
returnAnyCommonElements([1, 2, 3], [2, 3, 4])
//returnAnyCommon
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/ASwiftTour.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/ASwiftTour.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/01-TheBasics.playground/Contents.swift
================================================
// The Basics Chapter of “The Swift Programming Language.” iBooks. https://itun.es/au/jEUH0.l
//: # The Basics
//: ## Constants and Variables
//: ### Declaring Constants and Variables
let maximumNumberOfLoginAttempts = 10
var currentLoginAttempt = 0
var x = 0.0, y = 0.0, z = 0.0
//: ### Type Annotations
var welcomeMessage: String
welcomeMessage = "Hello"
var red, green, blue: Double
//: ### Naming Constants and Variables
let π = 3.14159
let 你好 = "你好世界"
let 🐶🐮 = "dogcow"
var friendlyWelcome = "Hello!"
friendlyWelcome = "Bonjour!"
let languageName = "Swift"
//languageName = "Swift++" // Compile time error
//: Printing Constants and Variables
print(friendlyWelcome)
print(π, 你好, 🐶🐮, separator: ", ", terminator: "")
print("The current value of friendlyWelcome is \(friendlyWelcome)")
//: ## Comments
// this is a comment
/* this is also a comment,
but written over multiple lines*/
/* this is the start of the first multiline comment
/* this is the second, nested multiline comment */
this is the end of the first multiline comment */
//: ## Semicolons
let cat = "🐱"; print(cat)
//: ## Integers
//: ### Integer Bounds
let minValue = UInt8.min
let maxValue = UInt8.max
//: ## Floating-Point Numbers
var w = [1, 1.2]
//: ## Type Safety and Type Inference
var meaningOfLife = 42
// inferred to be of type Int
// meaningOfLife = 35.0 //Type Error
let pi = 3.14159
let anotherPi = 3 + 0.14159
//: ## Numeric Literals
let descimalInteger = 17
let binaryInteger = 0b10001
let octalInteger = 0o21
let hexadecimalInteger = 0x11
//let hexFloat = 0x1234.0x5678
1.25e2
1.25e-2
0xFp2
0x8p4
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecialDouble = 0xC.3p0
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
//: ## Numeric Conversion
//: ### Integer Conversion
//let cannotBeNegative: UInt8 = -1
//let tooBig: Int8 = Int8.max + 1
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)
//: ### Integer and Floating Point Conversion
let three = 3
let pointOneFourOneFiveNine = 0.14159
let pi2 = Double(three) + pointOneFourOneFiveNine
let integerPi = Int(pi)
// Floats are always truncated when cast to Integers
let integerFourPointSeven = Int(4.75)
let integerNegativeThreePointNine = Int(-3.9)
// Literals can be cross type combined because they have no type until they are evaluated
3 + 0.14159
//: ## Type Aliases
// Type aliases are useful when you want to refer to an existing type by a name that is contextually more appropriate, such as when working with data of a specific size from an external source:
typealias AudioSample = UInt16
var macAmplitudeFound = AudioSample.min
//: ## Booleans
let orangesAreOrange = true
let turnipsAreDelicious = false
if turnipsAreDelicious {
print("Mmm, tasty turnips!")
} else {
print("Eww, turnips are horrible.")
}
// Non-Bool types can't be used for flow control
let i = 1
/*
if i {
}
*/
if i == 1 {
}
//: ## Tuples
let http404Error = (404, "Not Found")
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
print("The status message is \(statusMessage)")
// use _ if you don't want to decompose one of the values of a tuple
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// You can access the values of the tuple using index numbers
print("The status code is \(http404Error.0)")
print("The status message is \(http404Error.1)")
// You can name the elements of a tuple when it is defined
let http200Status = (statusCode: 200, description: "OK")
print("The status code is \(http200Status.statusCode)")
print("The status message is \(http200Status.description)")
// “Tuples are useful for temporary groups of related values. They are not suited to the creation of complex data structures. If your data structure is likely to persist beyond a temporary scope, model it as a class or structure, rather than as a tuple. For more information”
//: ## Optionals
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be ot type "Int?" (optional Int)
// nil
var serverResponseCode: Int? = 404
serverResponseCode = nil
var surveyAnswer: String?
// surveyAnswer is automatically set to nil
// If statements and forced Unwrapping
if convertedNumber != nil {
print("convertedNumber contains some integer value.")
}
if convertedNumber != nil {
print("convertedNumber has an integer value of \(convertedNumber!)")
}
//: ### Optional Binding
if let actualNumber = Int(possibleNumber) {
print("\'\(possibleNumber)\' has a value of \(actualNumber)")
} else {
print("\'\(possibleNumber)\' could not be converted to an Int")
}
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
//: ### Implicitly Unwrapped Optionals
//: Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization
let possibleString: String? = "An optional string."
let forcedString: String = possibleString!
let assumedString: String! = "An implicitly unwrapped optional string"
let implicitString: String = assumedString
if assumedString != nil {
print(assumedString)
}
if let definiteString = assumedString {
print(definiteString)
}
//: Implicitly unwrapped optionals should not be used when there is a possibility of a variable becoming nil at a later point. Always use a normal optional type if you need to check for a nil value during the lifetime of a variable.
//: ## Error Handling
//: In contrast to optionals, which can use the presence or absence of a value to signify success or failure of a function, error handling allows you to determine the underlying cause of failure and if necessary propagate the error to another part of your program.
func canThrowError() throws {
// This function may or may not throw an error.
}
do {
try canThrowError()
// no error was thrown
} catch {
// an error was thrown
}
enum SandwichError: Error {
case OutOfCleanDishes
case MissingIngredients([String])
}
func makeASandwich() throws {
throw SandwichError.MissingIngredients(["butter","ham","bread"])
}
func eatASandwich() {
print("yum yum yum")
}
func washDishes() {
print("Wash the dishes")
}
func buyGroceries(ingredients: [String]) {
ingredients.forEach{ i in print(i) }
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.OutOfCleanDishes {
washDishes()
} catch SandwichError.MissingIngredients(let ingredients) {
buyGroceries(ingredients: ingredients)
} catch {
print("Why did I fail")
}
//: ## Assertions and Preconditions
//: ### Debugging with Assertions
//: Use an assertion whenever a condition has the potential to be false, but must definitely be true in order for your code to continue execution.
let age = -3
//assert(age >= 0, "A person's age cannot be less than zero")
// Left this out as it stops the REPL from continuing
//: ### Enforcing Preconditions
var index = -3
precondition(index > 0, "Index must be greater than zero.")
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/01-TheBasics.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/02-BasicOperators.playground/Contents.swift
================================================
// Basic Operators
// Assignment operator
let b = 10
var a = 5
a = b
let (x, y) = (1, 2)
/*
// “Unlike the assignment operator in C and Objective-C, the assignment operator in Swift does not itself return a value. The following statement is not valid:”
if x = y {
}
*/
// Arithmetic Operators
1 + 2
5 - 3
2 * 3
10.0 / 2.5
// Swift Arithmetic operators can't overflow
"hello, " + "world"
let dog: Character = "🐶"
let cow: Character = "🐮"
//let dogcow = dog + cow // This has been removed from the book.
let dogcow = "🐶" + "🐮"
// Remainder Operator
9 % 4
// a = (b × some multiplier) + remainder
-9 % 4
// a % b and a % -b
9 % -4
-9 % -4
// Unary Minus Operator
let three = 3
let minusThree = -three
let plusThree = -minusThree
// Unary Plus Operator
// Doesn't do anything
let minusSix = -6
let alsoMinusSix = +minusSix
// Compound Assignment Operators
var aaa = 1
aaa += 2
// Comparison Operators
1 == 1
2 != 1
2 > 1
1 < 2
1 >= 1
2 <= 1
let name = "world"
if name == "world" {
print("hello, world")
} else {
print("I'm sorry \(name), but I don't recognize you")
}
// Identity operators
// “Swift also provides two identity operators (=== and !==), which you use to test whether two object references both refer to the same object instance.”
// Ternary Conditional Operator
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// Range Operators
// The Closed Range Operator
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// The Half-Closed range operator
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/02-BasicOperators.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/03-StringsAndCharacters.playground/Contents.swift
================================================
// Strings and Characters
let someString = "Some tring literal value"
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the king said gravely, "and go on
till you come to the end; then stop."
"""
let threeDoubleQuotes = """
Escaping the first quote \"""
Escaping all three quotes \"\"\"
"""
let singleLineString = "These are the same."
let mutilineString = """
These are the same.
"""
"""
This string starts with a line feed.
It also ends with a line feed.
"""
func generateQuotation() -> String {
let quotation = """
The White Rabbit put on his spectacles. "Where shall I begin,
please your Majesty?" he asked.
"Begin at the beginning," the king said gravely, "and go on
till you come to the end; then stop."
"""
return quotation
}
print(quotation == generateQuotation())
// Initializing an Empty Strings
var emptyString = ""
var anotherEmpyString = String()
if emptyString.isEmpty {
print("Nothing to see here")
}
// String mutability
var variableString = "Horse"
variableString += " and carriage"
let constantString = "Highlander"
// constantString += " and another Highlander" // There can be only one
// Working with Characters
for character in "Dog!🐶".characters {
print(character)
}
let exclamationMark: Character = "!"
let catCharacters: [Character] = ["C", "a", "t", "!", "🐱"]
let catString = String(catCharacters)
print(catString)
catString
// Concatenating Strings and Characters
let string1 = "Hello"
let string2 = " there"
var welcome = string1 + string2
// Welcome now equals "hellow there"
var instruction = "look over"
instruction += string2
welcome.append(exclamationMark)
// String Interpolation
let multiplier = 3
let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
// Special Characters in String LIterals
let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
// "Imagination is more important than knowledge" - Einstein
let dollarSign = "\u{24}" // $, Unicode scalar U+0024
let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
let sparklingHeart = "\u{1F496}" // 💖, Unicode scalar U+1F496
// Extended Grapheme Clusters
let eAcute: Character = "\u{E9}" // é
let combinedEAcute: Character = "\u{65}\u{301}" // e followed by ́
// eAcute is é, combinedEAcute is é
let precomposed: Character = "\u{D55C}" // 한
let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // ᄒ, ᅡ, ᆫ
// precomposed is 한, decomposed is 한
let enclosedEAcute: Character = "\u{E9}\u{20DD}"
// enclosedEAcute is é⃝
let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
// regionalIndicatorForUS is 🇺🇸
let regionalIndicatorForAUS: Character = "\u{1F1E6}\u{1F1FA}"
// regionalIndicatorForAUS is 🇦🇺
// Counting Characters
let unusualMenagerie = "Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪"
print("unusualMenagerie has \(unusualMenagerie.characters.count) characters")
// prints "unusualMenagerie has 40 characters"
// Note that Swift's use of extended grapheme clusters for Character values means that string concatenation and modification may not always affect a string's character count.
var word = "cafe"
print("the number of characters in \(word) is \(word.characters.count)")
// prints "the number of characters in cafe is 4"
word += "\u{301}" // Combining Acute accent, U+301
print("the number of characters in \(word) is \(word.characters.count)")
// prints "the number of characters in café is 4"
// Accessing and Modifying a String
// String Indices
// Different characters can require different amounts of memory to store, so in order to determine which Character is at a particular position, you must iterate over each Unicode scalar from the start or end of that String. For this reaason, Swift strings cannot be indexed by integer values.
let greeting = "Guten Tag!"
greeting[greeting.startIndex] // G
greeting[greeting.index(before: greeting.endIndex)] // !
greeting[greeting.index(after: greeting.startIndex)] // u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index] // a
// greeting[greeting.endIndex] // error
// greeting.endIndex.successor() // error
for index in greeting.characters.indices {
print("\(greeting[index]) ", terminator: "")
}
// prints "G u t e n T a g !"
// Inserting and Removing
// To insert a character at a specified index.
var welcome2 = "hello"
welcome2.insert("!", at: welcome2.endIndex)
// To insert another string at a specified index
welcome2.insert(contentsOf:" there".characters, at: welcome2.index(before: welcome2.endIndex))
// To remove a character at a specified index
welcome2.remove(at: welcome2.index(before: welcome2.endIndex))
welcome2
// To remove a substring
let range = welcome2.index(welcome2.endIndex, offsetBy: -6)..
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/04-CollectionTypes.playground/Contents.swift
================================================
// Collection Types
// Arrays
// Creating an Empty Array
var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// Creating an Array with a Default Value
var threeDoubles = Array(repeating: 0.0, count: 3)
// Creating an Array by Adding Two Arrays Together
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
// Creating an Array with an Array Literal
var shoppingList: [String] = ["Eggs","Milk"]
// Accessing and Modifying an Array
print("The shopping list contains \(shoppingList.count) items.")
if shoppingList.isEmpty {
print("The shopping list is empty.")
} else {
print("The shopping list is not empty")
}
shoppingList.append("Flour")
shoppingList += ["Baking Powder"]
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
var firstItem = shoppingList[0]
shoppingList[0] = "Six eggs"
shoppingList[4...6] = ["Bananas", "Apples"]
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
firstItem = shoppingList[0]
let apples = shoppingList.removeLast()
// Iterating Over an Array
for item in shoppingList {
print(item)
}
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
// Sets
// Hash Values for Set Types
// A type must be hashable in order to be stored in a set.
// Creating and Initializing an Empty Set
var letters = Set()
print("letters is of type Set with \(letters.count) items.")
letters.insert("a")
letters = []
// letters is now an empty set, but is still of type Set
// Creating a Set with an Array Literal
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
let alsoFavoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
// Accessing and Modifying a Set
print("I have \(favoriteGenres.count) favorite music genres.")
if favoriteGenres.isEmpty {
print("As far as music goes, I'm not picky.")
} else {
print("I have particular music preferences.")
}
favoriteGenres.insert("Jazz")
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
if favoriteGenres.contains("Funk") {
print("I get up on the good foot.")
} else {
print("It's too funky in here.")
}
// Iterating Over a Set
for genre in favoriteGenres {
print("\(genre)")
}
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
//for genre in favoriteGenres.sorted({ $0[$0.endIndex.predecessor()] > $1[$1.endIndex.predecessor()] }) {
// print("\(genre)")
//}
for genre in favoriteGenres.sorted().reversed() {
print("\(genre)")
}
// Performing Set Operations
let oddDigits: Set = [1,3,5,7,9]
let evenDigits: Set = [0,2,4,6,8]
let singleDigitPrimeNumbers: Set = [2,3,5,7]
oddDigits.union(evenDigits).sorted()
oddDigits.intersection(evenDigits).sorted()
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// Set Membership and Equality
// Set a is a superset of set b, because a contains all elements of b
// Set b is a subset of a
// Set b and set c are disjoint with one another as they share no elements in common
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]
houseAnimals.isSubset(of: farmAnimals)
farmAnimals.isSuperset(of: houseAnimals)
farmAnimals.isDisjoint(with: cityAnimals)
// Dictionaries
let alongFormDict = Dictionary()
let shortFormDict = [String:Int]()
// Creating an Empty Dictionary
var namesOfIntegers = [Int: String]()
namesOfIntegers[16] = "sixteen"
namesOfIntegers = [:]
// Creating a Dictionary with a Dictionary Literal
//var airports: Dictionary = ["TYO":"Tokyo", "DUB":"Dublin"]
var airports: [String: String] = ["YYZ":"Toronto Pearson", "DUB":"Dublin"]
// Accessing and Modifying a Dictionary
print("The dictionary of airports contains \(airports.count) items.")
if airports.isEmpty {
print("The airports dictionary is empty.")
} else {
print("The airports dictionary is not empty.")
}
airports["LHR"] = "London"
airports["LHR"] = "London Heathrow"
if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") {
print("The old value for DUB was \(oldValue).")
}
if let airportName = airports["DUB"] {
print("The name of the airport is \(airportName)")
} else {
print("That airport is not in the airports dictionary.")
}
airports["APL"] = "Apple International"
airports["APL"] = nil
if let removedValue = airports.removeValue(forKey: "DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for DUB.")
}
// Iterating over a dictionary
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
for airportName in airports.values {
print("Airport name: \(airportName)")
}
let airportCodes = [String](airports.keys)
let airportNames = [String](airports.values)
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/04-CollectionTypes.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/05-ControlFlow.playground/Contents.swift
================================================
// Control Flow Chapter
// For Loops
// For-In
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCount) legs")
}
// While Loops
// While
let finalSquare = 25
var board = [Int](repeating: 0, count: finalSquare + 1)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
var square = 0
var diceRoll = 0
while square < finalSquare {
// roll the dice
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
if square < board.count {
// if we're still on the board, move up or down for a snake or a ladder
square += board[square]
}
}
print("Game over!")
// Repeat-While
square = 0
diceRoll = 0
repeat {
// move up or down for a snake or ladder
square += board[square]
// roll the dice
diceRoll += 1
if diceRoll == 7 { diceRoll = 1 }
// move by the rolled amount
square += diceRoll
} while square < finalSquare
print("Game over!")
// Conditional Statements
// If
var temperatureInFarenheit = 30
if temperatureInFarenheit <= 32 {
print("It's very cold. Consider wearing a scarf")
}
temperatureInFarenheit = 40
if temperatureInFarenheit <= 32 {
print("It's very cold. Consider wearing a scarf")
} else {
print("It's not that cold. wear a t-shirt.")
}
temperatureInFarenheit = 90
if temperatureInFarenheit <= 32 {
print("It's very cold. Consider wearing a scarf")
} else if temperatureInFarenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
} else {
print("It's not that cold. wear a t-shirt.")
}
temperatureInFarenheit = 72
if temperatureInFarenheit <= 32 {
print("It's very cold. Consider wearing a scarf")
} else if temperatureInFarenheit >= 86 {
print("It's really warm. Don't forget to wear sunscreen.")
}
// Switch
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or consonant")
}
// No Implicit Fallthrough
let anotherCharacter: Character = "a"
switch anotherCharacter {
//case "a": // Not valid if this line is in place as no executble line for this case statement.
case "A":
print("The letter A")
default:
print("Not the letter A")
}
// Interval Matching
let approximateCount = 62
let countedThings = "moons orbitiy Saturn"
var naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "manu"
}
print("There are \(naturalCount) \(countedThings).")
// Note: Both the closed range operator (...) and half-open range operator (..<) functions are overloaded to return either an IntervalType or Range. An interval can determine whether it contains a particular element, such as when matching a switch statement case. A range is a collecton of consecutive values, which can be iterated on in a for-in statement.
// Tuples
let somePoint = (1,1)
switch somePoint {
case (0, 0):
print("(0,0) is at the origin")
case (_, 0):
print("\(somePoint.0),0) is on the x-axis")
case (0, _):
print("(0, \(somePoint.1)) is on the y-axis")
case (-2...2, -2...2):
print("(\(somePoint.0, somePoint.1)) is inside the box")
default:
print("(\(somePoint.0, somePoint.1)) is outside of the box")
}
// Value Bindings
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhare else at (\(x), \(y))")
}
// Where
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
// Control Transfer Statements
// Continue
let puzzleInput = "great minds think alike"
var puzzleOutput = ""
for character in puzzleInput.characters {
switch character {
case "a", "e", "i", "o", "u", " ":
continue
default:
puzzleOutput.append(character)
}
}
puzzleOutput
// Break
let numberSymbol: Character = "三" // Simplified Chinese for the number 3”
var possibleIntegerValue: Int?
switch numberSymbol {
case "1", "١", "一", "๑":
possibleIntegerValue = 1
case "2", "٢", "二", "๒":
possibleIntegerValue = 2
case "3", "٣", "三", "๓":
possibleIntegerValue = 3
case "4", "٤", "四", "๔":
possibleIntegerValue = 4
default:
break
}
if let integerValue = possibleIntegerValue {
print("The integer value of \(numberSymbol) is \(integerValue).")
} else {
print("An integer value could not be found for \(numberSymbol).")
}
// Fallthrough
let integerToDescribe = 5
var description = "The number \(integerToDescribe) is"
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
description += " a prime number, and also"
fallthrough
default:
description += " an integer."
}
print(description)
// Labelled Statements
board = [Int](repeating: 0, count: finalSquare + 1)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
square = 0
diceRoll = 0
gameLoop: while square != finalSquare {
diceRoll += 1
if diceRoll == 7 { diceRoll = 1}
switch square + diceRoll {
case finalSquare:
break gameLoop
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
print("Game over!")
// Early Exit
// Guard
func greet(person: [String: String]) {
guard let name = person["name"] else {
return
}
print("Hello \(name)!")
guard let location = person["location"] else {
print("I hope the weather is nice near you.")
return
}
print("I hope the weather is nice in \(location).")
}
greet(person: [:])
greet(person: ["name": "John"])
greet(person: ["name":"Jane", "location": "Cupertino"])
// Checking API Availability
if #available(iOS 9, OSX 10.12, *) {
print("Use iOS 9 APIs on iOS, and use OS X v10.10 APIs on OS X")
} else {
print("Fall back to earlier iOS and OSX APIs")
}
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/05-ControlFlow.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/05-ControlFlow.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/06-Functions.playground/Contents.swift
================================================
//: # Functions Chapter
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}
print(greet(person: "Anna"))
print(greet(person: "Brian"))
func greetAgain(person: String) -> String {
return "Hello, " + person + "!"
}
print(greetAgain(person: "Anna"))
// Function Parameters and Return Values
// Functions Without Parameters
func sayHelloWorld() -> String {
return "hello, world"
}
print(sayHelloWorld())
// Multiple Input Parameters
func greet(person: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return greetAgain(person: person)
} else {
return greet(person: person)
}
}
print(greet(person: "Time", alreadyGreeted: true))
// Functions Without Return Values
func greet2(person: String) {
print("Hello, \(person)!")
}
greet2(person: "Dave")
func printAndCount(string: String) -> Int {
print(string)
return string.characters.count
}
func printWithoutCounting(string: String) {
let _ = printAndCount(string: string)
}
printAndCount(string: "hello, world")
printWithoutCounting(string: "hello, world")
// Functions with Multiple Return Values
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1.. currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("min is \(bounds.min) and max is \(bounds.max)")
// Optional Tuple Return Types
func minMaxSafe(array: [Int]) -> (min: Int, max: Int)? {
if array.isEmpty {return nil }
var currentMin = array[0]
var currentMax = array[0]
for value in array[1.. currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
if let bounds = minMaxSafe(array: [8, -6, 2, 109, 3, 71]) {
print("min is \(bounds.min) and max is \(bounds.max)")
}
// Function Argument Labels and Parameter Names
// External Parameter Names
func someFunction(firstParameterName: Int, secondParameterName: Int) {
}
someFunction(firstParameterName: 1, secondParameterName: 2)
// Secifying Argument Labels
func greet(person: String, from hometown: String) -> String {
return "Hello \(person)! Glad you could visit from \(hometown)."
}
greet(person: "Bill", from: "Cupertino")
// Omitting Argument Labels
func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
}
someFunction(1, secondParameterName: 2)
// Default Parameter Values
func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6)
someFunction(parameterWithoutDefault: 4)
// Variadic Parameters
func arithmeticMean(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
arithmeticMean(3, 8, 19)
// In-Out Parameters
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// Function Types
// Every function has a specific function type, made up of the parameter types and the return type of the function.
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
func printHelloWorld() {
print("hello, world")
}
// Using Function Types
// you can define a constant or variable to be of a function type and assign an appropriate function to that variable:
var mathFunction: (Int, Int) -> Int = addTwoInts
print("Result: \(mathFunction(2, 3))")
mathFunction = multiplyTwoInts
print("Result: \(mathFunction(2, 3))")
let anotherMathFunction = addTwoInts
// Function Types as Parameter Types
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Function Types as Return Types
func stepForward(_ input: Int) -> Int {
return input + 1
}
func stepBackward(_ input: Int) -> Int {
return input - 1
}
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
return backward ? stepBackward : stepForward
}
var currentValue = 3
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
print("Counting to zero:")
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
// Nested Functions
func chooseAnotherStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
currentValue = -4
let moveNearerToZeroAgain = chooseAnotherStepFunction(backward: currentValue > 0)
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZeroAgain(currentValue)
}
print("zero!")
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/06-Functions.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/07-Closures.playground/Contents.swift
================================================
// Closures Chapter from From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/au/jEUH0.l
// Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
// Closure Expressions
// The Sort Function
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
func backward(s1: String, s2: String) -> Bool {
return s1 > s2
}
var reversedNames = names.sorted(by: backward)
// Closure Expression Syntax
reversedNames = names.sorted(by: { (s1:String, s2: String) -> Bool in return s1 > s2 })
// Inferring Type from from Context
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 })
// Implicit returns from Single-Expression Closures
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 })
// Shorthand Argument Names
reversedNames = names.sorted(by: { $0 > $1 })
// Operator Functions
reversedNames = names.sorted(by: >)
// Trailing Closures
func someFunctionThatTakesAClosure(closure: () -> ()) {
}
someFunctionThatTakesAClosure(closure: {})
someFunctionThatTakesAClosure() {
}
reversedNames = names.sorted() { $0 > $1 }
reversedNames = names.sorted { $0 > $1 }
let digitNames = [
0: "Zero", 1: "One", 2: "Two", 3: "Three", 4:"Four",
5: "Five", 6:"Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]
let strings = numbers.map {
(number) -> String in
var number = number
var output = ""
repeat {
output = digitNames[number % 10]! + output
number /= 10
} while number > 0
return output
}
strings
// Capturing Values
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
incrementByTen()
incrementByTen()
incrementByTen()
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
incrementByTen()
// Closures are Reference Types
let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// Escaping Closures
var completionHandlers: [() -> Void] = []
func soneFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure()
}
class SomeClass {
var x = 10
func doSomething() {
soneFunctionWithEscapingClosure { self.x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x) // Prints "200"
//: ## Autoclosures
var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
print(customersInLine.count)
let customerProvider = { customersInLine.remove(at: 0) }
print(customersInLine.count)
print("Now serving \(customerProvider())!")
print(customersInLine.count)
func serve(customer customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: { customersInLine.remove(at: 0) } )
//: Even though the first element of the customersInLine array is removed as part of the closure, that operation isn't carried out until the closure is actually called. If the closure is never called, the expression inside the closure is never evaluated. Note that the type of nextCustomer is not String but () -> String - a function that takes no arguments and returns a string.
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0) )
//: The serveNextCustomer function above takes an explicit closure that returns the next customer's name. The version below performs the same operation but, instead uses an autoclosure. Now you can call the function as if it took a String argument instead of a closure.
//: ### @autoclosure(escaping)
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
collectCustomerProviders(customersInLine.remove(at: 0))
collectCustomerProviders(customersInLine.remove(at: 0))
print("Collected \(customerProviders.count) closures.")
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!")
}
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/07-Closures.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/08-Enumerations.playground/Contents.swift
================================================
// Enumerations
// An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code.
enum CompassPoint {
case north
case south
case east
case west
}
enum Planet {
case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune
}
var directionToHead = CompassPoint.west
directionToHead = .east
// Matching Enumeration Values with a Switch Statement
directionToHead = .south
switch directionToHead {
case .north:
print("Lots of planets have a north")
case .south:
print("Watch out for penguins")
case .east:
print("Where the sun rises")
case .west:
print("Where the skies are blue")
}
let somePlanet = Planet.earth
switch somePlanet {
case .earth:
print("Mostly Harmless")
default:
print("Not a safe place for humans")
}
// Associated Values
enum Barcode {
case upc(Int, Int, Int, Int)
case qrCode(String)
}
var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode("ABCDEFGHIJKLMNOP")
switch productBarcode {
case .upc(let numberSystem, let manufacturer, let product, let check):
print("UPC: \(numberSystem), \(manufacturer), \(product), \(check)")
case .qrCode(let productCode):
print("QR code: \(productCode).")
}
productBarcode = Barcode.upc(8, 85909, 51226, 3)
switch productBarcode {
case let .upc(numberSystem, manufacturer, product, check):
print("UPC : \(numberSystem), \(manufacturer), \(product), \(check).")
case let .qrCode(productCode):
print("QR code: \(productCode).")
}
// Raw Values
enum ASCIIControlCharacter: Character {
case tab = "\t"
case lineFeed = "\n"
case carriageReturn = "\r"
}
// Implicitly Assigned Raw Values
enum PlanetRaw: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
}
let earthsOrder = PlanetRaw.earth.rawValue
// earthsOrder is 3
enum CompassPointRaw: String {
case north, south, east, west
}
let sunsetDirection = CompassPointRaw.west.rawValue
// sunsetDirection is "West"
// Initializing from a Raw Value
let possiblePlanet = PlanetRaw(rawValue: 7)
let positionToFind = 11
if let somePlanet = PlanetRaw(rawValue: positionToFind) {
switch somePlanet {
case .earth:
print("Mostly harmless")
default:
print("Not a safe place for humans")
}
} else {
print("There isn't a planet at position \(positionToFind)")
}
// Recursive Enumerations
enum ArithmeticExpression {
case number(Int)
indirect case addition(ArithmeticExpression, ArithmeticExpression)
indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
}
indirect enum ArithmeticExpression2 {
case number(Int)
case addition(ArithmeticExpression2, ArithmeticExpression2)
case multiplication(ArithmeticExpression2, ArithmeticExpression2)
}
let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)
let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
func evaluate(_ expression: ArithmeticExpression) -> Int {
switch expression {
case .number(let value):
return value
case let .addition(lhs, rhs):
return evaluate(lhs) + evaluate(rhs)
case let .multiplication(lhs, rhs):
return evaluate(lhs) * evaluate(rhs)
}
}
print(evaluate(product))
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/08-Enumerations.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/09-ClassesAndStructures.playground/Contents.swift
================================================
// Classes and Structures
class SomeClasse {
}
struct SomeStruct {
}
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
// Class and Structure Instances
let someResolution = Resolution()
let someVideoMode = VideoMode()
print("The width of someResolution is \(someResolution.width)")
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// Memberwise Initializers for Structure Types
// All structures have an automatically-generated memberwise initializer, which you can use to initialize the member properties of new structure instances.
let vga = Resolution(width: 640, height: 480)
// Structures and Enumerations are Value Types
// A value type is a type that is copied when it is assigned to a variable or constant, or when it is passed to a function.
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
print("cinema is now \(cinema.width) pixels wide")
print("hd is still \(hd.width) pixels wide")
enum CompassPoint {
case noth, south, east, west
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection = .east
if rememberedDirection == .west {
print("The remembered direction is still .west")
}
// Classes are Reference Types
// Reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used instead.
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Identity Operators
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Note that “identical to” (represented by three equals signs, or ===) does not mean the same thing as “equal to” (represented by two equals signs, or ==):
// Pointers
// A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but is not a direct pointer to an address in memory.
// Choosing Between Classes and Structures
// Assignment and Copy Behaviour for Dictionaries
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/09-ClassesAndStructures.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/10-Properties.playground/Contents.swift
================================================
// Properties
// Stored Properties
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
rangeOfThreeItems.firstValue = 6
// Stored Properties of Constant Structure Instances
// If you create an instance of a structure and assign that instance to a constant, you cannot modify the instance’s properties, even if they were declared as variable properties:
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
//rangeOfFourItems.firstValue = 6
// The above line will report and error, even though firstValue is a variable property
// Lazy Stored Properties
class DataImporter {
/*
DataImporter is a class to import data from an external file.
The class is assumed to take a non-trivial amount of time to initialize
*/
var fileName = "data.txt"
// the Data Importer class would provide data importing functionality here
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
// the DataManager class would provide data management functionality here
}
let manager = DataManager()
manager.data += ["Some data"]
manager.data += ["Some more data"]
// the DataImporter instance for the importer property has not yet been created
print(manager.importer.fileName)
// the DataImporter instance for the importer property has now been created
// Computed Properties
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0), size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// Shorthand Setter Declaration
// If no name is given for the new value a variable of name newValue is autogenerated
struct AlternativeRect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
}
// Read only Computed Properties
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// Property Observers
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
stepCounter.totalSteps = 360
stepCounter.totalSteps = 896
// Type Properties
// Type properties are useful for defining values that are universal to all instances of a particular type, such as a constant property that all instances can use (like a static constant in C), or a variable property that stores a value that is global to all instances of that type (like a static variable in C).
// Type Property Syntax
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
// Querying and setting Type Properties
print(SomeStructure.storedTypeProperty) // prints "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty) // prints "Another value."
print(SomeEnumeration.computedTypeProperty) // prints "6"
print(SomeClass.computedTypeProperty) // prints "27"
struct AudioChannel {
static let thresholdLevel = 10
static var maxInputLevelForAllChannels = 0
var currentLevel: Int = 0 {
didSet {
if currentLevel > AudioChannel.thresholdLevel {
// cap the new audio level to the threshold level
currentLevel = AudioChannel.thresholdLevel
}
if currentLevel > AudioChannel.maxInputLevelForAllChannels {
// store this as the new overall maximum input level
AudioChannel.maxInputLevelForAllChannels = currentLevel
}
}
}
}
var leftChannel = AudioChannel()
var rightChannel = AudioChannel()
leftChannel.currentLevel = 7
print(leftChannel.currentLevel)
print(AudioChannel.maxInputLevelForAllChannels)
rightChannel.currentLevel = 11
print(rightChannel.currentLevel)
print(AudioChannel.maxInputLevelForAllChannels)
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/10-Properties.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/11-Methods.playground/Contents.swift
================================================
// Methods Chapter
// Instance Methods
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
let counter = Counter()
counter.increment()
counter.increment(by:5)
counter.reset()
// The self Property
// Every instance of a type has an implicit property called self, which is exactly equivalent to the instance itself. You use this implicit self property to refer to the current instance within its own instance methods.
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// Modifying Value TYpes from Within
// Instance Methods
// if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method.
struct Point2 {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY:Double) {
x += deltaX
y += deltaY
}
}
var somePoint2 = Point2(x: 1.0, y: 1.0)
somePoint2.moveBy(x:2.0, y:3.0)
print("The point is now at (\(somePoint2.x), \(somePoint2.y))")
let fixedPoint = Point2(x: 3.0, y: 3.0)
//fixedPoint.moveByX(2.0, y: 3.0)
// this will report an error because fixedPoint is a constant
// Assigning to self Within a Mutating Method
struct Point3 {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = Point3(x: x + deltaX, y: y + deltaY)
}
}
// Mutating methods for enumerations can set the implicit self parameter to be a different member from the same enumeration:
enum TriStateSwitch {
case off, low, high
mutating func next() {
switch self {
case .off:
self = .low
case .low:
self = .high
case .high:
self = .off
}
}
}
var ovenLight = TriStateSwitch.low
ovenLight.next()
ovenLight.next()
// Type Methods
class SomeClass {
class func someTypeMethod() {
// type method implementation goes here
}
}
SomeClass.someTypeMethod()
struct LevelTracker {
static var highestUnlockedLevel = 1
var currentLevel = 1
static func unlock(_ level: Int) {
if level > highestUnlockedLevel { highestUnlockedLevel = level }
}
static func isUnlocked(_ level: Int) -> Bool {
return level <= highestUnlockedLevel
}
@discardableResult
mutating func advance(to level: Int) -> Bool {
if LevelTracker.isUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
class Player {
var tracker = LevelTracker()
let playerName: String
func complete(level: Int) {
LevelTracker.unlock(level + 1)
tracker.advance(to: level + 1)
}
init(name: String) {
playerName = name
}
}
var player = Player(name: "Argyrios")
player.complete(level: 1)
print("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
player = Player(name: "Beto")
if player.tracker.advance(to: 6) {
print("player is now on level 6")
} else {
print("level 6 has not yet been unlocked")
}
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/11-Methods.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/12-Subscripts.playground/Contents.swift
================================================
// Subscripts
/*
subscript(index: Int) -> Int {
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
*/
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// Subscript Usage
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
// Subscript Options
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
matrix
//let someValue = matrix[2, 2]
// Assertion triggered due to out of range access
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/12-Subscripts.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/13-Inheritance.playground/Contents.swift
================================================
// Inheritance
// Base Class
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// do nothing - an arbitrary vehicle doesn't necessarily make a noise
}
}
let someVehicle = Vehicle()
print("Vehicle: \(someVehicle.description)")
class Bicycle: Vehicle {
var hasBasket = false
}
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print("Bicycle: \(bicycle.description)")
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
}
let tandem = Tandem()
tandem.hasBasket = true
tandem.currentNumberOfPassengers = 2
tandem.currentSpeed = 22.0
print("Tandem: \(tandem.description)")
// Overriding
// Overriding methods
class Train: Vehicle {
override func makeNoise() {
print("Choo Choo")
}
}
let train = Train()
train.makeNoise()
//Overriding Properties
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)"
}
}
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print("Car: \(car.description)")
// Overriding Property Observers
class AutomaticCar: Car {
override var currentSpeed: Double {
didSet{
gear = Int(currentSpeed / 10.0) + 1
}
}
}
let automatic = AutomaticCar()
automatic.currentSpeed = 35.0
print("AutomaticCar: \(automatic.description)")
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/13-Inheritance.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/14-Initialization.playground/Contents.swift
================================================
// Initialization
struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// Customizing Initialization
// Initialization Parameters
struct Celsius {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// Parameter names and Argument Labels
struct Color {
let red, green, blue: Double
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
init(white: Double) {
red = white
green = white
blue = white
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
//let verGreen = Color(0.0, 1.0, 0.0)
// Compile time error because external names for parameters were omitted
// Initializer Parameters Without Argument Labels
struct Celsius2 {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
init(_ celsius: Double) {
temperatureInCelsius = celsius
}
}
let bodyTemperature = Celsius2(37.0)
// Optional Property Types
class SurveyQuestion {
var text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
cheeseQuestion.response = "Yes, I do like cheese."
// Assigning Constant Properties during Initialization
class SurveyQuestion2 {
let text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
print(text)
}
}
let beetsQuestion = SurveyQuestion2(text: "How about beets?")
beetsQuestion.ask()
beetsQuestion.response = "I also like beets. (But not with cheese.)"
// Default Initializer
class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
// Memberwise Initializers for Structure Types
// Because both stored properties have a default value, the Size structure automatically receives an init(width:height:) memberwise initializer, which you can use to initialize a new Size instance:
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
// Initializer Delegation for Value Types
//struct Size2 {
// var width = 0.0, height = 0.0
//}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let basicRect = Rect()
let originRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0))
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0))
// Class Inheritance and Initialization
// Rule 1
// Designated initializers must call a designated initializer from their immediate superclass
// Rule 2
// Convenience initializers must call another initializer available in the same class
// Rule 3
// Convenience initializers must ultimately end up calling a designated initializer
// Designated initializers must always delegate up. Convenience initializers must always delegate across
// Initialization is a 2 stage process. There are several safety checks that the compiler performs
// Safety Check 1
// A deignated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass
// Safety Check 2
// A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn't, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization
// Safety Check 3
// A convenience initializer must delegate to another initializer before assigning a value to any property (including properties defined by the same class). If it doesn't, the new value the convenience initializer assigns will be overwritten by its own class's designated initializer.
// Safety Check 4
// An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.
// Two-Phase initialization
// Phase 1
// - A designated or convenience initializer is called on a class
// - Memory for a new instance of that class is allocated. The memory is not yet initialized.
// - A designated initializer for that class confirms that all stored properties introduced by that class have a value. The memory for these stored properties is now initialized.
// - The designated initializer hands off to a superclass initializer to perform the same task for its own stored properties.
// - This continues up the class inheritance chain until the top of the chain is reached.
// - Once the top of the chain is reached, and the final class in the chain has ensured that all of its stored properties have a value, the instance's memory is considered to be fully initialized, and phase 1 is complete.
//
// Phase 2
// - Working back down from the top of the chain, each designated initializer in the chain has the option to customize the instance further. Initializers are now able to access self and can modify its properties, call its instance methods, and so on.
// - Finally, any convenience initializers in the chain have the option to customize the instance and to work with self.
// Initializer Inheritance and Overriding
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
let vehicle = Vehicle()
print("Vehicle: \(vehicle.description)")
class Bicycle: Vehicle {
override init() {
super.init()
numberOfWheels = 2
}
}
let bicycle = Bicycle()
print("Bicycle: \(bicycle.description)")
// Automatic Initializers
// Rule 1
// If your subclass doesn't define any designated initializers, it automatically inherits all of its superclass designated initializers
// Rule 2
// If your subclass provides an implementaction of all of its superclass designated initializers- either by inheriting them as per rule 1, or by providing a custom implementation as part of its definitition- the it automatically inherits all of the superclass convenience initializers.
// Designated and Convenience Initializers in Action
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
let namedMeat = Food(name: "Bacon")
let mysteryMeat = Food()
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
// In this example, the superclass for RecipeIngredient is Food, which has a single convenience initializer called init(). This initializer is therefore inherited by RecipeIngredient. The inherited version of init() functions in exactly the same way as the Food version, except that it delegates to the RecipeIngredient version of init(name: String) rather than the Food version.
class ShoppingListItem2: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
output += purchased ? " √" : " ✘"
return output
}
}
// Because ShoppingListItem2 provides a default value for all of the properties it introduces and does not define any initializers itself, ShoppingListItem automatically inherits all of the designated and convenience initializers from its superclass. ShoppingListItem2(name: "Eggs, quantity: 6),
var breakfastList = [
ShoppingListItem2(),
ShoppingListItem2(name: "Bacon"),
ShoppingListItem2(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
print(item.description)
}
// Failable Initializers
#if swift(>=3.1)
let wholeNumber: Double = 12345.0
let pi = 3.14159
if let valueMaintained = Int(exactly: wholeNumber) {
print("\(wholeNumber) conversion to int maintains value")
}
let valueChanged = Int(exactly: pi)
if valueChanged == nil {
print("\(pi) conversion to int does not maintain value")
}
#endif
struct Animal {
let species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}
let someCreature = Animal(species: "Giraffe")
// is of type Animal?, not Animal
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)")
}
let anonymousCreature = Animal(species: "")
if anonymousCreature == nil {
print("The anonymous creature could not be initialized")
}
// Failable Initializers for Enumerations
enum TemperatureUnit {
case Kelvin, Celsius, Fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
}
let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so initialization failed.")
}
// Failable Initializers for Enumerations with Raw Values
enum TempUnit: Character {
case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}
let fahrUnit = TempUnit(rawValue:"F")
if fahrUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
let unknownUnit2 = TempUnit(rawValue: "X")
if unknownUnit2 == nil {
print("This is not a defined temperature unit, so initialization failed.")
}
// Propagation of Initialization Failure
// Failable initializers for value types can trigger failure at any point. For classes, however a failable initializer can trigger an initialization failure only after all stored properties introduced by that class have been set to an initial value.
class Product {
let name: String!
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class CartItem: Product {
let quantity: Int
init?(name: String, quantity: Int) {
if quantity < 1 { return nil }
self.quantity = quantity
super.init(name: name)
}
}
if let twoSocks = CartItem(name: "sock", quantity: 2) {
print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
} else {
print("Unable to initialize zero shirts")
}
if let oneUnnamed = CartItem(name: "", quantity: 1) {
print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
} else {
print("Unable to initialize one unnamed product")
}
// Overriding a Failable Initializer
class Document {
var name: String?
// this initializer creates a document with a nil name value
init() {}
// this initializer creates a document with a non-empty name value
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}
class AutomaticallyNamedDocument: Document {
override init() {
super.init()
self.name = "[Untitled]"
}
override init(name: String) {
super.init()
if name.isEmpty {
self.name = "[Untitled]"
} else {
self.name = name
}
}
}
class UntitledDocument: Document {
override init() {
super.init(name: "[Untitled]")!
}
}
// The init! Failable Initializer
// Required Initializers
class SomeClass {
required init() {
// Initializer implementation goes here
}
}
class SomeSubclass: SomeClass {
required init() {
// subclass implementation of the required initializer goes here
}
}
// Setting a default Property Value with a Closure or Function
class SomeOtherClass {
let someProperty: Int = {
// create a default value for someProperty inside this closure
// someValue must be of the same type as SomeType
return 1234
}()
}
// Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.
struct Chessboard {
let boardColors: [Bool] = {
var temporaryBoard = [Bool]()
var isBlack = false
for i in 1...8 {
for j in 1...8 {
temporaryBoard.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
return temporaryBoard
}()
func squareIsBlackAt(row: Int, column: Int) -> Bool {
return boardColors[(row * 8) + column]
}
}
let board = Chessboard()
print(board.squareIsBlackAt(row: 0, column: 1))
print(board.squareIsBlackAt(row: 7, column: 7))
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/14-Initialization.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/15-Deinitialization.playground/Contents.swift
================================================
// Deinitialization Chapter
// Class definitions can have at most one deinitializer per class. The deinitializer does not take any parameters and is written without parentheses:
struct Bank {
static var coinsInBank = 10_000
static func distribute(coins numberOfCoinsRequested: Int) -> Int {
let numberOfCoinsToVend = min(numberOfCoinsRequested, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receive(coins: Int) {
coinsInBank += coins
}
}
class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.distribute(coins: coins)
}
func win(coins: Int) {
coinsInPurse += Bank.distribute(coins: coins)
}
deinit {
Bank.receive(coins: coinsInPurse)
}
}
var playerOne: Player? = Player(coins: 100)
print("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
print("There are now \(Bank.coinsInBank) coins left in the bank")
playerOne!.win(coins: 2_000)
print("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
print("The bank now only has \(Bank.coinsInBank) coins left")
playerOne = nil
print("PlayerOne has left the game")
print("The bank now has \(Bank.coinsInBank) coins")
Bank.coinsInBank // This should be back to 10_000. The playerOne variable doesn't get deinitialized in the playground because the GUI keeps it around in case it is referred to again I presume.
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/15-Deinitialization.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/16-AutomaticReferenceCounting.playground/Contents.swift
================================================
// Automatic Reference Counting
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
reference1 = Person(name: "John Appleseed")
reference2 = reference1
reference3 = reference1
reference1 = nil
reference2 = nil
reference3 = nil
// We should see the message that the Person object has been deinitialized however due to the playground this has not occured.
// Strong Reference cycles between Classes
class Person2 {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person2?
deinit { print("Apartment #\(unit) is being deinitialized") }
}
var john: Person2?
var unit4A: Apartment?
john = Person2(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
// Unfortunately, linking these two instances creates a strong reference cycle between them. The Person instance now has a strong reference to the Apartment instance, and the Apartment instance has a strong reference to the Person instance. Therefore, when you break the strong references held by the john and number73 variables, the reference counts do not drop to zero, and the instances are not deallocated by ARC:
john = nil
unit4A = nil
// We have now leaked memory
// Resolving Strong Reference Cycles between Class Instances
// Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization.
// Weak References
class Person3 {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment3?
deinit { print("\(name) is being deinitialized") }
}
class Apartment3 {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person3?
deinit { print("Apartment #\(unit) is being deinitialized") }
}
var james: Person3?
var number74: Apartment3?
james = Person3(name: "James Appleseed")
number74 = Apartment3(unit: "74")
james!.apartment = number74
number74!.tenant = james
james = nil
number74 = nil
// Unowned References
class Customer {
let name: String
var card: CreditCard?
init(name: String) { self.name = name }
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
var justin: Customer?
justin = Customer(name: "Justin McIntyre")
justin!.card = CreditCard(number: 1234_5678_9012_3456, customer: justin!)
justin = nil
// Unowned References and Implicitly Unwrapped Optional Properties
// Both properties should always have a value, and neither property should ever be nil once initialization is complete. This enables both properties to be accessed directly (without optional unwrapping) once initialization is complete, while still avoiding a reference cycle.
class Country {
let name: String
var capitalCity: City!
init(name: String, capitalName: String) {
self.name = name
self.capitalCity = City(name: capitalName, country: self)
}
}
class City {
let name: String
unowned let country: Country
init(name: String, country: Country) {
self.name = name
self.country = country
}
}
// The initializer for City is called from within the initializer for Country. However, the initializer for Country cannot pass self to the City initializer until a new Country instance is fully initialized, as described in Two-Phase Initialization. To cope with this requirement, you declare the capitalCity property of Country as an implicitly unwrapped optional property, indicated by the exclamation mark at the end of its type annotation (City!). This means that the capitalCity property has a default value of nil, like any other optional, but can be accessed without the need to unwrap its value.
var country = Country(name: "Canada", capitalName: "Ottawa")
print("\(country.name)'s capital city is called \(country.capitalCity.name)")
// Strong Reference Cycles for Closures
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
let heading = HTMLElement(name: "h1")
let defaultText = "some default text"
heading.asHTML = {
return "<\(heading.name)>\(heading.text ?? defaultText)\(heading.name)>"
}
print(heading.asHTML())
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
// Unfortunately, the HTMLElement class, as written above, creates a strong reference cycle between an HTMLElement instance and the closure used for its default asHTML value.
paragraph = nil
// Note that the message in the HTMLElement deinitializer is not printed, which shows that the HTMLElement instance is not deallocated.
// Resolving Strong Reference Cycles for Closures
/*
@lazy var someClosure: (Int, String) -> String = {
[unowned self] (index: Int, stringToProcess: String) -> String in
// Closure body goes here
}
*/
class HTMLElement2 {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var paragraph2: HTMLElement2? = HTMLElement2(name: "p", text: "hello, world")
print(paragraph2!.asHTML())
paragraph2 = nil
// prints "p is being deinitialized"
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/16-AutomaticReferenceCounting.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/17-OptionalChaining.playground/Contents.swift
================================================
// Optional Chaining
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
//let roomCount = john.residence!.numberOfRooms
// This triggers a runtime error
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retreive the number of rooms.")
}
// Defining Model Classes for Optional Chaining
class Person2 {
var residence: Residence2?
}
class Residence2 {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
return rooms[i]
}
func printNumberOfRooms() {
print("The number of rooms is \(numberOfRooms)")
}
var address: Address?
}
class Room {
let name: String
init(name: String) { self.name = name }
}
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if (buildingName != nil) {
return buildingName
} else if (buildingNumber != nil) {
return buildingNumber
} else {
return nil
}
}
}
// Accessing Properties Through Optional Chaining
let jack = Person2()
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retreive the number of rooms.")
}
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
jack.residence?.address = someAddress
func createAddress() -> Address {
print("Function was called.")
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
return someAddress
}
// Calling Methods through Optional Chaining
if jack.residence?.printNumberOfRooms() != nil {
print("It was possible to print the number of rooms.")
} else {
print("It was not possible to print the number of rooms.")
}
// printNumberOfRooms returns Void? if called on an optional parent value
if (jack.residence?.address = someAddress) != nil {
print("It was possible to set the address.")
} else {
print("It was not possible to set the address.")
}
// Prints "It was not possible to set the address."
// Accessing Subscripts Through Optional Chaining
if let firstRoomName = jack.residence?[0].name {
print("The first room name is \(firstRoomName).")
} else {
print("Unable to retrieve the first room name.")
}
//jack.residence?[0] = Room(name: "Bathroom")
//This subscript setting attempt also fails, because residence is currently nil.
let jacksHouse = Residence2()
jacksHouse.rooms.append(Room(name: "Living Room"))
jacksHouse.rooms.append(Room(name: "Kitchen"))
jack.residence = jacksHouse
if let firstRoomName = jack.residence?[0].name {
print("The first room name is \(firstRoomName).")
} else {
print("Unable to retrieve the first room name.")
}
// Accessing Subscripts of Optional Type
var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0] += 1
testScores["Brian"]?[0] = 72 // Fails as no Brian
testScores
// Linking Multiple levels of Chaining
if let jacksStreet = jack.residence?.address?.street {
print("Jack's street name is \(jacksStreet).")
} else {
print("Unable to retrieve the address.")
}
let jacksAddress = Address()
jacksAddress.buildingName = "The Larches"
jacksAddress.street = "Laurel Street"
jack.residence!.address = jacksAddress
if let jacksStreet = jack.residence?.address?.street {
print("Jack's street name is \(jacksStreet).")
} else {
print("Unable to retrieve the address.")
}
// Chaining on Methods With Optional Return Values
if let buildingIdentifier = jack.residence?.address?.buildingIdentifier() {
print("Jack's building identifier is \(buildingIdentifier).")
}
if let beginsWithThe = jack.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
if beginsWithThe {
print("Jack's building identifier begins with \"The\".")
} else {
print("Jack's building identifier does not begin with \"The\".")
}
}
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/17-OptionalChaining.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/18-ErrorHandling.playground/Contents.swift
================================================
import Cocoa
//: # Error Handling
//: Swift provides first-class support for throwing, catching, propagating, and manipulating recoverable errors at runtime (NOTE: recoverable).
//:
//: ## Representing and Throwing Errors
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
// throw VendingMachineError.InsufficientFunds(required: 5)
//: ## Handling Errors
//: ### Propagating Errors using Throwing Functions
func canThrowErrors() throws -> String { return "" }
func cannotThrowErrors() -> String { return "" }
struct Item {
var price: Int
var count: Int
}
class VendingMachine {
var inventory = [
"Candy Bar": Item(price: 12, count: 7),
"Chips": Item(price: 10, count: 4),
"Pretzels": Item(price: 7, count: 11)
]
var coinsDeposited = 0
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else {
throw VendingMachineError.invalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.outOfStock
}
guard item.price <= coinsDeposited else {
throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
}
coinsDeposited -= item.price
var newItem = item
newItem.count -= 1
inventory[name] = newItem
print("Dispensing \(name)")
}
}
let favoriteSnacks = [
"Alice": "Chips",
"Bob": "Licorice",
"Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName)
}
//: Note that vend() must be marked with the try keyword. Also because the errors are not handled here the error is propagated up to buyFavoriteSnack() as noted by the throws keyword.
struct PurchasedSnack {
let name: String
init(name: String, vendingMachine: VendingMachine) throws {
try vendingMachine.vend(itemNamed: name)
self.name = name
}
}
//: ## Handling Errors Using Do-Catch
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
// Enjoy delicious snack
} catch VendingMachineError.invalidSelection {
print("Invalid Selection")
} catch VendingMachineError.outOfStock {
print("Out of Stock")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional $\(coinsNeeded).")
}
//: ## Converting Errors to Optional Values
//: If an error is thrown while evaluating the try? expression, the value of the expression is nil
enum UnluckyError: Error { case unlucky }
func someThrowingFunction() throws -> Int {
let success = arc4random_uniform(5)
if success == 0 { throw UnluckyError.unlucky }
return Int(success)
}
let x = try? someThrowingFunction()
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
//: Try? lets you write concise error handling code when you want to handle all errors the same way.
struct Data { }
func fetchDataFromDisk() throws -> Data {
let success = arc4random_uniform(5)
if success == 0 { throw UnluckyError.unlucky }
return Data()
}
func fetchDataFromServer() throws -> Data {
let success = arc4random_uniform(5)
if success == 0 { throw UnluckyError.unlucky }
return Data()
}
func fetchData() -> Data? {
if let data = try? fetchDataFromDisk() { return data }
if let data = try? fetchDataFromServer() { return data }
return nil
}
fetchData()
//: ## Disabling Error Propagation
//: Calling a throwing function or method with try! disables error propagation and wraps the call in a run-time assertion that no error will be thrown. If an error actually is thrown, you'll get a runtime error.
//let photo = try! loadImage("./Resources/John Appleseed.jpg")
//: ## Specifying Clean-Up Actions
//: A defer statement defers execution until the current scope is exited.
//: Deferred statements may not contain any code that would transfer control out of the statements, such as a break or return statement, or by throwing an error.
//: Deferred actions are executed in reverse order of how they are specified.
enum FileError: Error {
case endOfFile
case fileClosed
}
func exists(_ filename: String) -> Bool { return true }
class FakeFile {
var isOpen = false
var filename = ""
var lines = 100
func readline() throws -> String? {
if self.isOpen {
if lines > 0 {
lines -= 1
return "line number \(lines) of text\n"
} else {
throw FileError.endOfFile
//return nil
}
} else {
throw FileError.fileClosed
}
}
}
func open(fileNamed: String) -> FakeFile {
let file = FakeFile()
file.filename = fileNamed
file.isOpen = true
print("\(file.filename) has been opened")
return file
}
func close(file: FakeFile) {
file.isOpen = false
print("\(file.filename) has been closed")
}
func processFile(named: String) throws {
if exists(named) {
let file = open(fileNamed: named)
defer {
close(file: file)
}
while let line = try file.readline() {
// Work with the file
print(line)
}
// close(file) is called here, at the end of the scope.
}
}
do {
try processFile(named: "myFakeFile")
} catch FileError.endOfFile {
print("Reached the end of the file")
} catch FileError.fileClosed {
print("The file isn't open")
}
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/18-ErrorHandling.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/19-TypeCasting.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/19-TypeCasting.playground/section-1.swift
================================================
// Type Casting
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}
class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}
class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}
// Swift’s type checker is able to deduce that Movie and Song have a common superclass of MediaItem, and so it infers a type of MediaItem[] for the library array:
let library = [
Movie(name: "Casablanca", director: "Michael Curtiz"),
Song(name: "Blue Suede Shoes", artist: "ElvisPresley"),
Movie(name: "Citizen Kane", director: "Orson Welles"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
// The items stored in library are still Movie and Song instances behind the scenes. However, if you iterate over the contents of this array, the items you receive back are typed as MediaItem, and not as Movie or Song. In order to work with them as their native type, you need to check their type, or downcast them to a different type, as described below.
// Checking Type
var movieCount = 0
var songCount = 0
for item in library {
if item is Movie {
movieCount += 1
} else if item is Song {
songCount += 1
}
}
print("Media library contains \(movieCount) movies and \(songCount) songs")
// Downcasting
for item in library {
if let movie = item as? Movie {
print("Movie: '\(movie.name)', dir. \(movie.director)")
} else if let song = item as? Song {
print("Song: '\(song.name)', by \(song.artist)")
}
}
// Type Casting for Any and AnyObject
var things = [Any]()
things.append(0)
things.append(0.0)
things.append(42)
things.append(3.1459)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, \(name)" })
for thing in things {
switch thing {
case 0 as Int:
print("zero as an Int")
case 0 as Double:
print("zero as a Double")
case let someInt as Int:
print("an integer value of \(someInt)")
case let someDouble as Double where someDouble > 0:
print("a positive double value of \(someDouble)")
case is Double:
print("some other double value that I don't want to print")
case let someString as String:
print("a string value of \"\(someString)\"")
case let (x, y) as (Double, Double):
print("an (x, y) point at \(x), \(y)")
case let movie as Movie:
print("a movie called '\(movie.name)', dir. \(movie.director)")
default:
print("something else")
}
}
// The cases of a switch statement use the forced version of the type cast operator (as, not as?) to check and cast to a specific type. This check is always safe within the context of a switch case statement.
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/20-NestedTypes.playground/Contents.swift
================================================
// Nested Types
struct BlackjackCard {
// nested Suit enumeration
enum Suit: Character {
case spades = "♠", hearts = "♡", diamonds = "♢", clubs = "♣"
}
// nestedRank enumeration
enum Rank: Int {
case two = 2, three, four, five, six, seven, eight, nine, ten
case jack, queen, king, ace
struct Values {
let first: Int, second: Int?
}
var values: Values {
switch self {
case .ace:
return Values(first: 1, second: 11)
case .jack, .queen, .king:
return Values(first: 10, second: nil)
default:
return Values(first: self.rawValue, second: nil)
}
}
}
// BlackjackCard properties and methods
let rank: Rank, suit: Suit
var description: String {
var output = "suit is \(suit.rawValue),"
output += " value is \(rank.values.first)"
if let second = rank.values.second {
output += " or \(second)"
}
return output
}
}
let theAceOfSpades = BlackjackCard(rank: .ace, suit: .spades)
print("theAceOfSpades: \(theAceOfSpades.description)")
// Referring to Nested Types
let heartsSymbol = BlackjackCard.Suit.hearts.rawValue
print("heartsSymbol is \(heartsSymbol)")
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/20-NestedTypes.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/21-Extensions.playground/Contents.swift
================================================
// Extensions
/*
extension SomeType {
// new functionality to add to SomeType goes here
}
extension SomeType: SomeProtocol, AnotherProtocol {
// implementation of protocol requirements goes here
}
*/
// Computed Properties
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters")
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters")
let aMarathon = 42.km + 195.m
print("A marathon is \(aMarathon) meters long")
// Extensions can add new computed properties, but they cannot add stored properties, or add property observers to existing properties.
// Initializers
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
}
let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y:2.0), size: Size(width: 5.0, height: 5.0))
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height:3.0))
// Methods
extension Int {
func repetitions(task: () -> Void) {
for _ in 0.. Int {
var decimalBase = 1
for _ in 0.. 0:
return .positive
default:
return .negative
}
}
}
func printIntegerKinds(_ numbers: [Int]) {
for number in numbers {
switch number.kind {
case .negative:
print("-")
//print("- ", terminator: false)
case .zero:
print("0")
//print("0 ", terminator: false)
case .positive:
print("+")
//print("+ ", terminator: false)
}
}
print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/21-Extensions.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/22-Protocols.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/22-Protocols.playground/section-1.swift
================================================
// Protocols
import Foundation
/*
protocol SomeProtocol {
// protocol definition goes here
}
struct SomeStructure: FirstProtocol, AnotherProtocol {
// structure definition goes here
}
// If a class has a superclass, list the superclass name before any protocols it adopts, followed by a comma:
class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
// class definition goes here
}
*/
// Property Requirements
// Property requirements are always declared as variable properties, prefixed with the var keyword.
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
}
// Always prefix type property requirements with the static keyword when you define them in a protocol. This is true even though type property requirements can be prefixed with the static or class keyword when implemented by a class:
protocol AnotherProtocol {
static var someTypeProperty: Int { get set }
}
// Here's an example of a protocol with a single instance property requirement:
protocol FullyNamed {
var fullName: String { get }
}
struct Person: FullyNamed {
var fullName: String
}
let john = Person(fullName: "John AppleSeed")
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return ((prefix != nil ? prefix! + " " : "") + name)
}
}
var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
// Method Requirements
/*
protocol SomeProtocol {
static func someTypeMethod()
}
*/
protocol RandomNumberGenerator {
func random() -> Double
}
// linear congruential generator:
class LinearCongruentialGenerator: RandomNumberGenerator {
var lastRandom = 42.0
let m = 139968.0
let a = 3877.0
let c = 29573.0
func random() -> Double {
lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
return lastRandom / m
}
}
let generator = LinearCongruentialGenerator()
print("Here's a random number: \(generator.random())")
print("And another one: \(generator.random())")
// Mutating Method Requirements
protocol Togglable {
mutating func toggle()
}
enum OnOffSwitch: Togglable {
case off, on
mutating func toggle() {
switch self {
case .off:
self = .on
case .on:
self = .off
}
}
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle()
lightSwitch
// Initializer Requirements
// Protocols can require specific initializers to be implemented by conforming types.
/*
protocol SomeProtocol {
init(someParameter: Int)
}
*/
// Class Implementations of Protocol Initializer Requirements
// You can implement a protocol initializer requirement on a conforming class as either a designated initializer or a convenience initializer. In both cases, you must mark the initializer implementation with the required modifier
/*
class SomeClass: SomeProtocol {
required init(someParameter: Int) {
// initializer implementation goes here
}
{
*/
// If a subclass overrides a designated initializer from a superclass, and also implements a matching initializer requirement from a protocol, mark the initializer implementation with both the required and override modifiers
/*
protocol SomeProtocol {
init()
}
class SomeSuperClass {
init() {
// initializer implementation goes here
}
}
class SomeSubClass: SomeSuperClass, SomeProtocol {
// "required" from SomeProtocol conformance; "override" from SomeSuperClass
required override init() {
// initializer implementation goes here
}
}
*/
// Failable Initializer Requirements
// Protocols as Types
// Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use
class Dice {
let sides: Int
let generator: RandomNumberGenerator
init(sides: Int, generator: RandomNumberGenerator) {
self.sides = sides
self.generator = generator
}
func roll() -> Int {
return Int(generator.random() * Double(sides)) + 1
}
}
var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
print("Random dice roll is \(d6.roll())")
}
// Delegation
protocol DiceGame {
var dice: Dice { get }
func play()
}
protocol DiceGameDelegate {
func gameDidStart(_ game: DiceGame)
func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
func gameDidEnd(_ game: DiceGame)
}
class SnakesAndLadders: DiceGame {
let finalSquare = 25
let dice = Dice(sides: 6, generator:LinearCongruentialGenerator())
var square = 0
var board: [Int]
init() {
board = [Int](repeating: 0, count: finalSquare + 1)
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
}
var delegate: DiceGameDelegate?
func play() {
square = 0
delegate?.gameDidStart(self)
gameLoop: while square != finalSquare {
let diceRoll = dice.roll()
delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
switch square + diceRoll {
case finalSquare:
break gameLoop
case let newSquare where newSquare > finalSquare:
continue gameLoop
default:
square += diceRoll
square += board[square]
}
}
delegate?.gameDidEnd(self)
}
}
class DiceGameTracker: DiceGameDelegate {
var numberOfTurns = 0
func gameDidStart(_ game: DiceGame) {
numberOfTurns = 0
if game is SnakesAndLadders {
print("Started a new game of Snakes and Ladders")
}
print("The game is using a \(game.dice.sides)-sided dice")
}
func game(_ game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
numberOfTurns += 1
print("Rolled a \(diceRoll)")
}
func gameDidEnd(_ game: DiceGame) {
print("The game lasted for \(numberOfTurns) turns")
}
}
let tracker = DiceGameTracker()
let game = SnakesAndLadders()
game.delegate = tracker
game.play()
// Adding Protocol Conformance with an Extension
protocol TextRepresentable {
var textualDescription: String { get }
}
extension Dice: TextRepresentable {
var textualDescription: String {
return "A \(sides)-sided dice"
}
}
let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
print(d12.textualDescription)
d6.textualDescription
extension SnakesAndLadders: TextRepresentable {
var textualDescription: String {
return "A game of Snakes and Ladders with \(finalSquare) squares"
}
}
print(game.textualDescription)
// Declaring Protocol Adoption with an Extension
// If a type already conforms to all of the requirements of a protocol, but has not yet stated that it adopts that protocol, you can make it adopt the protocol with an empty extension:
struct Hamster {
var name: String
var textualDescription: String {
return "A hamster named \(name)"
}
}
extension Hamster: TextRepresentable {}
let simonTheHamster = Hamster(name: "Simon")
let somethingTextRepresentable: TextRepresentable = simonTheHamster
print(somethingTextRepresentable.textualDescription)
// Collections of Protocol Types
let things: [TextRepresentable] = [game, d12, simonTheHamster]
for thing in things {
print(thing.textualDescription)
}
// Note that the thing constant is of type TextRepresentable. It is not of type Dice, or DiceGame, or Hamster, even if the actual instance behind the scenes is of one of those types.
// Protocol Inheritance
/*
protocol InheritingProtocol: SomeProtocol, Another Protocol {
// protocol definition goes here
}
*/
protocol PrettyTextRepresentable: TextRepresentable {
var prettyTextualDescription: String { get }
}
// PrettyTextRepresentable must satisfy all of the requirements enforced by TextRepresentable, plus the additional requirements enforced by PrettyTextRepresentable.
extension SnakesAndLadders: PrettyTextRepresentable {
var prettyTextualDescription: String {
var output = textualDescription + ":\n"
for index in 1...finalSquare {
switch board[index] {
case let ladder where ladder > 0:
output += "▲ "
case let snake where snake < 0:
output += "▼ "
default:
output += "○ "
}
}
return output
}
}
print(game.prettyTextualDescription)
// Class-Only Protocols
// You can limit protocol adoption to class types by adding the class keyword.
/*
protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
// class-only protocol definition goes here
}
*/
// Note: Use a class-only protocol when the behaviour defined by that protocol's requirements assumes or requires that a conforming type has reference semantics rather than value semantics.
// Protocol Composition
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person2: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person2(name:"Malcom", age: 21)
wishHappyBirthday(to: birthdayPerson)
// Note: Protocol compositions do not define a new, permanent protocol type. Rather they define a temporary local protocol that has the combined requirements of all protocols in the composition.
// Checking for Protocol Conformance
protocol HasArea {
var area: Double { get }
}
// You can check for protocol conformance only if your protocol is marked with the @objc attribute
class Circle: HasArea {
let pi = 3.1415927
var radius: Double
var area: Double { return pi * radius * radius }
init(radius: Double) { self.radius = radius }
}
class Country: HasArea {
var area: Double
init(area: Double) { self.area = area }
}
class Animal {
var legs: Int
init(legs: Int) { self.legs = legs }
}
let objects: [AnyObject] = [
Circle(radius: 2.0),
Country(area: 243_610),
Animal(legs: 4)
]
for object in objects {
if let objectWithArea = object as? HasArea {
print("Area is \(objectWithArea.area)")
} else {
print("Something that doesn't have an area")
}
}
// Note that the underlying objects are not changed by the casting process. They continue to be a Circle, a Country and an Animal. However, at the point that they are stored in the objectWithArea constant, they are only known to be of type HasArea, and so only their area property can be accessed.
// Optional Protocol Requirements
// Optional property requirements, and optional method requirements that return a value, will always return an optional value of the appropriate type when they are accessed or called, to reflect the fact that the optional requirement may not have been implemented.
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
class Counter {
var count = 0
var dataSource: CounterDataSource?
func increment() {
if let amount = dataSource?.increment?(forCount: count) {
count += amount
} else if let amount = dataSource?.fixedIncrement {
count += amount
}
}
}
class ThreeSource: NSObject, CounterDataSource {
let fixedIncrement = 3
}
var counter = Counter()
counter.dataSource = ThreeSource()
for _ in 1...4 {
counter.increment()
print(counter.count)
}
@objc class TowardsZeroSource: NSObject, CounterDataSource {
func increment(forCount count: Int) -> Int {
if count == 0 {
return 0
} else if count < 0 {
return 1
} else {
return -1
}
}
}
counter.count = -4
counter.dataSource = TowardsZeroSource()
for _ in 1...5 {
counter.increment()
print(counter.count)
}
// Protocol Extensions
// Protocols can be extended to procide method and property implementations to conforming types. This allows you to define behaviour on protocols themselves, rather than in each type's individual conformance or in a global function.
// For example, the RandomNumberGenerator protocol can be extended to provide a randomBool() method, which uses the result of the required random() method to return a random Bool value:
extension RandomNumberGenerator {
func randomBool() -> Bool {
return random() > 0.5
}
}
// By creating an extension on the protocol, all conforming types automatically gain this method implementation without and additional modification.
//let generator2 = LinearCongruentialGenerator()
//print("Here's a random number: \(generator2.random())")
print("Here's a random Boolean: \(generator.randomBool())")
// Providing Default Implementations
// Protocol extensions can provide default implementations to any method or property requirement
// If a conforming type provides its own implementation that is used instead.
extension PrettyTextRepresentable {
var prettyTextualDescription: String {
return textualDescription
}
}
extension Hamster: PrettyTextRepresentable { }
print(simonTheHamster.prettyTextualDescription)
// Adding Constraints to Protocol Extensions
// You can specify constraints that conforming types must satisfy before methods and properties of an extension are available.
// You use the where clause after the name of the protocol you are extending.
extension Collection where Iterator.Element : TextRepresentable {
var textualDescription: String {
let itemsAsText = self.map { $0.textualDescription }
return "[" + itemsAsText.joined(separator: ", ") + "]"
}
}
let murrayTheHamster = Hamster(name: "Murray")
let morganTheHamster = Hamster(name: "Morgan")
let mauriceTheHamster = Hamster(name: "Maurice")
let hamsters = [murrayTheHamster, morganTheHamster, mauriceTheHamster]
// Because Array conforms to CollectionType, and the array's elements conform to the TextRepresentable protocol, the array can use the asList() method to get a textual representation of its contents:
print(hamsters.textualDescription)
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/23-Generics.playground/Contents.swift
================================================
// Generics
// The Problem That Generics Solve
// standard, non-generic function
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
// The swapTwoInts function is useful, but it can only be used with Int values. If you want to swap two String values, or two Double values, you have to write more functions, such as the swapTwoStrings and swapTwoDoubles functions shown below
func swapTwoStrings(_ a: inout String, _ b: inout String) {
let temporaryA = a
a = b
b = temporaryA
}
func swapTwoDoubles(_ a: inout Double, _ b: inout Double) {
let temporaryA = a
a = b
b = temporaryA
}
// Generic Functions
func swapTwoValues(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
swapTwoValues(&someInt, &anotherInt)
print("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
print("someString is now \(someString), and anotherString is now \(anotherString)")
// Generic Types
// Non-generic version of a Stack first
struct IntStack {
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
}
// Now a Generic version
struct Stack {
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
}
var stackOfStrings = Stack()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
stackOfStrings
let fromTheTop = stackOfStrings.pop()
// Extending a Generic Type
extension Stack {
var topItem: Element? {
return items.isEmpty ? nil : items[items.count - 1]
}
}
if let topItem = stackOfStrings.topItem {
print("The top item on the stack is \(topItem).")
}
// Type Constraints
/*
func someFunction(someT: T, someU: U) {
// function body goes here
}
*/
func findIndex(ofString valueToFind: String, in array: [String]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
if let foundIndex = findIndex(ofString: "llama", in: strings) {
print("The index of llama is \(foundIndex)")
}
func findIndex(of valueToFind: T, in array: [T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
let doubleIndex = findIndex(of: 9.3, in: [3.14159, 0.1, 0.25])
let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"])
// Associated Types
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
struct IntStack2: Container {
// original IntStack implementation
var items = [Int]()
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// conformance to the Container protocol
typealias Item = Int
mutating func append(_ item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
struct Stack2: Container {
// original Stack implementation
var items = [Element]()
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
// conformance to the Container protocol
mutating func append(_ item: Element) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Element {
return items[i]
}
}
// Extending an Existing Type to Specify an Associated Type
extension Array: Container {}
// Generic Where Clauses
func allItemsMatch
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
// check that both containers contain the same number of items
if someContainer.count != anotherContainer.count {
return false
}
// check each pair of items it see if they are equivilent
for i in 0..()
stackOfStrings2.push("uno")
stackOfStrings2.push("dos")
stackOfStrings2.push("tres")
var arrayOfStrings = ["uno", "dos", "tres"]
if allItemsMatch(stackOfStrings2, arrayOfStrings) {
print("All items match.")
} else {
print("Not all items match.")
}
// Extensions with a Generic Where Clause
extension Stack2 where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
if stackOfStrings2.isTop("tres") {
print("Top element is tres.")
} else {
print("Top element is something else.")
}
// If you try to call the isTop(_:) method on a stack whose elements aren't equatable, you'll get a compile-time error.
struct NotEquatable { }
var notEquatableStack = Stack2()
let notEquatableValue = NotEquatable()
notEquatableStack.push(notEquatableValue)
// notEquatableStack.isTop(notEquatableValue) // Error
extension Container where Item: Equatable {
func startsWith(_ item: Item) -> Bool {
return count >= 1 && self[0] == item
}
}
if [9, 9, 9].startsWith(42) {
print("Starts with 42.")
} else {
print("Starts with something else.")
}
extension Container where Item == Double {
func average() -> Double {
var sum = 0.0
for index in 0.. Item { get }
associatedtype Iterator: IteratorProtocol where Iterator.Element == Item
func makeIterator() -> Iterator
}
protocol ComparableContainer: Container where Item: Comparable { }
// Generic Subscripts
extension Container {
subscript(indices: Indices) -> [Item]
where Indices.Iterator.Element == Int {
var result = [Item]()
for index in indices {
result.append(self[index])
}
return result
}
}
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/23-Generics.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/24-AccessControl.playground/Contents.swift
================================================
// Access Control
// You can assign specific access levels to individual types (classes, structures, and enumerations), as well as to properties, methods, initializers, and subscripts belonging to those types. Protocols can be restricted to a certain context, as can global constants, variables, and functions.
// Modules and Source Files
// A module is a single unit of code distribution - a framework or application. Something that can be imported
// Access Levels
// Public - Available anywhere. Used for defining the public interface.
// Internal - Use within any source file within a module.
// Private - Use only within the defining source file
// No entity can be defined in terms of another entity that has a lower (more restrictive) access level.
// Default Access level - Internal
// Access Control Syntax
public class SomePublicClass {}
internal class SomeInternalClass {}
fileprivate class SomeFilePrivateClass {}
private class SomePrivateClass {}
public var somePublicVariable = 0
internal let someInternalConstant = 0
fileprivate func someFilePrivateFunction() {}
private func somePriviateFunction() {}
class SomeImplicitlyInternalClass {} // implicitly internal
let someImplicitlyInternalConstant = 0 // implicitly internal
public class AnotherPublicClass { // explicitly public class
public var somePublicProperty = 0 // explicitly public class member
var someInternalProperty = 0 // implicitly internal class member
private func somePrivateMethod() {} // explicitly private class member
}
class AnotherInternalClass { // implicitly internal class
var someInternalProperty = 0 // implicitly internal class member
private func somePrivateMethod() {} // explicitly private class member
}
fileprivate class AnotherFilePrivateClass { // explicitly file-private class
func someFilePrivateMethod() {} // inplicitly file-private method
private func somePrivateMethod() {} // explicitly file-private method
}
private class AnotherPrivateClass { // explicitly private class
var somePrivateProperty = 0 // implicitly private class member
func somePrivateMethod() {} // implicitly private class member
}
// Tuple Types
// Tuples don't have a way to explicitly set their access level. Instead the tuples access level is set from the most restrictive access level of its components
// Function Types
// The access level of a function is set as the most restrictive access level of the function arguments and return type. You also must explicitly set the access level of the function type if it doesn't match the default
/*
func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
}
The function above won't compile because the SomePrivateClass sets the function type to private which is not explicitly set.
*/
private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
// function implementation goes here
return (SomeInternalClass(), SomePrivateClass())
}
// Enumeration Types
// The individual cases of an enumeration have the same access level as the enum
private enum CompassPoint {
case north
case south
case east
case west
}
// Subclasses
// A subclass cannot have a higher access level than its superclass.
// An override can make an inherited class member more accessible than its superclass.
public class A {
fileprivate func someMethod() {}
}
internal class B: A {
override internal func someMethod() {}
}
public class C {
fileprivate func someMethod() {}
}
internal class D: C {
override internal func someMethod() {
super.someMethod()
}
}
// Constants, Variables, Properties and Subscripts
// A constant, variable or property cannot be more public than its type.
private var privateInstance = SomePrivateClass()
// Getters and Setters
// Below, we have a value string that is internal. We also have a numberOfEdits variable that tracks how many times value has been modified. numberOfEdits is effectively readonly from outside the class because its setter is marked as private.
struct TrackedString {
private(set) var numberOfEdits = 0
var value: String = "" {
didSet {
numberOfEdits += 1
}
}
}
var stringToEdit = TrackedString()
stringToEdit.value = "This string will be tracked."
stringToEdit.value += " This edit will increment numberOfEdits."
stringToEdit.value += " So will this one."
print("The number of edits is \(stringToEdit.numberOfEdits)")
stringToEdit.numberOfEdits
// Initializers
// Default initialisers are given the same access level as their type except that public types get given internal initializers. You can provide a public initializer if you need one.
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/24-AccessControl.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/25-AdvancedOperators.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/25-AdvancedOperators.playground/section-1.swift
================================================
// Advanced Operators
// Unlike arithmetic operators in C, arithmetic operators in Swift do not overflow by default. Overflow behavior is trapped and reported as an error. To opt in to overflow behavior, use Swift’s second set of arithmetic operators that overflow by default, such as the overflow addition operator (&+). All of these overflow operators begin with an ampersand (&).
// Bitwise Operators
// Bitwise NOT
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits
// Bitwise AND
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits
// Bitwise OR
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedBits = someBits | moreBits
// Bitwise XOR
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits
// Bitwise Left and Right Shift
let shiftBits: UInt8 = 4
shiftBits << 1
shiftBits << 2
shiftBits << 5
shiftBits << 6
shiftBits >> 2
let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16
let greenComponent = (pink & 0x00FF00) >> 8
let blueComponent = pink & 0x0000FF
let negativeBits: Int8 = -4
negativeBits << 1
negativeBits << 2
negativeBits << 5
negativeBits << 6
negativeBits >> 2
negativeBits >> 5 // Doesn't overflow
// Overflow Operators
// Overflow addition (&+)
// Overflow subtraction (&-)
// Overflow multiplication (&*)
var potentialOverflow = Int16.max
// potentialOverflow += 1 // This causes an error if it runs
var willOverflow = UInt8.max
willOverflow = willOverflow &+ 1
// Value Underflow
var unsignedOverflow = UInt8.min
unsignedOverflow = unsignedOverflow &+ 1
unsignedOverflow = UInt8.min
unsignedOverflow = unsignedOverflow &- 1
var signedOverflow = Int8.min
signedOverflow = signedOverflow &- 1
// Precedence and Associativity
// Operator associativity defines how operators of the same precedence are grouped together (or associated)—either grouped from the left, or grouped from the right. Think of it as meaning “they associate with the expression to their left,” or “they associate with the expression to their right.
2 + 3 * 4 % 5
// * and % have a higher precedence than +.
// * and & have the same precendence as each other but both associate to their left. Think of this as adding implicit parentheses around these parts of the expression, starting from their left: (This explanation seems arbitrary to me. Aparently more info in the Expressions chapter)
// Operator Functions
// Infix Operators
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y:4.0)
let combinedVector = vector + anotherVector
// Prefix and Postfix Operators
extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
}
let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
let alsoPositive = -negative
// Compound Assignment Operators
extension Vector2D {
static func += (left: inout Vector2D, right: Vector2D) {
left = left + right
}
}
var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
// It is not possible to overload the default assignment operator (=). Only the compound assignment operators can be overloaded. Similarly, the ternary conditional operator (a ? b : c) cannot be overloaded.
// Equivalence Operators
// Custom classes and structures do not receive a default implementation of the equivalence operators, known as the “equal to” operator (==) and “not equal to” operator (!=).
extension Vector2D {
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
static func != (left: Vector2D, right: Vector2D) -> Bool {
return !(left == right)
}
}
let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
print("These two vectors are equivilent.")
}
// Custom Operators
// Custom operators can be defined only with the characters / = - + * % < > ! & | ^ . ~
// +++ prefix doubling incrementer
prefix operator +++
extension Vector2D {
static prefix func +++ (vector: inout Vector2D) -> Vector2D {
vector += vector
return vector
}
}
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
// Precedence and Associativity for Custom Infix Operators
infix operator +-: AdditionPrecedence
extension Vector2D {
static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y - right.y)
}
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
================================================
FILE: Swift-Playgrounds/The Swift Programming Language/LanguageGuide/25-AdvancedOperators.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/AdoptingCocoaDesignPatterns.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/AdoptingCocoaDesignPatterns.playground/section-1.swift
================================================
// Adopting Cocoa Design Patterns
import Cocoa
// Delegation
/*
if let fullScreenSize = myDelegate?.window?(myWindow, willUseFullScreenContentSize: mySize) {
println(NSStringFromSize(fullScreenSize))
}
*/
// 1. Check that myDelegate is not nil.
// 2. Check that myDelegate implements the method window:willUseFullScreenContentSize:.
// 3. If 1 and 2 hold true, invoke the method and assign the result of the method to the value named fullScreenSize.
// 4. Print the return value of the method.
// In a pure Swift app, type the delegate property as an optional NSWindowDelegate object and assign it an initial value of nil.
class MyDelegate: NSObject, NSWindowDelegate {
func window(_ window: NSWindow, willUseFullScreenContentSize proposedSize: NSSize) -> NSSize {
return proposedSize
}
}
let myWindow = NSWindow()
myWindow.delegate = MyDelegate()
//if let fullScreenSize = myWindow.delegate?.window(myWindow, willUseFullScreenContentSize: NSSize()) {
// print(NSStringFromSize(fullScreenSize))
//}
// Lazy Initialization
// Error Reporting
// Error reporting in Swift follows the same pattern it does in Objective-C.
// In the simplest case, you return a Bool value from the function to indicate whether or not it succeeded.
// When you need to report the reason for the error, you can add to the function an NSError out parameter of type NSErrorPointer. This type is roughly equivalent to Objective-C’s NSError **. You can use the prefix & operator to pass in a reference to an optional NSError type as an NSErrorPointer object, as shown in the code listing below.
/*
var writeError: NSError?
let written = myString.writeToFile(path, atomically: false, encoding: NSUTF8StringEncoding, error: &writeError)
if !written {
if let error = writeError {
println("write failure: \(error.localizedDescription)")
}
}
*/
// Target-Action
// Basically the same as in Objective-C
// Introspection
// In ObjC you use isKindOfClass: and conformsToProtocol:
// In Swift you use the is operator and the as? operator to downcast
/*if errorPointer is NSButton {
println("\(typeName) is a string")
} else {
println("typeName is not a string")
}
if let button = errorPointer as? NSErrorPointer {
}
*/
// Checking for and casting to a protocol follows exactly the same syntax as checking for and casting to a class.
/*
if let dataSource = object as? UITableViewDataSource {
// object conforms to UITableViewDataSource and is bound to dataSource
} else {
// object not conform to UITableViewDataSource
}
*/
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/BasicSetup.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/BasicSetup.playground/section-1.swift
================================================
// Basic Setup
// Swift is designed to provide seamless compatibility with Cocoa and Objective-C.
/* This guide covers three important aspects of the compatability of Objective-C and Swift
- Interoperability, lets you interface between Swift and Objective-C code.
- Mix and Match, allows you to create mixed language apps
- Migration, from objective-C code to Swift
*/
// Understanding the Swift Import Process
// Any Objective-C framework (or C library) that’s accessible as a module can be imported directly into Swift.
import Foundation
// The import Process
// - Objective-C framworks vend APIs in header files.
// - In Swift those header files rae compiled down to Objective-C modules
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/BasicSetup.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/InteractingWithC-APIs.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/InteractingWithC-APIs.playground/section-1.swift
================================================
// Interacting with C APIs
import Foundation
// Primitive Types
// Swift provides equivalents of C primitive integer types—for example, char, int, float, and double.
// However, there is no implicit conversion between these types and core Swift integer types, such as Int. Therefore, use these types if your code specifically requires them, but use Int wherever possible otherwise.
/*
C Type Swift Type
bool CBool
char, signed char CChar
unsigned char CUnsignedChar
short CShort
unsigned short CUnsignedShort
int CInt
unsigned int CUnsignedInt
long CLong
unsigned long CUnsignedLong
long long CLongLong
unsigned long long CUnsignedLongLong
wchar_t CWideChar
char16_t CChar16
char32_t CChar32
float CFloat
double CDouble
*/
// Enumerations
// Swift imports as a Swift enumeration any C-style enumeration marked with the NS_ENUM macro.
/*
Objective-C
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
}
*/
enum UITableViewCellStyle: Int {
case Default
case Value1
case Value2
case Subtitle
}
// Swift also imports options marked with the NS_OPTIONS macro. Whereas options behave similarly to imported enumerations, options can also support some bitwise operations, such as &, |, and ~.
// Pointers
/* For Arguments
C Syntax Swift Syntax
------------------ -----------------------
const void * CConstVoidPointer
void * CMutableVoidPointer
const Type * CConstPointer
Type * CMutablePointer
*/
/* For return types, variables, and argument types more than one pointer level deep
C Syntax Swift Syntax
------------------ -----------------------
void * COpaquePointer
Type * UnsafePointer
*/
/* For Class Types
C Syntax Swift Syntax
------------------ -----------------------
Type * const * CConstPointer
Type * __strong * CMutablePointer
Type ** AutoreleasingUnsafePointer
*/
// C Mutable Pointers
// When a function is declared as taking a CMutablePointer argument, it can accept any of the following
// - nil, which is passed as a null pointer
// - A CMutablePointer value
// - An in-out expression whose operand is a stored lvalue of type Type, which is passed as the address of the lvalue
// - An in-out Type[] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call
func takesAMutablePointer(x: UnsafePointer) {
// Does something
}
var x: Float = 0.0
var p: UnsafePointer = nil
var a: [Float] = [1.0, 2.0, 3.0]
takesAMutablePointer(nil)
takesAMutablePointer(p)
takesAMutablePointer(&x)
takesAMutablePointer(&a)
/*
func takesAMutablePointer(x: UnsafePointer) {
}
var y: Int = 0
var p: UnsafePointer = nil
var q: UnsafePointer = nil
var b: [Int] = [1, 2, 3]
*/
// C Const Pointers
// CConstPointer argument, it can accept any of the following:
// - nil, which is passed as a null pointer
// - A CMutablePointer, CMutableVoidPointer, CConstPointer, CConstVoidPointer, or AutoreleasingUnsafePointer value, which is converted to CConstPointer if necessary
// - An in-out expression whose operand is an lvalue of type Type, which is passed as the address of the lvalue
// - A Type[] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call
func takesAMutableVoidPointer(x:UnsafeMutablePointer) {
}
var x2: Float = 0.0, y2: Int = 0
var p2: UnsafeMutablePointer = nil, q2: UnsafeMutablePointer = nil
var a2: [Float] = [1.0, 2.0, 3.0], b2: [Int] = [1,2,3]
takesAMutableVoidPointer(nil)
takesAMutableVoidPointer(p2)
takesAMutableVoidPointer(p2)
takesAMutableVoidPointer(&x2)
takesAMutableVoidPointer(&y2)
takesAMutableVoidPointer(&a2)
takesAMutableVoidPointer(&b2)
// AutoreleasingUnsafePointer
// AutoreleasingUnsafePointer, it can accept any of the following:
// - nil, which is passed as a null pointer
// - An AutoreleasingUnsafePointer value
// - An in-out expression, whose operand is primitive-copied to a temporary nonowning buffer. The address of that buffer is passed to the callee, and on return, the value in the buffer is loaded, retained, and reassigned into the operand.
func takesAnAutoreleasingPointer(x: AutoreleasingUnsafeMutablePointer) {
/* ... */
}
var z: NSDate? = nil
var r: AutoreleasingUnsafeMutablePointer = nil
takesAnAutoreleasingPointer(nil)
takesAnAutoreleasingPointer(r)
takesAnAutoreleasingPointer(&z)
// Global Constants
// Global constants defined in C and Objective-C source files are automatically imported by the Swift compiler as Swift global constants.
// Preprocessor Directives
// The Swift compiler does not include a preprocessor. Instead, it takes advantage of compile-time attributes, build configurations, and language features to accomplish the same functionality. For this reason, preprocessor directives are not imported in Swift.
// #define FADE_ANIMATION_DURATION 0.35
let FADE_ANIMATION_DURATION = 0.35
// the compiler automatically imports simple macros defined in C and Objective-C source
// Complex Macros are not transferred across.
// Build Configurations
// Swift code can be conditionally compiled based on the evaluation of Build Configurations.
// Build configurations include the literals true and false, command line flags and the platform testing functions listed below.
// You can specify command line flags using -D <#flag#>.
/*
Function Valid Arguments
------------------ -----------------------
os() OSX, iOS
arch() x86_64, arm, arm64, i386
*/
/*
#if <#build configuration#> && !<#build configuration#>
<#statements#>
#elseif <#build configuration#>
<#statements#>
#else
<#statements#>
#endif
*/
// Conditional compilation statements in Swift must completely surround blocks of code that are self-contained and syntactically valid.
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/InteractingWithC-APIs.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/InteractingWithObjective-C-APIs.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/InteractingWithObjective-C-APIs.playground/section-1.swift
================================================
//: # Interacting with Objective-C APIs
import UIKit
//import CoreGraphics
//import Foundation
//: ## Initialization
// UITableView *myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped];
let myTableView: UITableView = UITableView(frame: CGRect.zero, style: .grouped)
let myTextField = UITextField(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 40.0))
// Objective-C Factory Methods
// UIColor *color = [UIColor colorWithRed: 0.5 green:0.0 blue:0.5 alpha:1.0]
let color = UIColor(red: 0.5, green: 0.0, blue: 0.5, alpha: 1.0)
//: ## Failable Initialization
if let image = UIImage(contentsOfFile: "MyImage.png") {
print(image)
} else {
print("UIImage initialization failed")
}
//: ## Accessing Properties
myTextField.textColor = UIColor.darkGray
myTextField.text = "Hello world"
//: In Objective-C, a method that returns a value and takes no arguments can be treated as an implicit getter—and be called using the same syntax as a getter for a property. This is not the case in Swift. In Swift, only properties that are written using the @property syntax in Objective-C are imported as properties.
//: ## Working with Methods
//: When Objective-C methods come over to Swift,
//: - the first part of an Objective-C selector becomes the base method name and appears outside the parentheses.
//: - The first argument appears immediately inside the parentheses, without a name.
//: - The rest of the selector pieces correspond to argument names and go inside the parentheses.
//: - All selector pieces are required at the call site.
let mySubview = UIView()
// [myTableView insertSubview:mySubview atIndex:2];
myTableView.insertSubview(mySubview, at: 2)
myTableView.layoutIfNeeded() // Parenthesis still required despite lack of arguments
//: ## id Compatibility
//: AnyObject is a protocol type.
//: The AnyObject protocol allows you to write type-safe Swift code while maintaining the flexibility of an untyped object. Because of the additional safety provided by the AnyObject protocol, Swift imports id as AnyObject.
var x: Any = "hello" as String
x as? String
x as? NSString
x = "goodbye" as NSString
x as? String
x as? NSString
// Downcasting Any
let userDefaults = UserDefaults.standard
let lastRefreshDate = userDefaults.object(forKey: "LastRefreshDate") // lastRefreshDate is of type Any?
if let date = lastRefreshDate as? Date {
print("\(date.timeIntervalSinceReferenceDate)")
}
// If you are cetain of the type of the object, you can use the forced downcast operator
// let myDate = lastRefreshDate as! Date
// let timeInterval = myDate.timeIntervalSinceReferenceDate
// Dynamic Method Lookup
var myObject: AnyObject = UITableViewCell()
myObject = NSDate()
let futureDate = myObject.addingTimeInterval(10)
let timeSinceNow = myObject.timeIntervalSinceNow
// Unrecognized Selectors and Optional Chaining
// myObject.character(at: 5) // crash, myObject doesn't respond to that method
let myCount = myObject.count // Int? type and nil value
let myChar = myObject.character?(at: 5) // unichar? type and nil value
if let fifthCharacter = myObject.character?(at: 5) {
print("Found \(fifthCharacter) at index 5")
}
//: ## Nullability and Optionals
//: Swift makes all classes in argument types and return types optional in imported Objective-C APIs.
//: Swift imports object types as implicitly unwrapped optionals.
var nulableProperty: Any?
var nonNullProperty: Any
var unannotatedProperty: Any!
func returnsNonNullValue() -> Any { return false }
func takesNonNullParameter(value: Any) {}
func returnsNullableValue() -> Any? { return nil }
func takesNullableParameter(value: Any?) {}
func returnsUnannotatedValue() -> Any! { return false }
func takesUnannotatedParameter(value: Any!) {}
// Extensions
extension UIBezierPath {
convenience init(triangleSideLength: CGFloat, origin: CGPoint) {
self.init()
let squareRoot = CGFloat(sqrt(3.0))
let altitude = (squareRoot * triangleSideLength) / 2
move(to: origin)
addLine(to: CGPoint(x: origin.x + triangleSideLength, y: origin.x))
addLine(to: CGPoint(x: origin.x + triangleSideLength / 2, y: origin.y + altitude))
close()
}
}
// You can use extensions to add properties (including class and static properties). However, these properties must be computed; extensions can’t add stored properties to classes, structures, or enumerations.
extension CGRect {
var area: CGFloat {
return width * height
}
}
let rect = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 50.0)
let area = rect.area
// Closures
// Objective-C blocks are automatically imported as Swift closures.
// void (^completionBlock)(NSData *, NSError *) = ^(NSData *data, NSError *error) { /* ... */ }
let completionBlock: (Data) -> Void = { data in
/* ... */
}
// Avoiding String Reference Cycles When Capturing self
/*
self.closure = { [unowned self] in
self.doSomething()
}
*/
// Object Comparison
// Equality (==), compares the contents of the objects.
// Identity (===), determines whether or not the constants or variables refer to the same object instance.
// Swift invokes the isEqual: method defined on the NSObject class. The NSObject class only performs an identity comparison, so you should implement your own isEqual: method in classes that derive from the NSObject class.
//
// Swift Type Compatibility
// The @objc attribute makes your Swift API available in Objective-C and the Objective-C runtime.
/*
class Jukebox: NSObject {
var library: Set
var nowPlaying: String?
var isCurrentlyPlaying: Bool {
return nowPlaying != nil
}
static var favoritesPlaylist: [String] {
// return an array of song names
}
init(songs: String...) {
self.library = Set(songs)
}
func playSong(named name: String) throws {
// play song or throw and error if unavailable
}
}
*/
// Configuring Swift Interfaces in Objective-C
@objc(Color)
enum Цвет: Int {
@objc(Red)
case Красный
@objc(Black)
case Черный
}
@objc(Squirrel)
class Белка: NSObject {
@objc(color)
var цвет: Цвет = .Красный
@objc(initWithName:)
init(имя: String) {
// ...
}
@objc(hideNuts:inTree:)
func прячьОрехи(количество: Int, вДереве дерево: Цвет) { // Error
// ...
}
}
// Requiring Dynamic Dispatch
// Selectors
// An Objective-C selector is a type that refers to the name of an Objective-C method. In Swift, Objective-C selectors are represented by the Selector structure.
// In Swift string literals can be automatically converted to selectors
class MyViewController: UIViewController {
let myButton = UIButton(frame: CGRect(x: 0, y: 0, width: 100, height: 50))
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
let action = #selector(MyViewController.tappedButton)
myButton.addTarget(self, action: action, for: .touchUpInside)
}
func tappedButton(sender: UIButton!) {
print("tapped button")
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
// Unsafe Invocation of Objective-C Methods
let string: NSString = "Hello, Cocoa!"
let selector = #selector(NSString.lowercased(with:))
let locale = Locale.current
if let result = string.perform(selector, with: locale) {
print(result.takeUnretainedValue())
}
let array: NSArray = ["delta", "alpha", "zulu"]
let anotherSelector = #selector(getter: NSDictionary.allKeys)
// array.perform(selector) // Raises an exception because NSArray does not respond to this selector
// Keys and Key Paths
class Person: NSObject {
var name: String
var friends: [Person] = []
var bestFriend: Person? = nil
init(name: String) {
self.name = name
}
}
let gabrielle = Person(name: "Gabrielle")
let jim = Person(name: "Jim")
let yuanyuan = Person(name: "Yuanyuan")
gabrielle.friends = [jim, yuanyuan]
gabrielle.bestFriend = yuanyuan
#keyPath(Person.name)
gabrielle.value(forKey: #keyPath(Person.name))
#keyPath(Person.bestFriend.name)
gabrielle.value(forKeyPath: #keyPath(Person.bestFriend.name))
#keyPath(Person.friends.name)
gabrielle.value(forKeyPath: #keyPath(Person.friends.name))
let personNameKeyPath = #keyPath(Person.name)
yuanyuan.value(forKeyPath: personNameKeyPath)
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/Mix&Match.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/Mix&Match.playground/section-1.swift
================================================
// Mix and Match
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/Mix&Match.playground/timeline.xctimeline
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/WorkingWithCocoaDataTypes.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/Using Swift With Cocoa And Objective-C/WorkingWithCocoaDataTypes.playground/section-1.swift
================================================
// Working with Cocoa Frameworks
// Data types that are convertible or can be used interchangeably are referred to as bridged data types.
import UIKit
// Strings
// Swift automatically bridges between the String type and the NSString class.
// To enable string bridging, just import Foundation.
import Foundation
let string: String = "abc"
let bridgedString: NSString = string as NSString
let stringLiteral: NSString = "123"
if let integerValue = Int(stringLiteral as String) {
print("\(stringLiteral) is the integer \(integerValue)")
}
// Numbers
// Swift automatically bridges from Int, UInt, Float, Double, Bool to NSNumber
let number = 42
let bridgedNumber: NSNumber = number as NSNumber
let integerLiteral: NSNumber = 5
let floatLiteral: NSNumber = 3.14159
let booleanLiteral: NSNumber = true
// Arrays
// Swift automatically bridges from NSArray to the native Array structure. The bridged class will be of type AnyObject[]. You can downcast the AnyObject[] to a more specific type. This will return an optional type though as it is not possible to know that all of the elements of the array can be downcast to the specified type until runtime.
let schoolSupplies: NSArray = ["Pencil", "Eraser", "Notebook"]
// Sets
let amenities: NSSet = ["Sauna", "Steam Room", "Jacuzzi"]
// Dictionaries
let medalRankings: NSDictionary = ["Gold": "1st Place", "Silver": "2nd Place", "Bronze": "3rd Place"]
// Core Foundation
// Core Foundation types are automatically imported as full-fledged Swift classes. Wherever memory management annotations have been provided, Swift automatically manages the memory of Core Foundation objects, including Core Foundation objects that you instantiate yourself.
// Remapped Types
// When Swift imports Core Foundation types, the compiler remaps the names of these types. The compiler removes Ref from the end of each type name because all Swift classes are reference types, therefore the suffix is redundant.
// The Core Foundation CFTypeRef type completely remaps to the AnyObject type. Wherever you would use CFTypeRef, you should now use AnyObject in your code.
// Memory Managed Objects
// Core Foundation objects returned from annotated APIs are automatically memory managed in Swift—you do not need to invoke the CFRetain, CFRelease, or CFAutorelease functions yourself.
// Unmanaged Objects
// When Swift imports APIs that have not been annotated, the compiler cannot automatically memory manage the returned Core Foundation objects. Swift wraps these returned Core Foundation objects in an Unmanaged structure. All indirectly returned Core Foundation objects are unmanaged as well. For example, here’s an unannotated C function:
/*
Objective-C
CFStringRef StringByAddingTwoStrings(CFStringRef string1, CFStringRef string2)
Swift
func StringByAddingTwoStrings(CFString!, CFString!) -> Unmanaged!
*/
// When you receive an unmanaged object from an unannotated API, you should immediately convert it to a memory managed object before you work with it. Use takeUnretainedValue() or takeRetainedValue()
/*
let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
*/
// Unified Logging
// The unified logging system provides an API for capturing messaging across all levels of the system, and is a replacement for the NSLog function in the Foundation framework.
/*
import os.log
os_log("This is a log message.")
let fileSize = 1234567890
os_log("Finished downloading file. Size: %{iec-bytes}d", fileSize)
os_log("This is additional info that may be helpful for troubleshooting.", type: .info)
let customLog = OSLog(subsystem: "com.your_company.your_subsystem_name.plist", category: "your_category_name")
os_log("This is info that may be helpful during development or debugging.", log: customLog, type: .debug)
*/
================================================
FILE: Swift-Playgrounds/WWDC/2014/AdvancedSwift.playground/Contents.swift
================================================
// WWDC 2014 - Advanced Swift
class Thing {
init(_ location: Thing?, _ name: String, _ longDescription: String) {
self.location = location
self.name = name
self.longDescription = longDescription
}
weak var location: Thing?
var name: String
var longDescription: String
}
let westOfHouse = Thing(nil, "house", "West of House")
let westWallOfHouse = Thing(westOfHouse, "wall", "The Plaster has crumbled away, leaving the wood beneath to rot.")
let pathWestOfHouse = Thing(westOfHouse, "path", "An overgrown path leads south around the corner of the house.")
protocol Pullable {
func pull()
}
class Boards: Thing, Pullable {
func pull() {
if location === westWallOfHouse {
print("They come off with little effort.")
location = westOfHouse
} else {
print("Think of the splinters!")
}
}
}
let boards = Boards(westWallOfHouse, "boards", "They've been nailed directly to the wall.")
/*
func performPull(object: Thing) {
if let pullableObject = object as Pullable {
pullableObject.pull()
} else {
println("You aren't sure how to print a \(object.name).")
}
}
*/
extension Thing: CustomStringConvertible {
var description: String { return name }
}
extension Thing {
var nameWithArticle: String {
return "a " + name
}
}
var object = Thing(westOfHouse, "wall", "The Plaster has crumbled away, leaving the wood beneath to rot.")
// Printable doesn't work in a playground yet (Beta 3)
print("You aren't sure how to pull \(object)")
//println("You aren't sure how to pull \(object.description)")
//println("You aren't sure how to pull \(an ~ object)")
/*
// Special Protocols
// LogicValue if logicValue {
// Printable "\(printable)"
// Sequence for x in sequence
// IntegerLiteralConvertible 65536
// Float LIteralConvertible 1.0
// StringLiteralConvertible "abc"
// ArrayLiteralConvertible [ a, b, c ]
// DictionaryLiteralConvertible [ a: x, b: y ]
protocol Printable {
var description: String { get }
}
*/
/*
// Overloading an operator
operator infix ~ {} // Define the operator you want to use
// infix, postfix and prefix are options
func ~ (decorator: (Thing) -> String, object: Thing -> String {
return decorator(object)
})
func an(object: Thing) -> String {
return object.nameWithArticle
}
let mud = Thing(westOfHouse, "mud", "I don't know")
println("You aren't sure how to pull \(an ~ mud).")
*/
// Defining a Place
enum Direction {
case North, South, East, West
}
/*
class Place: Thing {
//init(_ name: String, _ longDescription: String) {
// super.init(<#Thing?#>, <#String#>, <#String#>)
//}
//var exits: Dictionary =
*/
================================================
FILE: Swift-Playgrounds/WWDC/2014/AdvancedSwift.playground/contents.xcplayground
================================================
================================================
FILE: Swift-Playgrounds/main.swift
================================================
//
// main.swift
// Swift-Playgrounds
//
// Created by Daniel Pink on 5/06/2014.
// Copyright (c) 2014 Electronic Innovations. All rights reserved.
//
import Cocoa
NSApplicationMain(C_ARGC, C_ARGV)
================================================
FILE: Swift-Playgrounds.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
E66B1CC01E4C183C00B6593E /* README.md in Sources */ = {isa = PBXBuildFile; fileRef = E66B1CBF1E4C183C00B6593E /* README.md */; };
E6C330A81E4C00CD0000AA37 /* icon_56811.png in Resources */ = {isa = PBXBuildFile; fileRef = E6C330A61E4C00CD0000AA37 /* icon_56811.png */; };
E6E1BED819401B3600DA4D53 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6E1BED719401B3600DA4D53 /* main.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
E6E1BEE519401B3600DA4D53 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = E6E1BECA19401B3600DA4D53 /* Project object */;
proxyType = 1;
remoteGlobalIDString = E6E1BED119401B3600DA4D53;
remoteInfo = "Swift-Playgrounds";
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
E61C4B621E4BFC0200E4E565 /* ASwiftTour.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = ASwiftTour.playground; sourceTree = ""; };
E61C4B641E4BFC0200E4E565 /* 01-TheBasics.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "01-TheBasics.playground"; sourceTree = ""; };
E61C4B651E4BFC0200E4E565 /* 02-BasicOperators.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "02-BasicOperators.playground"; sourceTree = ""; };
E61C4B661E4BFC0200E4E565 /* 03-StringsAndCharacters.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "03-StringsAndCharacters.playground"; sourceTree = ""; };
E61C4B671E4BFC0200E4E565 /* 04-CollectionTypes.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "04-CollectionTypes.playground"; sourceTree = ""; };
E61C4B681E4BFC0200E4E565 /* 05-ControlFlow.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "05-ControlFlow.playground"; sourceTree = ""; };
E61C4B691E4BFC0200E4E565 /* 06-Functions.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "06-Functions.playground"; sourceTree = ""; };
E61C4B6A1E4BFC0200E4E565 /* 07-Closures.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "07-Closures.playground"; sourceTree = ""; };
E61C4B6B1E4BFC0200E4E565 /* 08-Enumerations.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "08-Enumerations.playground"; sourceTree = ""; };
E61C4B6C1E4BFC0200E4E565 /* 09-ClassesAndStructures.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "09-ClassesAndStructures.playground"; sourceTree = ""; };
E61C4B6D1E4BFC0200E4E565 /* 10-Properties.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "10-Properties.playground"; sourceTree = ""; };
E61C4B6E1E4BFC0200E4E565 /* 11-Methods.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "11-Methods.playground"; sourceTree = ""; };
E61C4B6F1E4BFC0200E4E565 /* 12-Subscripts.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "12-Subscripts.playground"; sourceTree = ""; };
E61C4B701E4BFC0200E4E565 /* 13-Inheritance.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "13-Inheritance.playground"; sourceTree = ""; };
E61C4B711E4BFC0200E4E565 /* 14-Initialization.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "14-Initialization.playground"; sourceTree = ""; };
E61C4B721E4BFC0200E4E565 /* 15-Deinitialization.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "15-Deinitialization.playground"; sourceTree = ""; };
E61C4B731E4BFC0200E4E565 /* 16-AutomaticReferenceCounting.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "16-AutomaticReferenceCounting.playground"; sourceTree = ""; };
E61C4B741E4BFC0200E4E565 /* 17-OptionalChaining.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "17-OptionalChaining.playground"; sourceTree = ""; };
E61C4B751E4BFC0200E4E565 /* 18-ErrorHandling.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "18-ErrorHandling.playground"; sourceTree = ""; };
E61C4B761E4BFC0200E4E565 /* 19-TypeCasting.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "19-TypeCasting.playground"; sourceTree = ""; };
E61C4B771E4BFC0200E4E565 /* 20-NestedTypes.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "20-NestedTypes.playground"; sourceTree = ""; };
E61C4B781E4BFC0200E4E565 /* 21-Extensions.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "21-Extensions.playground"; sourceTree = ""; };
E61C4B791E4BFC0200E4E565 /* 22-Protocols.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "22-Protocols.playground"; sourceTree = ""; };
E61C4B7A1E4BFC0300E4E565 /* 23-Generics.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "23-Generics.playground"; sourceTree = ""; };
E61C4B7B1E4BFC0300E4E565 /* 24-AccessControl.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "24-AccessControl.playground"; sourceTree = ""; };
E61C4B7C1E4BFC0300E4E565 /* 25-AdvancedOperators.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "25-AdvancedOperators.playground"; sourceTree = ""; };
E66B1CBF1E4C183C00B6593E /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
E6C3307F1E4BFCCF0000AA37 /* Swift-Playgrounds.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Swift-Playgrounds.app"; sourceTree = BUILT_PRODUCTS_DIR; };
E6C330801E4BFCCF0000AA37 /* Swift-PlaygroundsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Swift-PlaygroundsTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
E6C330831E4C008E0000AA37 /* AdoptingCocoaDesignPatterns.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = AdoptingCocoaDesignPatterns.playground; sourceTree = ""; };
E6C330841E4C008E0000AA37 /* BasicSetup.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = BasicSetup.playground; sourceTree = ""; };
E6C330851E4C008E0000AA37 /* InteractingWithC-APIs.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "InteractingWithC-APIs.playground"; sourceTree = ""; };
E6C330861E4C008E0000AA37 /* InteractingWithObjective-C-APIs.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "InteractingWithObjective-C-APIs.playground"; sourceTree = ""; };
E6C330871E4C008E0000AA37 /* Mix&Match.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Mix&Match.playground"; sourceTree = ""; };
E6C330881E4C008E0000AA37 /* WorkingWithCocoaDataTypes.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = WorkingWithCocoaDataTypes.playground; sourceTree = ""; };
E6C3308A1E4C00A50000AA37 /* Array.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Array.playground; sourceTree = ""; };
E6C3308B1E4C00A50000AA37 /* Dictionary.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Dictionary.playground; sourceTree = ""; };
E6C3308C1E4C00A50000AA37 /* FreeFunctions.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = FreeFunctions.playground; sourceTree = ""; };
E6C3308D1E4C00A50000AA37 /* NumericTypes.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = NumericTypes.playground; sourceTree = ""; };
E6C3308E1E4C00A50000AA37 /* Protocols.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Protocols.playground; sourceTree = ""; };
E6C3308F1E4C00A50000AA37 /* String.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = String.playground; sourceTree = ""; };
E6C330901E4C00A50000AA37 /* Undocumented.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Undocumented.playground; sourceTree = ""; };
E6C330921E4C00CD0000AA37 /* 2014-08-11-SwiftOperators.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-08-11-SwiftOperators.playground"; sourceTree = ""; };
E6C330931E4C00CD0000AA37 /* Cheryls-Birthday-Alternative-1.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Cheryls-Birthday-Alternative-1.playground"; sourceTree = ""; };
E6C330941E4C00CD0000AA37 /* Cheryls-Birthday.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "Cheryls-Birthday.playground"; sourceTree = ""; };
E6C330951E4C00CD0000AA37 /* WritingSwiftClassesWithObjectiveCBehaviour.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = WritingSwiftClassesWithObjectiveCBehaviour.playground; sourceTree = ""; };
E6C330971E4C00CD0000AA37 /* 2014-08-08-LockingInSwift.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-08-08-LockingInSwift.playground"; sourceTree = ""; };
E6C330991E4C00CD0000AA37 /* 2014-08-18-SwiftLiteralConvertibles.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-08-18-SwiftLiteralConvertibles.playground"; sourceTree = ""; };
E6C3309B1E4C00CD0000AA37 /* 2014-07-23-AccessControl.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-07-23-AccessControl.playground"; sourceTree = ""; };
E6C3309C1E4C00CD0000AA37 /* 2014-07-28-InteractingWithCPointers.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-07-28-InteractingWithCPointers.playground"; sourceTree = ""; };
E6C3309D1E4C00CD0000AA37 /* 2014-08-05-Boolean.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-08-05-Boolean.playground"; sourceTree = ""; };
E6C3309E1E4C00CD0000AA37 /* 2014-08-15-ValueAndReferenceTypes.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-08-15-ValueAndReferenceTypes.playground"; sourceTree = ""; };
E6C3309F1E4C00CD0000AA37 /* 2014-08-27-OptionalCaseStudy-valuesForKeys.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = "2014-08-27-OptionalCaseStudy-valuesForKeys.playground"; sourceTree = ""; };
E6C330A21E4C00CD0000AA37 /* AdvancedSwift.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = AdvancedSwift.playground; sourceTree = ""; };
E6C330A51E4C00CD0000AA37 /* GameDevUniversity.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = GameDevUniversity.playground; sourceTree = ""; };
E6C330A61E4C00CD0000AA37 /* icon_56811.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon_56811.png; sourceTree = ""; };
E6C330A71E4C00CD0000AA37 /* SpriteKitTestbed.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = SpriteKitTestbed.playground; sourceTree = ""; };
E6E1BED619401B3600DA4D53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
E6E1BED719401B3600DA4D53 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
E6E1BECF19401B3600DA4D53 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
E6E1BEE119401B3600DA4D53 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
E61C4B611E4BFC0200E4E565 /* The Swift Programming Language */ = {
isa = PBXGroup;
children = (
E61C4B621E4BFC0200E4E565 /* ASwiftTour.playground */,
E61C4B631E4BFC0200E4E565 /* LanguageGuide */,
);
path = "The Swift Programming Language";
sourceTree = "";
};
E61C4B631E4BFC0200E4E565 /* LanguageGuide */ = {
isa = PBXGroup;
children = (
E61C4B641E4BFC0200E4E565 /* 01-TheBasics.playground */,
E61C4B651E4BFC0200E4E565 /* 02-BasicOperators.playground */,
E61C4B661E4BFC0200E4E565 /* 03-StringsAndCharacters.playground */,
E61C4B671E4BFC0200E4E565 /* 04-CollectionTypes.playground */,
E61C4B681E4BFC0200E4E565 /* 05-ControlFlow.playground */,
E61C4B691E4BFC0200E4E565 /* 06-Functions.playground */,
E61C4B6A1E4BFC0200E4E565 /* 07-Closures.playground */,
E61C4B6B1E4BFC0200E4E565 /* 08-Enumerations.playground */,
E61C4B6C1E4BFC0200E4E565 /* 09-ClassesAndStructures.playground */,
E61C4B6D1E4BFC0200E4E565 /* 10-Properties.playground */,
E61C4B6E1E4BFC0200E4E565 /* 11-Methods.playground */,
E61C4B6F1E4BFC0200E4E565 /* 12-Subscripts.playground */,
E61C4B701E4BFC0200E4E565 /* 13-Inheritance.playground */,
E61C4B711E4BFC0200E4E565 /* 14-Initialization.playground */,
E61C4B721E4BFC0200E4E565 /* 15-Deinitialization.playground */,
E61C4B731E4BFC0200E4E565 /* 16-AutomaticReferenceCounting.playground */,
E61C4B741E4BFC0200E4E565 /* 17-OptionalChaining.playground */,
E61C4B751E4BFC0200E4E565 /* 18-ErrorHandling.playground */,
E61C4B761E4BFC0200E4E565 /* 19-TypeCasting.playground */,
E61C4B771E4BFC0200E4E565 /* 20-NestedTypes.playground */,
E61C4B781E4BFC0200E4E565 /* 21-Extensions.playground */,
E61C4B791E4BFC0200E4E565 /* 22-Protocols.playground */,
E61C4B7A1E4BFC0300E4E565 /* 23-Generics.playground */,
E61C4B7B1E4BFC0300E4E565 /* 24-AccessControl.playground */,
E61C4B7C1E4BFC0300E4E565 /* 25-AdvancedOperators.playground */,
);
path = LanguageGuide;
sourceTree = "";
};
E6C330821E4C008E0000AA37 /* Using Swift With Cocoa And Objective-C */ = {
isa = PBXGroup;
children = (
E6C330831E4C008E0000AA37 /* AdoptingCocoaDesignPatterns.playground */,
E6C330841E4C008E0000AA37 /* BasicSetup.playground */,
E6C330851E4C008E0000AA37 /* InteractingWithC-APIs.playground */,
E6C330861E4C008E0000AA37 /* InteractingWithObjective-C-APIs.playground */,
E6C330871E4C008E0000AA37 /* Mix&Match.playground */,
E6C330881E4C008E0000AA37 /* WorkingWithCocoaDataTypes.playground */,
);
path = "Using Swift With Cocoa And Objective-C";
sourceTree = "";
};
E6C330891E4C00A50000AA37 /* Swift Stanard Library */ = {
isa = PBXGroup;
children = (
E6C3308A1E4C00A50000AA37 /* Array.playground */,
E6C3308B1E4C00A50000AA37 /* Dictionary.playground */,
E6C3308C1E4C00A50000AA37 /* FreeFunctions.playground */,
E6C3308D1E4C00A50000AA37 /* NumericTypes.playground */,
E6C3308E1E4C00A50000AA37 /* Protocols.playground */,
E6C3308F1E4C00A50000AA37 /* String.playground */,
E6C330901E4C00A50000AA37 /* Undocumented.playground */,
);
path = "Swift Stanard Library";
sourceTree = "";
};
E6C330911E4C00CD0000AA37 /* Others */ = {
isa = PBXGroup;
children = (
E6C330921E4C00CD0000AA37 /* 2014-08-11-SwiftOperators.playground */,
E6C330931E4C00CD0000AA37 /* Cheryls-Birthday-Alternative-1.playground */,
E6C330941E4C00CD0000AA37 /* Cheryls-Birthday.playground */,
E6C330951E4C00CD0000AA37 /* WritingSwiftClassesWithObjectiveCBehaviour.playground */,
);
path = Others;
sourceTree = "";
};
E6C330961E4C00CD0000AA37 /* Blogs */ = {
isa = PBXGroup;
children = (
E6C330971E4C00CD0000AA37 /* 2014-08-08-LockingInSwift.playground */,
E6C330981E4C00CD0000AA37 /* NSHipster */,
E6C3309A1E4C00CD0000AA37 /* Swift Blog */,
);
path = Blogs;
sourceTree = "";
};
E6C330981E4C00CD0000AA37 /* NSHipster */ = {
isa = PBXGroup;
children = (
E6C330991E4C00CD0000AA37 /* 2014-08-18-SwiftLiteralConvertibles.playground */,
);
path = NSHipster;
sourceTree = "";
};
E6C3309A1E4C00CD0000AA37 /* Swift Blog */ = {
isa = PBXGroup;
children = (
E6C3309B1E4C00CD0000AA37 /* 2014-07-23-AccessControl.playground */,
E6C3309C1E4C00CD0000AA37 /* 2014-07-28-InteractingWithCPointers.playground */,
E6C3309D1E4C00CD0000AA37 /* 2014-08-05-Boolean.playground */,
E6C3309E1E4C00CD0000AA37 /* 2014-08-15-ValueAndReferenceTypes.playground */,
E6C3309F1E4C00CD0000AA37 /* 2014-08-27-OptionalCaseStudy-valuesForKeys.playground */,
);
path = "Swift Blog";
sourceTree = "";
};
E6C330A01E4C00CD0000AA37 /* WWDC */ = {
isa = PBXGroup;
children = (
E6C330A11E4C00CD0000AA37 /* 2014 */,
);
path = WWDC;
sourceTree = "";
};
E6C330A11E4C00CD0000AA37 /* 2014 */ = {
isa = PBXGroup;
children = (
E6C330A21E4C00CD0000AA37 /* AdvancedSwift.playground */,
);
path = 2014;
sourceTree = "";
};
E6C330A31E4C00CD0000AA37 /* Specific Technologies */ = {
isa = PBXGroup;
children = (
E6C330A41E4C00CD0000AA37 /* SpriteKit */,
);
path = "Specific Technologies";
sourceTree = "";
};
E6C330A41E4C00CD0000AA37 /* SpriteKit */ = {
isa = PBXGroup;
children = (
E6C330A51E4C00CD0000AA37 /* GameDevUniversity.playground */,
E6C330A61E4C00CD0000AA37 /* icon_56811.png */,
E6C330A71E4C00CD0000AA37 /* SpriteKitTestbed.playground */,
);
path = SpriteKit;
sourceTree = "";
};
E6E1BEC919401B3600DA4D53 = {
isa = PBXGroup;
children = (
E66B1CBF1E4C183C00B6593E /* README.md */,
E6E1BED419401B3600DA4D53 /* Swift-Playgrounds */,
E6C3307F1E4BFCCF0000AA37 /* Swift-Playgrounds.app */,
E6C330801E4BFCCF0000AA37 /* Swift-PlaygroundsTests.xctest */,
);
sourceTree = "";
};
E6E1BED419401B3600DA4D53 /* Swift-Playgrounds */ = {
isa = PBXGroup;
children = (
E61C4B611E4BFC0200E4E565 /* The Swift Programming Language */,
E6C330821E4C008E0000AA37 /* Using Swift With Cocoa And Objective-C */,
E6C330891E4C00A50000AA37 /* Swift Stanard Library */,
E6C330911E4C00CD0000AA37 /* Others */,
E6C330961E4C00CD0000AA37 /* Blogs */,
E6C330A01E4C00CD0000AA37 /* WWDC */,
E6C330A31E4C00CD0000AA37 /* Specific Technologies */,
E6E1BED519401B3600DA4D53 /* Supporting Files */,
);
path = "Swift-Playgrounds";
sourceTree = "";
};
E6E1BED519401B3600DA4D53 /* Supporting Files */ = {
isa = PBXGroup;
children = (
E6E1BED619401B3600DA4D53 /* Info.plist */,
E6E1BED719401B3600DA4D53 /* main.swift */,
);
name = "Supporting Files";
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
E6E1BED119401B3600DA4D53 /* Swift-Playgrounds */ = {
isa = PBXNativeTarget;
buildConfigurationList = E6E1BEEE19401B3600DA4D53 /* Build configuration list for PBXNativeTarget "Swift-Playgrounds" */;
buildPhases = (
E6E1BECE19401B3600DA4D53 /* Sources */,
E6E1BECF19401B3600DA4D53 /* Frameworks */,
E6E1BED019401B3600DA4D53 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "Swift-Playgrounds";
productName = "Swift-Playgrounds";
productReference = E6C3307F1E4BFCCF0000AA37 /* Swift-Playgrounds.app */;
productType = "com.apple.product-type.application";
};
E6E1BEE319401B3600DA4D53 /* Swift-PlaygroundsTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = E6E1BEF119401B3600DA4D53 /* Build configuration list for PBXNativeTarget "Swift-PlaygroundsTests" */;
buildPhases = (
E6E1BEE019401B3600DA4D53 /* Sources */,
E6E1BEE119401B3600DA4D53 /* Frameworks */,
E6E1BEE219401B3600DA4D53 /* Resources */,
);
buildRules = (
);
dependencies = (
E6E1BEE619401B3600DA4D53 /* PBXTargetDependency */,
);
name = "Swift-PlaygroundsTests";
productName = "Swift-PlaygroundsTests";
productReference = E6C330801E4BFCCF0000AA37 /* Swift-PlaygroundsTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
E6E1BECA19401B3600DA4D53 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Electronic Innovations";
TargetAttributes = {
E6E1BED119401B3600DA4D53 = {
CreatedOnToolsVersion = 6.0;
LastSwiftMigration = 0820;
};
E6E1BEE319401B3600DA4D53 = {
CreatedOnToolsVersion = 6.0;
LastSwiftMigration = 0820;
TestTargetID = E6E1BED119401B3600DA4D53;
};
};
};
buildConfigurationList = E6E1BECD19401B3600DA4D53 /* Build configuration list for PBXProject "Swift-Playgrounds" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = E6E1BEC919401B3600DA4D53;
productRefGroup = E6E1BEC919401B3600DA4D53;
projectDirPath = "";
projectRoot = "";
targets = (
E6E1BED119401B3600DA4D53 /* Swift-Playgrounds */,
E6E1BEE319401B3600DA4D53 /* Swift-PlaygroundsTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
E6E1BED019401B3600DA4D53 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E6C330A81E4C00CD0000AA37 /* icon_56811.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E6E1BEE219401B3600DA4D53 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
E6E1BECE19401B3600DA4D53 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E66B1CC01E4C183C00B6593E /* README.md in Sources */,
E6E1BED819401B3600DA4D53 /* main.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E6E1BEE019401B3600DA4D53 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
E6E1BEE619401B3600DA4D53 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = E6E1BED119401B3600DA4D53 /* Swift-Playgrounds */;
targetProxy = E6E1BEE519401B3600DA4D53 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
E6E1BEEC19401B3600DA4D53 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
METAL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
E6E1BEED19401B3600DA4D53 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "-";
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.9;
METAL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
};
name = Release;
};
E6E1BEEF19401B3600DA4D53 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "Swift-Playgrounds/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "au.com.electronicinnovations.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
E6E1BEF019401B3600DA4D53 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = "Swift-Playgrounds/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "au.com.electronicinnovations.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Release;
};
E6E1BEF219401B3600DA4D53 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Swift-Playgrounds.app/Contents/MacOS/Swift-Playgrounds";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = "Swift-PlaygroundsTests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
METAL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = "au.com.electronicinnovations.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUNDLE_LOADER)";
};
name = Debug;
};
E6E1BEF319401B3600DA4D53 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Swift-Playgrounds.app/Contents/MacOS/Swift-Playgrounds";
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
);
INFOPLIST_FILE = "Swift-PlaygroundsTests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
METAL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "au.com.electronicinnovations.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
TEST_HOST = "$(BUNDLE_LOADER)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
E6E1BECD19401B3600DA4D53 /* Build configuration list for PBXProject "Swift-Playgrounds" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E6E1BEEC19401B3600DA4D53 /* Debug */,
E6E1BEED19401B3600DA4D53 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
E6E1BEEE19401B3600DA4D53 /* Build configuration list for PBXNativeTarget "Swift-Playgrounds" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E6E1BEEF19401B3600DA4D53 /* Debug */,
E6E1BEF019401B3600DA4D53 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
E6E1BEF119401B3600DA4D53 /* Build configuration list for PBXNativeTarget "Swift-PlaygroundsTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E6E1BEF219401B3600DA4D53 /* Debug */,
E6E1BEF319401B3600DA4D53 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = E6E1BECA19401B3600DA4D53 /* Project object */;
}
================================================
FILE: Thoughts-Questions.txt
================================================
Swift Thoughts and Questions
- How do you get pretty printing of instances in the playground?
- Could you get a pretty printout of something like a 2D matrix?
- How does Phase two of object initialization work?
- In the Deinitialization Chapter is the Bank object (that only contains Type properties and methods) a hacky way of having a singleton?
- The Player deinitialization method doesn't get called in the playground when the playerOne variable is set to nil.
In "Using Swift with Cocoa and Objective-C"
- let myTextField = UITextField(frame: CGRect(0.0, 0.0, 200.0, 40.0)) is corrected by the playground autocorrecto to let myTextField = UITextField(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 40.0))
- myTextField.editing = false is reported as an error as editing is not allowed to be assigned.
- The following doesn't seem to work in a playground
let myLength = myObject.length?
if let fifthCharacter = myObject.characterAtIndex(5) {
println("Found \(fifthCharacter) at index 5")
}
- let squareRoot = Float(sqrt(3)) gives an "Ambiguous use of sqrt in Beta 3". It doesn't look like you can call sqrt() on an integer.
- The following code gives a error in the playground no matter what object and UIButton are.
if object is UIButton {
// object is of type UIButton
} else {
// object is not of type UIButton
}