Swiftの勉強

Swiftについて
Swiftのリソース(開発ツールやドキュメントへのリンク)
標準ライブラリ
Documentationの左のアイコンを開き、Filterを使って関数を検索できる
Swift Standard Library | Apple Developer Documentation
Swiftの特徴
Playground
Objective-Cとの相互運用
オープンソース
LLVMコンパイラ
メモリの自動管理
Optional型
グローバルスコープで書かれたコードはプログラムのエントリポイントとして使用される
セミコロンは必要ない
letで定数、varで変数を定義する
型推論
型変換は明示的に行う
\()
で文字列の中に変数を埋め込むことができる
if, switch, for, while などがある
class
protocol
エラー処理のためのdo-catchとtry
ジェネリック型
async, await
SwiftUI | Apple Developer Documentation

print(_:separator:terminator:) | Apple Developer Documentation
指定された項目のテキスト表現を標準出力に書き込みます。
func print(
_ items: Any...,
separator: String = " ",
terminator: String = "\n"
)

iOSアプリ開発チュートリアル
iOS App Dev Tutorials | Apple Developer Documentation
2種類のフレームワークがある?
SwiftUI
UIKit
Using stacks to arrange views — iOS App Dev Tutorials | Apple Developer Documentation
プロジェクト作成
Choose a template for your new project:
> iOS
> Appliation
> App
Product Name
> 任意の名前
Interface
> SwiftUI
Language
> Swift
プロジェクトの保存場所を選択
View
プロトコルに準拠した構造体を作成.
PreviewProvider
プロトコルに準拠した構造体の previews
プロパティに作成した View
を登録
import SwiftUI
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Viewの中にTextやLabelなどをVStackやHStackを使って配置する
View | Apple Developer Documentation
protocol View
アプリのユーザー インターフェイスの一部を表し、ビューの構成に使用する修飾子を提供する型。
PreviewProvider | Apple Developer Documentation
protocol PreviewProvider : _PreviewProvider
Xcode でビュー プレビューを生成するタイプ
Text | Apple Developer Documentation
1 行以上の読み取り専用テキストを表示するビュー
@frozen struct Text
ProgressView | Apple Developer Documentation
タスクの完了に向けた進行状況を示すビュー
struct ProgressView<Label, CurrentValueLabel> where Label : View, CurrentValueLabel : View
VStack | Apple Developer Documentation
サブビューを縦一列に並べたビュー
@frozen struct VStack<Content> where Content : View
HStack | Apple Developer Documentation
サブビューを水平に並べたビュー
@frozen struct HStack<Content> where Content : View
Label | Apple Developer Documentation
タイトル付きのアイコンで構成される、ユーザー インターフェイス アイテムの標準ラベル。
struct Label<Title, Icon> where Title : View, Icon : View
SF Symbols - Apple Developer をアイコンとして使用できる
Spacer | Apple Developer Documentation
含まれているスタック レイアウトの長軸に沿って、またはスタックに含まれていない場合は両方の軸に沿って拡張する柔軟なスペース。
@frozen struct Spacer
Circle | Apple Developer Documentation
それを含むビューのフレームを中心とする円
@frozen struct Circle
Button | Apple Developer Documentation
アクションを開始するコントロール。
struct Button<Label> where Label : View
actionにボタンクリック時のイベントを登録する
Image | Apple Developer Documentation
A view that displays an image.
@frozen struct Image
Creating a card view — iOS App Dev Tutorials | Apple Developer Documentation
import Foundation
と import SwiftUI
だと何が変わるのだろう?
SwiftUI
で Foundation
が使用されているので,通常は明示的に Foundation
を import する必要はない.
SwiftUI
を使用しない(今回のチュートリアルでは構造体を定義するだけの)ファイルでは,Foundation
を import する.
別のファイルで定義された構造体 (DailyScrum) を使用する際に,特に何もせずにいきなり使用できる?
Color | Apple Developer Documentation
特定のコンテキストに適応する色の表現
@frozen struct Color
LabelStyle | Apple Developer Documentation
ビュー内のすべてのラベルにカスタムの外観を適用するタイプ。
protocol LabelStyle
Displaying data in a list — iOS App Dev Tutorials | Apple Developer Documentation

