Last active
November 13, 2023 08:51
-
-
Save ZenkieBear/7e0ba499f32870cd86de9797bbc7b999 to your computer and use it in GitHub Desktop.
learn-swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
print("Hello, world") | |
// Prints "Hello, world | |
// Simple Values | |
var myVariable = 18 | |
myVariable = 33 | |
let myConstant = 18 | |
//print(myVariable, myConstant) | |
// Type Infer | |
let implicitInteger = 70 | |
let implicitDouble = 70.0 | |
let explicitDouble: Double = 70 | |
let explicitFloat: Float = 4 | |
//print(implicitInteger, implicitDouble, explicitDouble, explicitFloat) | |
// Explicitly Convert Type | |
let label = "This width is " | |
let width = 94 | |
let widthLabel = label + String(width) | |
//print(widthLabel) | |
// \() expression | |
let apples = 3 | |
let oranges = 5 | |
let appleSummary = "I have \(apples) apples." | |
let fruitSummary = "I have \(apples + oranges) frruits." | |
let price = 5.2 | |
let applePrice = "Apple's price is \(price)" | |
let zenkie = "Zenkié Bear" | |
let greetingZenkie = "Salut, \(zenkie)!" | |
//print(appleSummary, fruitSummary, greetingZenkie, separator: "\n") | |
// Multiple line string | |
let quotation = """ | |
Even though there's whitespace to the left, | |
the actual lines aren't indented. | |
Except for this line. | |
Double quotes (") can appear without being escaped. | |
I still have \(apples + oranges) pieces of fruit. | |
""" | |
//print(quotation) | |
// Arrays and Dictionaries | |
var fruits = ["strawberries", "limes", "tangerines"] | |
fruits[1] = "grapes" | |
var occupations = [ | |
"Zenkie": "Programmer", | |
"Tayler": "Singer" | |
] | |
occupations["Bobo"] = "Product Designer" | |
//print(fruits, occupations, separator: "\n") | |
// Appending, array auto grows | |
fruits.append("blueberries") | |
//print(fruits) | |
// Write an empty array or dictionary | |
fruits = [] | |
occupations = [:] | |
// Define to an initial constant | |
let emptyArray: [String] = [] | |
let emptyDictionary: [String: String] = [:] | |
//print(fruits, occupations, emptyArray, emptyDictionary) | |
// Control Flow | |
//let individualScores = [75, 43, 30, 87, 12] | |
let individualScores = [75, 43, 80, 87, 12] | |
var teamScore = 0 | |
for score in individualScores { | |
if score > 50 { | |
teamScore += 3 | |
} else { | |
teamScore += 1 | |
} | |
} | |
//print(teamScore) | |
// if after = | |
let scoreDecoration = if teamScore > 10 { | |
"🎉" | |
} else { | |
"🙂" | |
} | |
//print("Score", teamScore, scoreDecoration) | |
// Optional value | |
var optionalString: String? = "Hello" | |
//print(optionalString == nil) | |
var optionalName: String? = "Zenkie Bear" | |
optionalName = nil | |
var greeting = "Hello!" | |
//if optionalName != nil { | |
// let name = optionalName | |
if let name = optionalName { // equal to previous 2 lines | |
// if the optionName is nil, this block won't be execute | |
greeting = "Hello, \(name)" | |
} | |
//print(greeting) | |
// ?? operator | |
let nickname: String? = nil | |
let fullName: String? = "John Appleseed" | |
let informalGreeting = "Hi \(nickname ?? fullName)" | |
//print(informalGreeting) | |
if let nickname { | |
print("Hey, \(nickname)") | |
} | |
// Switch | |
let vegetable = "green pe pper" | |
switch vegetable { | |
case "celery": | |
print("Add some raisins and make ants on the 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("Everthing tastes good in soup.") | |
} | |
// for-in literate | |
let interestingNumbers = [ | |
"Prime": [2, 3, 5, 7, 11, 13], | |
"Fibonacci": [1, 1, 2, 3, 5, 8], | |
"Square": [1, 4, 9, 16, 25], | |
] | |
for (type, numbers) in interestingNumbers { | |
var largest = 0 | |
for number in numbers { | |
if number > largest { | |
largest = number | |
} | |
} | |
// print("\(type)'s largest is \(largest)") | |
} | |
// while loop | |
var n = 2 | |
while n < 0 { | |
n *= 2 | |
} | |
print(n) | |
var m = 2 | |
repeat { | |
m *= 2 | |
} while m < 0 | |
print(m) | |
var total = 0 | |
for i in 0..<4 { | |
total += i | |
} | |
print(total) // 0 + 1 + 2 + 3 = 6 | |
// Functions and Closures | |
func greet(_ person: String, on lunch: String) -> String { | |
return "Hello \(person), today's lunch is \(lunch)." | |
} | |
//print(greet("Bobo", on: "Beef")) | |
// Tuples | |
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int, avg: Double) { | |
var min = scores[0], max = scores[0], sum = 0 | |
for score in scores { | |
if score > max { | |
max = score | |
} | |
if score < min { | |
min = score | |
} | |
sum += score | |
} | |
var avg = Double(sum) / Double(scores.count) | |
return (min, max, sum, avg) | |
} | |
let staticts = calculateStatistics(scores: [5, 3, 100, 3, 9]) | |
//print(staticts) | |
//print(staticts.2) | |
// Nested function | |
func returnFifteen() -> Int { | |
var y = 10 | |
func add() { | |
y += 5 | |
} | |
add() | |
return y | |
} | |
print(returnFifteen()) | |
// Function variable | |
func useIncrementer() -> ((Int) -> Int) { | |
func addOne(_ number: Int) -> Int { | |
return number + 1 | |
} | |
return addOne | |
} | |
var incrementer = useIncrementer() | |
print(incrementer(7)) | |
// Function parameter type | |
func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool { | |
for item in list { | |
if condition(item) { | |
return true | |
} | |
} | |
return false | |
} | |
func lessThan10(number: Int) -> Bool { | |
return number < 10 | |
} | |
var numbers = [20, 19, 17, 12] | |
print(hasAnyMatches(list: numbers, condition: lessThan10)) | |
// Anounymous function | |
print(numbers.map({(number: Int) -> Int in | |
if (number % 2 == 1) { | |
return 0 | |
} | |
let result = 3 * number | |
return result | |
})) | |
// concisely | |
let mappedNumbers = numbers.map({number in number * 3}) | |
//print(mappedNumbers) | |
// Refering to parameter by number | |
//let sortedNumbers = numbers.sorted (by: { $0 > $1 }) | |
let sortedNumbers = numbers.sorted { $0 > $1 } | |
//print(sortedNumbers) | |
// Objects and Classes | |
class Shape { | |
var numberOfSides = 0 | |
let name = "Zenkie Bear" | |
func simpleDescription() -> String { | |
return "A shape with \(numberOfSides) sides." | |
} | |
func getName() -> String { | |
return name | |
} | |
} | |
var shape = Shape() | |
shape.numberOfSides = 7 | |
//print(shape.simpleDescription(), shape.getName()) | |
// Initializer & self | |
class NamedShape { | |
var numberOfSides = 0 | |
let name: String | |
init(_ name: String) { | |
self.name = name | |
} | |
func simpleDescription() -> String { | |
return "A shape with \(numberOfSides) sides." | |
} | |
func getName() -> String { | |
return self.name | |
} | |
} | |
var namedShape = NamedShape("Zenkié Bear") | |
namedShape.numberOfSides = 7 | |
//print(namedShape.simpleDescription(), namedShape.getName()) | |
// Extend & Override | |
class Square: NamedShape { | |
var sideLength: Double | |
init(sideLength: Double, name: String) { | |
self.sideLength = sideLength | |
super.init(name) | |
numberOfSides = 4 | |
} | |
func area() -> Double { | |
return sideLength * sideLength | |
} | |
override func simpleDescription() -> String { | |
return "A square with sides of length \(sideLength)." | |
} | |
} | |
let square = Square(sideLength: 5.2, name: "my test square") | |
//print(square.area(), square.simpleDescription()) | |
// Experiment | |
class Circle: NamedShape { | |
var radius: Double | |
init(radius: Double, name: String) { | |
self.radius = radius | |
super.init(name) | |
} | |
func area() -> Double { | |
return radius * radius * 3.14 | |
} | |
override func simpleDescription() -> String { | |
return "A circle with radius of length \(radius)." | |
} | |
} | |
let circle = Circle(radius: 10, name: "my test circle") | |
//print(circle.area(), circle.simpleDescription()) | |
// Getter & Setter | |
class EquilateralTriangle: NamedShape { | |
var sideLength: Double | |
init(sideLength: Double, name: String) { | |
self.sideLength = sideLength | |
super.init(name) | |
numberOfSides = 3 | |
} | |
var perimeter: Double { | |
get { | |
return 3 * sideLength | |
} | |
set { | |
sideLength = newValue / 3.0 | |
} | |
} | |
override func simpleDescription() -> String { | |
return "A equilateral triangle with sides of length \(sideLength)." | |
} | |
} | |
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle") | |
//print(triangle.perimeter) | |
triangle.perimeter = 9.9 | |
//print(triangle.sideLength) | |
// willSet & didSet | |
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: "test TriangleAndSquare") | |
//print(triangleAndSquare.square.sideLength, triangleAndSquare.square.sideLength) | |
triangleAndSquare.square = Square(sideLength: 50, name: "larger square") | |
//print(triangleAndSquare.triangle.sideLength) | |
// ?. expression | |
var optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square") | |
optionalSquare = nil | |
let sideLength = optionalSquare?.sideLength ?? -1 | |
//print(sideLength) | |
// Enumerations ans 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 | |
print(ace, aceRawValue) | |
// Experiment | |
func compareRanks(a: Rank, b: Rank) -> Bool { | |
return a.rawValue > b.rawValue | |
} | |
var ranks = [Rank.two, Rank.three, Rank.ace, Rank.king, Rank.eight, Rank.ten, Rank.jack] | |
ranks.sort(by: compareRanks) | |
//print(ranks) | |
// Create from rawValue | |
if let convertedRank = Rank(rawValue: 3) { | |
// print(convertedRank.simpleDescription()) | |
} | |
// Actual values | |
enum Suit { | |
case spades, hearts, diamonds, clubs | |
func simpleDescription() -> String { | |
switch self { | |
case .spades: | |
return "spades" | |
case .hearts: | |
return "hearts" | |
case .diamonds: | |
return "diamonds" | |
default: | |
return "clubs" | |
} | |
} | |
func color() -> String { | |
switch self { | |
case .spades, .clubs: | |
return "black" | |
default: | |
return "red" | |
} | |
} | |
} | |
let hearts = Suit.hearts | |
let heartsDescription = hearts.simpleDescription() | |
print(hearts, heartsDescription) | |
// Experiment | |
print(Suit.spades.color(), | |
Suit.hearts.color(), | |
Suit.diamonds.color(), | |
Suit.clubs.color()) | |
// Assign value when make instance | |
enum ServerResponse { | |
case result(String, String) | |
case failure(String) | |
} | |
let success = ServerResponse.result("6:00 am", "8:09 pm") | |
let china = ServerResponse.result("7:00 am", "5:50 pm") | |
let failure = ServerResponse.failure("Out of cheese.") | |
func printResponse(_ response: ServerResponse) { | |
switch response { | |
case let .result(sunrise, sunset): | |
print("Sunrise is at \(sunrise) and sunet is at \(sunset).") | |
case let .failure(message): | |
print("Failure... \(message)") | |
} | |
} | |
//printResponse(success) | |
//printResponse(china) | |
//printResponse(failure) | |
// Structure | |
struct Card { | |
var rank: Rank | |
var suit: Suit | |
func simpleDescription() -> String { | |
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())" | |
} | |
} | |
let threeOfSpades = Card(rank: .three, suit: .spades) | |
let threeOfSpadesDescription = threeOfSpades.simpleDescription() | |
//print(threeOfSpades, threeOfSpadesDescription) | |
func getFullDeckCards() -> [Card] { | |
var result: [Card] = [] | |
for rank in 1...13 { | |
for suit in [Suit.spades, Suit.hearts, Suit.diamonds, Suit.clubs] { | |
result.append(Card(rank: Rank(rawValue: rank) ?? Rank.ace, suit: suit)) | |
} | |
} | |
return result | |
} | |
for card in getFullDeckCards() { | |
// print(card.simpleDescription()) | |
} | |
// Concurrency | |
func fetchUserID(from server: String) async -> Int { | |
if server == "primary" { | |
return 1989 | |
} | |
return 501 | |
} | |
func fetchUsername(from server: String) async -> String { | |
let userID = await fetchUserID(from: server) | |
if userID == 1989 { | |
return "Taylor Swift" | |
} | |
return "Guest" | |
} | |
func connectUser(to server: String) async { | |
async let userID = fetchUserID(from: server) | |
async let username = fetchUsername(from: server) | |
let greeting = await "Hello \(username), user ID \(userID)" | |
// print(greeting) | |
} | |
Task { | |
await connectUser(to: "primary") | |
} | |
Task { | |
let userIDs = await withTaskGroup(of: Int.self) { taskGrop in | |
for server in ["primary", "test", "development"] { | |
taskGrop.addTask { | |
return await fetchUserID(from: server) | |
} | |
} | |
var results: [Int] = [] | |
for await result in taskGrop { | |
results.append(result) | |
} | |
return results | |
} | |
// print(await userIDs) | |
} | |
// actor's methods and properties are process security | |
actor ServerConnection { | |
var server: String = "primary" | |
private var activeUsers: [Int] = [] | |
func connect() async -> Int { | |
let userID = await fetchUserID(from: server) | |
activeUsers.append(userID) | |
return userID | |
} | |
} | |
Task { | |
let server = ServerConnection() | |
let userID = await server.connect() | |
// print(userID) | |
} | |
// Protocols and Extensions | |
protocol ExampleProtocol { | |
var simpleDescription: String { get } | |
mutating func adjust() | |
func get() -> String | |
} | |
class SimpleClass: ExampleProtocol { | |
var simpleDescription: String = "A very simple class" | |
var anotherProperty = "Hi" | |
func adjust() { | |
simpleDescription += " Now 100% adjusted." | |
} | |
func get() -> String { | |
return simpleDescription | |
} | |
} | |
var a = SimpleClass() | |
a.adjust() | |
//print(a.simpleDescription) | |
struct SimpleStructure: ExampleProtocol { | |
var simpleDescription: String = "A simple structure" | |
// mutating means this method will change some properties of one instance | |
mutating func adjust() { | |
simpleDescription += " (adjusted)" | |
} | |
func get() -> String { | |
return simpleDescription | |
} | |
} | |
var b = SimpleStructure() | |
b.adjust() | |
//print(b.simpleDescription, b.get()) | |
// Extension | |
extension Int: ExampleProtocol { | |
func get() -> String { | |
return String(self) | |
} | |
var simpleDescription: String { | |
return "The number \(self)" | |
} | |
mutating func adjust() { | |
self += 42 | |
} | |
} | |
//print(7.simpleDescription) | |
// Experiment | |
extension Double { | |
var absoluteValue: Double { | |
return abs(self) | |
} | |
} | |
let number = -5.5 | |
let absoluteNumber = number.absoluteValue | |
//print(number, number.absoluteValue) | |
let protocalValue: any ExampleProtocol = a | |
print(protocalValue.simpleDescription) | |
print(a.anotherProperty) | |
//price(protocalValue.anotherProperty) | |
// Error handling | |
enum PrinterError: Error { | |
case outOfPaper | |
case onToner | |
case onFire | |
} | |
func send(job: Int, printName: String) throws -> String { | |
if (printName == "Never Has Toner") { | |
throw PrinterError.onToner | |
} | |
return "Job sent" | |
} | |
// do-catch | |
do { | |
// let printerResponse = try send(job: 1040, printName: "Bi Sheng") | |
let printerResponse = try send(job: 1040, printName: "Never Has Toner") | |
print(printerResponse) | |
//} catch { | |
// print(error) | |
} catch let e { | |
print(e) | |
} | |
// Experiment | |
do { | |
throw PrinterError.onToner | |
// throw PrinterError.onFire // I'll just put this over here, with the rest of the fire. | |
// throw PrinterError.outOfPaper // Printer error: outOfPaper. | |
} 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) | |
} | |
// try? | |
let printerSuccess = try? send(job: 1989, printName: "Mergenthanler") | |
let printerFailure = try? send(job: 1989, printName: "Never Has Toner") | |
//print(printerSuccess, printerFailure) | |
// Defer | |
var fridgeIsOpen = false | |
let fridgeContent = ["milk", "eggs", "leftovers"] | |
func fridgeContains(_ food: String) -> Bool { | |
fridgeIsOpen = true | |
defer { | |
fridgeIsOpen = false | |
} | |
let result = fridgeContent.contains(food) | |
return result | |
} | |
if fridgeContains("banana") { | |
print("Found a banana") | |
} | |
//print(fridgeIsOpen) | |
// Generics | |
func makeArray<I>(repeating item: I, numberOfTimes: Int) -> [I] { | |
var result: [I] = [] | |
for _ in 0..<numberOfTimes { | |
result.append(item) | |
} | |
return result | |
} | |
//print(makeArray(repeating: "Hello", numberOfTimes: 10)) | |
// With types | |
enum OptionalValue<Wrapped> { | |
case none | |
case some(Wrapped) | |
} | |
var possibleInteger: OptionalValue<Int> = .none | |
//print(possibleInteger) | |
possibleInteger = .some(100) | |
//print(possibleInteger) | |
// where | |
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> [T.Element] | |
where T.Element: Equatable, T.Element == U.Element | |
{ | |
var result: [T.Element] = [] | |
for lhsItem in lhs { | |
for rhsItem in rhs { | |
if lhsItem == rhsItem { | |
result.append(lhsItem) | |
} | |
} | |
} | |
return result | |
} | |
print(anyCommonElements([1, 2, 3], [2, 3])) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment