目次
Swift
REPL
% swift repl Welcome to Apple Swift version 5.7.1 (swiftlang-5.7.1.135.3 clang-1400.0.29.51). Type :help for assistance. 1> var a = "Hello" a: String = "Hello" 2> print(a) Hello 3> print(a + " Swift") Hello Swift 4>
Swift Package Manager
% mkdir hello % cd hello % swift package init --name hello --type executable Creating library package: hello Creating Package.swift Creating README.md Creating .gitignore Creating Sources/ Creating Sources/hello/hello.swift Creating Tests/ Creating Tests/helloTests/ Creating Tests/helloTests/helloTests.swift
% swift run Building for debugging... [3/3] Linking hello Build complete! (0.96s) Hello, World!
% swift test Building for debugging... [3/3] Linking helloPackageTests Build complete! (12.87s) Test Suite 'All tests' started at 2022-12-13 10:01:34.569 Test Suite 'helloPackageTests.xctest' started at 2022-12-13 10:01:34.570 Test Suite 'helloTests' started at 2022-12-13 10:01:34.571 Test Case '-[helloTests.helloTests testExample]' started. Test Case '-[helloTests.helloTests testExample]' passed (0.004 seconds). Test Suite 'helloTests' passed at 2022-12-13 10:01:34.574. Executed 1 test, with 0 failures (0 unexpected) in 0.004 (0.004) seconds Test Suite 'helloPackageTests.xctest' passed at 2022-12-13 10:01:34.574. Executed 1 test, with 0 failures (0 unexpected) in 0.004 (0.004) seconds Test Suite 'All tests' passed at 2022-12-13 10:01:34.574. Executed 1 test, with 0 failures (0 unexpected) in 0.004 (0.005) seconds
% ./.build/x86_64-apple-macosx/debug/hello Hello, World! % file ./.build/x86_64-apple-macosx/debug/hello ./.build/x86_64-apple-macosx/debug/hello: Mach-O 64-bit executable x86_64
% cat Sources/hello/hello.swift
@main public struct hello { public private(set) var text = "Hello, World!" public static func main() { print(hello().text) } }
% cat Tests/helloTests/helloTests.swift
import XCTest @testable import hello final class helloTests: XCTestCase { func testExample() throws { // This is an example of a functional test case. // Use XCTAssert and related functions to verify your tests produce the correct // results. XCTAssertEqual(hello().text, "Hello, World!") } }
Boot Camp Text で Python と比較
唐突に Python と Swift を比較してみようと思った。
https://pycamp.pycon.jp/textbook/ を Swift で書いてみる。Xcode 14.1 の Playground で動作を確認する。
fizzbuzz
第一段階。まず引数をそのまま返す関数を作って100回実行する。
func fizzbuzz(_ num: Int) -> Int { return num } for num in 1...100 { print(fizzbuzz(num)) }
- 1..<101 とも書ける
- 関数定義で _ をつけるのは「外部引数名の省略」のため。つけない場合は、呼び出す側では fizzbuzz(num:num) と書く。
第2段階。
func fizzbuzz(_ num: Int) -> String { if num % 3 == 0 && num % 5 == 0 { return "FizzBuzz" } else if num % 3 == 0 { return "Fizz" } else if num % 5 == 0 { return "Buzz" } return String(num) } for num in 1...100 { print(fizzbuzz(num)) }
- 論理演算子は and ではなく &&
- 文字列リテラルでシングルクオートは使えない
- Int を文字列に型変換するには String(値)
定数と変数
let a = 1 print(a) //a = 2 //print(a) var b = 2 print(b) b = 3 print(b) //b = "4" //print(b) 出力 1 2 3
- let は定数。a=2 のコメントアウトを外すとエラー
- var は変数。初期値の型を代入できる。b="4" のコメントアウトを外すとエラー
var c: Float = 5 print(c) 出力 5.0
- 変数の宣言で型を記述できる
べき乗
import Foundation print(pow(5,2))
- 5**2 はべき乗ではないので pow 関数を使う
- pow 関数を使うには Foundation などのインポートが必要
文字列
print("Hello\"world") var a = 1 print("Hello \(a) world")
Hello"world Hello 1 world
複数行文字列リテラル
print(""" foo bar baz """)
- 開始の """ の直後には何も書かない
- 終了の """ の直前にも何も書かない
print("spam" + "ham")
- 足し算はできる
- 掛け算はできない
let s = "swift" let i = s.startIndex print(s[i]) 結果 s
- 文字列処理はいろいろ大変という話
コレクション
var a : [Any] = ["spam", "egg", 0.5] print(a)
- 中身の型が揃っていない配列を作るには Any 型指定が必要
a += ["ham"] // a = a + ["ham"] a[1]
- スライスは ArraySlice で行う
for animal in ["cat", "dog", "snake"] { print(animal) }
- これだけみると Python そっくりなのに
コレクションは配列、辞書、集合
タプル
var (dog, cat) = ("dog", "cat") print(dog, cat)
- ここだけ見てるとコレクションっぽいというか Python っぽい
var animals = ("dog", "cat") print(animals) print(animals.0) print(animals.1) //for animal in animals { // print(animal) //}
- for は使えない。シーケンスではないと言われる。
let http200Status = (statusCode: 200, description: "OK") print(http200Status.statusCode) let (statusCode, _) = http200Status print(statusCode)
ファイル操作
Playground でテキストファイルの読み書き、意外に大変
https://stackoverflow.com/questions/24245916/how-can-i-read-a-file-in-a-swift-playground
日付
import Foundation var d = NSDate() print(d) var d2 = Date() print(d2)
正規表現
Swift 5.7 の新機能
https://www.hackingwithswift.com/swift/5.7/regexes
そのまま引用
let search1 = /My name is (.+?) and I'm (\d+) years old./ let greeting1 = "My name is Taylor and I'm 26 years old." if let result = try? search1.wholeMatch(in: greeting1) { print("Name: \(result.1)") print("Age: \(result.2)") }
もうしわけないので if let ではなく guard let else return に書き換えてみる
func hello() { let search1 = /My name is (.+?) and I'm (\d+) years old./ let greeting1 = "My name is Taylor and I'm 26 years old." guard let result = try? search1.wholeMatch(in: greeting1) else { return } print("Name: \(result.1)") print("Age: \(result.2)") } hello()
https://speakerdeck.com/ainame/swift-5-dot-7debian-waruzheng-gui-biao-xian-woshi-sitemiyou
SwiftUI
文献
末尾クロージャー
SwiftUI APIの設計技術:プログレッシブディスクロージャ
https://developer.apple.com/videos/play/wwdc2022/10059/
<html> <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">先に見てたのはこっちで、なるほどシンタックスシュガーとデフォルト動作がすごい作り込まれてることがわかった<a href="https://twitter.com/hashtag/wwdc22?src=hash&ref_src=twsrc%5Etfw">#wwdc22</a> SwiftUI APIの設計技術:プログレッシブディスクロージャ <a href="https://t.co/lUiqLFz7XH">https://t.co/lUiqLFz7XH</a></p>— にしもつ (@24motz) <a href="https://twitter.com/24motz/status/1601522343976701952?ref_src=twsrc%5Etfw">December 10, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> </html>
Button(action: { a = 1 }) { Text("Label") } // 以下のように書ける Button("Label") { a = 1 }
しかも第1引数は localized string key で、英語で書いて Localizable.strings (ja) をあとで書けば2ヶ国語対応になる。
ちゃんと書いてあった。
https://developer.apple.com/documentation/swiftui/button
そして action は trailing closure として書けるのか。
https://docs.swift.org/swift-book/LanguageGuide/Closures.html
ボタンを押すとアラートを出して、さらに OK を押させる。
Instance Method alert(_:isPresented:actions:)
公式のサンプルを改変。
struct ContentView: View { @State private var didSave = false var body: some View { Button("Save") { didSave = true } .alert( "Saved.", isPresented: $didSave ) { Button("OK") { print("OK is pressed") } } } }
print の出力はプレビューではなくシミュレーターで実行すると確認できる。
State didSave はOKを押したときに false に戻る。
あえて冗長に書くと
struct ContentView: View { @State private var didSave = false var body: some View { Button( action: { didSave = true }, label: { Text("Hello") } ) .alert( "Saved.", isPresented: $didSave, actions: { Button( action: { print("OK is pressed") }, label: { Text("OK") } ) } ) } }
repl で末尾クロージャーを試す
1> var names = ["cat", "dog", "snake"] names: [String] = 3 values { [0] = "cat" [1] = "dog" [2] = "snake" } 2> names.sorted { $0 > $1 } $R0: [String] = 3 values { [0] = "snake" [1] = "dog" [2] = "cat" } 3> names.sorted { $0.count < $1.count } $R1: [String] = 3 values { [0] = "cat" [1] = "dog" [2] = "snake" }
Ruby だと
names = ["cat", "dog", "snake"] names.sort { |a,b| a.length <=> b.length } # => ["cat", "dog", "snake"] names.sort { _1.length <=> _2.length } # => ["cat", "dog", "snake"]