音楽プレーヤー
Media Player | Apple Developer Documentation
Media Player Framework
アプリ内から曲、オーディオ ポッドキャスト、オーディオ ブックなどを検索して再生
MusicKit (Apple Music と連携したりできる) の一部
MPMusicPlayerControllerなるものがあるらしい
MPMusicPlayerController | Apple Developer Documentation
デバイスの音楽アプリ ライブラリからオーディオ メディア アイテムを再生するために使用されるオブジェクト。
class MPMusicPlayerController : NSObject
Playing Audio Using the Built-In Music Player | Apple Developer Documentation
音楽プレーヤーに関する記事
これを見ると,songs()
で曲の情報を取得している
// Get the music player.
let musicPlayer = MPMusicPlayerApplicationController.applicationQueuePlayer
// Add a playback queue containing all songs on the device.
musicPlayer.setQueue(with: .songs())
songs() | Apple Developer Documentation
class func songs() -> MPMediaQuery
音楽アイテムに一致し、コレクションを曲名でグループ化およびソートするメディア クエリを作成します。
MPMediaQuery
を返すらしい
MPMediaQuery | Apple Developer Documentation
フィルターとグループ化タイプを使用して、デバイスのメディア ライブラリから一連のメディア アイテムを指定するクエリ。
class MPMediaQuery : NSObject
items | Apple Developer Documentation
メディア クエリの述語に一致するメディア アイテムの配列。
var items: [MPMediaItem]? { get }
MPMediaQuery
のitems
で[MPMediaItem]
が取得できる

他の音楽再生フレームワークを調べてみる
ドキュメンテーションのフィルターにmusicを入れてみる
Technologies | Apple Developer Documentation
- AVFAudio フレームワークの
- AVAudioPlayer と
- AVAudioEngine が使えるらしい

AVFAudio | Apple Developer Documentation
AVFAudio Framework
音楽再生フレームワーク
オーディオの再生、録音、および処理。アプリのシステム オーディオ動作を構成
AVAudioPlayer | Apple Developer Documentation
class AVAudioPlayer : NSObject
ファイルまたはバッファからオーディオ データを再生するオブジェクト
- ファイルまたはバッファからオーディオ データを再生,一時停止,停止
- ボリューム、パン、レート、ループ動作を制御
- タイムラインの指定されたポイントからオーディオを非同期的に再生
AVAudioPlayer
で複数ファイルを再生する際は毎回init()
を呼び出す必要がある?
オーディオを再生するためのアプリの準備の詳細については、 iOS および tvOS アプリのオーディオ再生の構成を参照してください
ストリーミングや位置オーディオの再生など、より高度な再生機能については、代わりにAVAudioEngineを使用してください。
AVAudioPlayer
を使っている記事
init(contentsOf:) | Apple Developer Documentation
ファイルからオーディオを再生するプレーヤーを作成します
init(contentsOf url: URL) throws
AVAudioPlayer
はURL
を受け取ることができる.

AVAudioEngine | Apple Developer Documentation
class AVAudioEngine : NSObject
オーディオ ノードのグラフを管理し、再生を制御し、リアルタイム レンダリングの制約を構成するオブジェクト
AVAudioEngine
は,AVAudioNode
を組み合わせて音楽を再生する.再生ノードと出力ノードの間に,ミキサーノードを接続したりできるらしい.
AVAudioEngine
を使用した記事
曲の再生は,AVAudioPlayerNodeが担う
AVAudioPlayerNode
はscheduleFile()
でAVAudioFile
を受け取る
AVAudioFile
はURL
を受け取る
MPMediaItem
のassetURL
でURL
を取得
こちらの記事の次/前の曲に移動する にて,
AVAudioEngineには曲のキューを保持する機能がありません。
なのでアプリケーションコードとして再生リストを保持しておく必要があります。
AVAudioPlayerNode | Apple Developer Documentation
オーディオ ファイルのバッファまたはセグメントの再生をスケジュールするためのオブジェクト。
class AVAudioPlayerNode : AVAudioNode
AVAudioEngineで再生するノード
AVAudioPlayerNode
はAVAudioFile
か,AVAudioPCMBuffer
を受け取ることができる.
- scheduleFile(_:at:completionHandler:) | Apple Developer Documentation
- scheduleBuffer(_:completionHandler:) | Apple Developer Documentation
AVAudioFile | Apple Developer Documentation
システムが読み取りまたは書き込み用に開くことができるオーディオ ファイルを表すオブジェクト。
class AVAudioFile : NSObject
URL
を受け取る
init(forReading fileURL: URL) throws
readでファイルからバッファ (AVAudioFile
-> AVAudioPCMBuffer
)
writeでバッファからファイル (AVAudioPCMBuffer
-> AVAudioFile
)
func read(into buffer: AVAudioPCMBuffer) throws
func write(from buffer: AVAudioPCMBuffer) throws
AVAudioPCMBuffer | Apple Developer Documentation
PCM オーディオ形式で使用するオーディオ バッファーを表すオブジェクト。
class AVAudioPCMBuffer : AVAudioBuffer
PCMとは,Pulse Code Modulation(パルス符号変調)のこと
https://ja.wikipedia.org/wiki/パルス符号変調
MPMediaItem | Apple Developer Documentation
メディア ライブラリに含まれる 1 つのアイテムを表すプロパティのコレクション。
class MPMediaItem : MPMediaEntity
メディア(曲)の情報が入っている
assetURL | Apple Developer Documentation
メディア アイテムを指す URL。
var assetURL: URL? { get }

ファイルの読み書き
DocumentsフォルダのURLを取得するコード
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
FileManager | Apple Developer Documentation
class FileManager : NSObject
ファイル システムのコンテンツへの便利なインターフェイスであり、それと対話する主要な手段です。
default | Apple Developer Documentation
プロセスの共有ファイル マネージャー オブジェクト。
class var `default`: FileManager { get }
urls(for:in:) | Apple Developer Documentation
要求されたドメイン内の指定された共通ディレクトリの URL の配列を返します。
func urls(
for directory: FileManager.SearchPathDirectory,
in domainMask: FileManager.SearchPathDomainMask
) -> [URL]
FileManager.SearchPathDirectory.documentDirectory | Apple Developer Documentation
ドキュメント ディレクトリ。
case documentDirectory = 9
userDomainMask | Apple Developer Documentation
ユーザーのホーム ディレクトリ — ユーザーの個人的なアイテム (~) をインストールする場所。
static var userDomainMask: FileManager.SearchPathDomainMask { get }
URL | Apple Developer Documentation
リモート サーバー上のアイテムやローカル ファイルへのパスなど、リソースの場所を識別する値。
struct URL

Configuring the Audio Playback of iOS and tvOS Apps | Apple Developer Documentation
音楽再生に関する記事
バックグラウンド再生のこととか書かれてある
iOS および tvOS アプリのオーディオ再生の設定

mp3ファイルのメタデータ



ボタンを配置する
func play() {
}
struct ContentView: View {
var body: some View {
Button(action: play) {
Text("Play")
}.padding()
}
}

アイコンボタンを配置する
Button(action: {}, label: {Image(systemName: "play")}).padding()
アイコンはSF Symbolsから指定する.

アイコンボタンを変更する
@State var isPlay = false
var body: some View {
Button(action: {
isPlay = !isPlay
}, label: {
Image(systemName: self.isPlay ? "pause" : "play")
}).padding()

再生はする...けれどあまり良くない例?
2023-01-03 23:41:05.623814+0900 MusicPlayer[22403:1091876] [plugin] AddInstanceForFactory: No factory registered for id <CFUUID 0x600003231ba0> F8BB1C28-BAE8-11D6-9C31-00039315CD46
import AVFoundation
struct ContentView: View {
@State var isPlay = false
@State var audioPlayer: AVAudioPlayer!
var body: some View {
Button(action: {
isPlay = !isPlay
if isPlay {
self.audioPlayer.play()
} else {
self.audioPlayer.pause()
}
}, label: {
Image(systemName: self.isPlay ? "pause" : "play")
}).onAppear(perform: {
guard let soundURL = Bundle.main.url(forResource: "sample", withExtension: "mp3") else {
print("Not Found")
return
}
self.audioPlayer = try! AVAudioPlayer(contentsOf: soundURL)
}).padding()
}
}
SwiftUIは struct を使うので AVAudioPlayerDelegate に準拠することができません。

これらを参考にして,MusicPlayerクラスを作成
import Foundation
import AVFoundation
class MusicPlayer: NSObject, ObservableObject, AVAudioPlayerDelegate {
var audioPlayer: AVAudioPlayer?
func setUrl(url: URL) {
audioPlayer = try! AVAudioPlayer(contentsOf: url)
audioPlayer?.delegate = self
}
func play() {
audioPlayer?.play()
}
func pause() {
audioPlayer?.pause()
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("Did finish Playing")
}
}
struct ContentView: View {
@State var isPlay = false
@ObservedObject var musicPlayer = MusicPlayer()
var body: some View {
Button(action: {
isPlay = !isPlay
if isPlay {
musicPlayer.play()
} else {
musicPlayer.pause()
}
}, label: {
Image(systemName: isPlay ? "pause" : "play")
}).onAppear(perform: {
guard let soundURL = Bundle.main.url(forResource: "sample", withExtension: "mp3") else {
print("Not Found")
return
}
musicPlayer.setUrl(url: soundURL)
}).padding()
}
}
次は,
- 再生時間の表示
- 次の曲の再生
などを行いたい