- 投稿日:2019-07-30T23:59:28+09:00
Create MLとVisionで画像認識
できたもの
上記gif動画のように移したカードが何かを判定する簡単なアプリを作成しました。.mlmodelファイルの作成
Create MLから.mlmodelファイルを作成します。
Xcodeのplaygroundから作成できます。次期バージョンからは独立したアプリになるみたいですがXcode10.3環境ではplaygroundから使用します。playgroundをmacOSで開いたら
import CreateMLUI let builder = MLImageClassifierBuilder() builder.showInLiveView()上記画像のようになると思います。
Drop Images
というところに画像ファイル(ディレクトリ)をドロップします。
パラメータも選択できますが、今回のアプリレベルなら調整は必要ありませんでした。精度に関してはこのあたりに書いてあります。
ドロップするとトレーニングが始まって完了するとmlmodelファイルがダウンロード可能です。
アップロードしたディレクトリは以下のようになっています。
各ディレクトリには10枚程度画像が入っています。ドキュメントには最低10枚とあったのでまずは最低枚数を試しました(結果それでうまくいきました)。iOS
コードはiOS11のVision.frameworkを使ってみるを参考にさせていただきました。
ViewController.swiftimport UIKit import AVFoundation import Vision class ViewController: UIViewController { @IBOutlet fileprivate weak var textView: UITextView! override func viewDidLoad() { super.viewDidLoad() // カメラキャプチャの開始 startCapture() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } // カメラキャプチャの開始 private func startCapture() { let captureSession = AVCaptureSession() captureSession.sessionPreset = .photo // 入力の指定 guard let captureDevice = AVCaptureDevice.default(for: .video), let input = try? AVCaptureDeviceInput(device: captureDevice), captureSession.canAddInput(input) else { assertionFailure("Error: 入力デバイスを追加できませんでした") return } captureSession.addInput(input) // 出力の指定 let output = AVCaptureVideoDataOutput() output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "VideoQueue")) guard captureSession.canAddOutput(output) else { assertionFailure("Error: 出力デバイスを追加できませんでした") return } captureSession.addOutput(output) // プレビューの指定 let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) previewLayer.videoGravity = .resizeAspectFill previewLayer.frame = view.bounds view.layer.insertSublayer(previewLayer, at: 0) // キャプチャ開始 captureSession.startRunning() } } extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate { func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { // CMSampleBufferをCVPixelBufferに変換 guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { assertionFailure("Error: バッファの変換に失敗しました") return } // CoreMLのモデルクラスの初期化 guard let model = try? VNCoreMLModel(for: ImageClassifier().model) else { assertionFailure("Error: CoreMLモデルの初期化に失敗しました") return } // 画像認識リクエストを作成(引数はモデルとハンドラ) let request = VNCoreMLRequest(model: model) { [weak self] (request: VNRequest, error: Error?) in guard let results = request.results as? [VNClassificationObservation] else { return } // 判別結果とその確信度を上位3件まで表示 // identifierは類義語がカンマ区切りで複数書かれていることがあるので、最初の単語のみ取得する let displayText = results.prefix(3).compactMap { "\(Int($0.confidence * 100))% \($0.identifier.components(separatedBy: ", ")[0])" }.joined(separator: "\n") DispatchQueue.main.async { self?.textView.text = displayText } } // CVPixelBufferに対し、画像認識リクエストを実行 try? VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:]).perform([request]) } }プロジェクトに先程の.mlmodelファイルを加えたら完了です。
困った点
最初は読み込むカードのみの画像を入れたところ、カードが写ってなくてもどちらかに判定、それもどちらかに固定で判定されてしまう状態でした。さらにもう一方のカードを移してもあまりconfidenceが上がらない状態で困っていました。
カードが写っているかどうかも判定したかったため背景のみの写真も撮影してothers
としてアップロードしたところ精度が非常に上がりました。
今回は同じ部屋でしか試していないのですが、屋外などでは今回のままではうまく行かないかもしれません。
枚数やオプションを増やした場合、一気に学習時間が伸びたのでそのへんがやはり問題になってくるのだなと感じました。
- 投稿日:2019-07-30T18:38:10+09:00
[Swift]UIViewにaddGestureRecognizerしようとしてつまずいた話
問題
UIViewにUITapGestureRecognizerをaddGestureRecognizerしようとしてもできなかった
前提
・isUserInteractionEnabled = true
・UIViewもnilではなかった解決方法
addGestureRecognizer(.init(target: self, action: #selector(tapped)))initを直したら動きました
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapped)))最後に
今思うとaddGestureRecognizerなので、.initで書いたらサブクラスのUITapGestureRecognizerではなく,スーパークラスのUIGestureRecognizerが呼ばれるので、それはそうですよねというお話(引数が同じなのですっかりハマってしまいました。??
- 投稿日:2019-07-30T18:13:36+09:00
SwiftでMapタイプの切り替え方
何をやるのか?
簡易的なMapアプリのオプション機能として、mapタイプの切り替えを行う。
前提
MapKitにてMapが設置されていることを前提とする。
Mapの種類
画面 定義 内容 .mutedStandard 交通機関 .standard 標準の地図 .satellite 航空写真 .hybrid 航空写真
+
ラベル.satelliteFlyover 3D Flyover .hybridFlyover 3D Flyover
+
ラベル実装コード
@IBAction func changeMapButton(_ sender: UIButton) { if Map.mapType == .standard { Map.mapType = .satellite } else if Map.mapType == .satellite{ Map.mapType = .hybrid } else if Map.mapType == .hybrid{ Map.mapType = .satelliteFlyover } else if Map.mapType == .satelliteFlyover{ Map.mapType = .hybridFlyover } else if Map.mapType == .hybridFlyover{ Map.mapType = .mutedStandard } else { Map.mapType = .standard } }if文を使い現在のmapTypeと各mapTypeを順番に比較し、もし同じTypeだった場合次のTypeを代入するという簡単なコードになっています。
x-codeのフレームワークのButtonをStoryboardに貼り、それに対応する関数内に記述すれば問題ありません。最後に
非常に簡単な実装ですが、割と本格的なアプリのように仕上がるので、初学者の方やプログラミングやった事ないけど興味ある人も是非一度実装して、開発の楽しさを体験してみましょう。
- 投稿日:2019-07-30T15:26:06+09:00
UIAlertControllerにUIProgressViewを追加してKVO監視更新
データ変換をするクラスを作って、処理中にその中で変更される進捗度合いを、KVOで UIAlertController上のUIProgressViewに反映させます。
最初、進捗に応じた UIProgressView の表示更新ができなかったんですが、以下のように
表示側にはDispatchQueue.main.async(flags: .barrier) {}
、
処理側には、DispatchQueue.global(qos: .background).async {}
を入れることで解決できました。// progressView と _observer はメンバ変数 let progressAlert = UIAlertController(title: "Please wait", message: "Converting from old to new", preferredStyle: .alert) self.progressView.progress = 0.0 progressAlert.view.addSubview(self.progressView) // UIAlertControllerの高さ変更とUIProgressViewの配置 let height:NSLayoutConstraint = NSLayoutConstraint(item: progressAlert.view!, attribute: NSLayoutConstraint.Attribute.height, relatedBy: NSLayoutConstraint.Relation.equal, toItem: nil, attribute: NSLayoutConstraint.Attribute.notAnAttribute, multiplier: 1, constant: 100) progressAlert.view.addConstraint(height) self.progressView.translatesAutoresizingMaskIntoConstraints = false self.progressView.leadingAnchor.constraint(equalTo: progressAlert.view.leadingAnchor, constant: 10.0).isActive = true self.progressView.trailingAnchor.constraint(equalTo: progressAlert.view.trailingAnchor, constant: -10.0).isActive = true self.progressView.topAnchor.constraint(equalTo: progressAlert.view.topAnchor, constant: 65.0).isActive = true self.progressView.heightAnchor.constraint(equalToConstant: 2.0) // present と observe 設定と終了処理 present(progressAlert, animated: true, completion: { let dataMigration = DataMigration() self._observer = dataMigration.observe(\.dataProgress, options: .new) { object, change in DispatchQueue.main.async(flags: .barrier) { self.progressView.setProgress(object.dataProgress, animated: true) } } dataMigration.convert(<何かオプション>, completionHandler: {(sucess)->Void in self._observer = nil if sucess { print("Convert Complete") } else { print("Error") } progressAlert.dismiss(animated: true, completion: { ... 終了時の処理 ... }) }) })observeをするためには、DataMigrationは NSObjectのサブクラスでなければなりません。
class DataMigration: NSObject { @objc dynamic var dataProgress: Float = 0.0 func convert(options: [Any], compleationHandler:@escaping ((_ success: Bool) -> Void) ) { var numberOfData: Float = ...データの個数... var countData: Float = 0.0 DispatchQueue.global(qos: .background).async { for ...numberOfData分の繰り返し... { ...何か処理... countData += 1 self.dataProgress = countData / numberOfData } completionHandler(true) } } }参考にしたのは下記です。
StackOverflow: Add Progress bar to UIAlertController with showing update
- 投稿日:2019-07-30T14:40:46+09:00
CoreData: warning: Multiple NSEntityDescriptions claim および CoreData: error: +[XXXX entity] Failed to find a unique match for an NSEntityDescription
CoreDataで、デフォルトのオートマイグレーションを使うのではなく、自前で2つの
NSPersistentContainer
でloadPersistentStores()
して、一方から読み込み、もう一方に書き込むということをしました。このとき書き込み側で、
CoreData: warning: Multiple NSEntityDescriptions claim ....
あるいは
CoreData: error: +[XXXX entity] Failed to find a unique match for an NSEntityDescription ...
のような警告もしくはエラーが発生しました。やっていたこと。
let object = Xxxx(context: moc) ...attrbuteに値を代入... do { try moc.save() } catch { print("Failed to save new note") }これを下記のようにすることで回避できました。
let discription = NSEntityDescription.entity(forEntityName: "Xxxx", in: moc)! let object = Xxxx(entity: discription, insertInto: moc) moc.insert(object) ...attrbuteに値を代入... do { try moc.save() } catch { print("Failed to save new note") }
moc
はNSPersistentContainer
のviewContext: NSManagedObjectContext
です。参考記事は以下です。
stackoverflow: Multiple NSEntityDescriptions Claim NSManagedObject Subclass
- 投稿日:2019-07-30T13:00:17+09:00
UIDynamicsで物理演算を使った自然なアニメーション
UIKit Dynamics
Viewに物理演算を用いたアニメーションを設定できます。
ドキュメントはこちらUIDynamicAnimator
Viewに物理に基づいたアニメーションを提供する根幹となるもの
var dynamicAnimator: UIDynamicAnimator! override func viewDidLoad() { super.viewDidLoad() dynamicAnimator = UIDynamicAnimator(referenceView: self.view) } }重力を与える
storyboard上に配置した赤いViewに条件を追加します。
重力を与えるにはUIGravityBehaviorを使用します。let gravityBehavior = UIGravityBehavior(items: [redView]) dynamicAnimator.addBehavior(gravityBehavior)ここでデフォルトの重力の大きさは1.0で、大きさ1.0は1000 point/second^2の加速度を意味します。
デフォルトの重力の向きは(0.0, 1.0)です。パラメータ
パラメータとして次のようなものが設定できます。
プロパティ・メソッド名 型 説明 gravityDirection CGVector 重力ベクトル(大きさと方向) angle CGFloat 重力ベクトルの方向(ラジアン) magnitude CGFloat 重力ベクトルの大きさ setAngle(_:, magnitude:) (CGFloat, CGFloat) -> Void 重力ベクトルの方向(ラジアン)と大きさ 他にsetAngle(_ angle: CGFloat, magnitude: CGFloat)メソッドを使用しても設定できます。
例えばaddBehavior(_:)する前に以下のように設定すると、gravityBehavior.gravityDirection = CGVector(dx: 2.0, dy: 2.0) gravityBehavior.magnitude = 1.0一行目は右下に向かって重力の大きさ2.828..($2\sqrt{2} $)で動くような設定になります。
二行目でmagnitudeを1.0にすると、その方向を保ったままベクトルの大きさが1.0になるので最終的に重力ベクトルは(0.707..., 0.707...)となります。衝突境界
衝突境界を追加したい場合にはUICollisionBehaviorを使用します。
デバイスの枠を境界とする
translatesReferenceBoundsIntoBoundaryはreferenceViewを境界として扱うかどうかというBool値です。
referenceViewは最初にUIDynamicAnimatorを初期化した時に設定したViewです。
先ほどこれにself.viewを設定したので、この場合デバイスの画面の端が境界になると考えられます。let collisionBehavior = UICollisionBehavior(items: [redView]) collisionBehavior.translatesReferenceBoundsIntoBoundary = true dynamicAnimator.addBehavior(collisionBehavior)自由に境界を設定
CGPointでどこからどこまでを境界とみなすかを指定します。
第一引数で指定するIDは後でこの境界だけ削除する場合などに使います。let collisionBehavior = UICollisionBehavior(items: [redView]) collisionBehavior.addBoundary(withIdentifier: "floor" as NSCopying, from: CGPoint(x: self.view.bounds.width/2 - 20,y: self.view.bounds.height/2 + 200), to: CGPoint(x: self.view.bounds.width/2 + 20, y: self.view.bounds.height/2 + 200)) dynamicAnimator.addBehavior(collisionBehavior)この他にUIBezierPathを使用して境界を設定することもできます。
パラメータ
collisionModeで何を衝突対象とするのかを指定できる。
CollisionBehavior.Modeで指定できるのは以下。
CollisionBehavior.Mode 説明 動作 .items UICollisionBehaviorに紐付いているアイテム同士だけが衝突する .boundaries 設定した境界のみが衝突対象となり、アイテム同士は衝突しない .everything アイテム同士も境界も衝突する デフォルトは.everything。
弾性係数・抵抗・摩擦
ある物体に対する弾性係数や抵抗など初期条件になるようなものを設定するにはUIDynamicItemBehaviorを使用します。
let dynamicItemBehavior = UIDynamicItemBehavior(items: [redView]) dynamicItemBehavior.elasticity = 1.0 dynamicItemBehavior.resistance = 0 dynamicItemBehavior.friction = 0 dynamicAnimator.addBehavior(dynamicItemBehavior)パラメータ
設定できる項目には以下のようなものがあります。
プロパティ・メソッド名 型 説明 density CGFloat 相対的な質量密度(1.0の密度を持つ100 x 100ポイントのitemに、大きさ1.0の力を加えると、100 point/secondで加速する) elasticity CGFloat 弾性率の大きさ(1.0で完全弾性衝突) friction CGFloat スライドする時にかかる摩擦の大きさ(1.0で強い摩擦、それ以上の値を指定することも可) resistance CGFloat 抵抗の大きさ(CGFLOAT_MAXが最高値、1.0を設定した時は力が加えられなくなるとすぐに停止する) allowsRotation Bool 回転を許可するか(デフォルトでtrue) angularResistance CGFloat 角抵抗の大きさ isAnchored Bool アイテムの位置が固定されているか addLinearVelocity(_:, for:) (CGPoint, UIDynamicItem) -> Void 速度を与える(1秒あたりに動くpoint数を指定) addAngulerVelocity(_:, for:) (CGFloat, UIDynamicItem) -> Void 角速度を与える(1秒あたりに動くラジアンを指定) 外力
アイテムに外力を加えるにはUIPushBehaviorを使用します。
鉛直投げ上げをするとき、プログラムは以下のようになります。let pushBehavior = UIPushBehavior(items: [redView], mode: UIPushBehavior.Mode.instantaneous) pushBehavior.pushDirection = CGVector(dx: 0.0, dy: -5.0) dynamicAnimator.addBehavior(pushBehavior)ここで1.0の力とは、連続で1.0の力を与えたとき、密度値が1.0の100ポイントx 100ポイントのビューが100 point/second^2の加速度を持つような大きさをいいます。この値をUIKit Newtonと呼びます。
パラメータ
プロパティ名・メソッド名 型 説明 mode UIPushBehavior.Mode 力を加えるのが連続的(.continuous)か1度だけ(instantaneous)なのか pushDirection CGFloat 力のベクトル(大きさと方向) angle CGFloat 力のベクトルの方向(ラジアン) magnitude CGFloat 力のベクトルの大きさ setAngle(_:, magnitude:) (CGFloat, CGFloat) -> Void 力のベクトルの方向(ラジアン)と大きさ setTargetOffsetFromCenter(_:for:) (UIOffset, UIdynamicItem) -> Void 力が物体のどこにかかるか。指定しない場合は中心にかかる その他
他にもバネのような動きを実現するUISnapBehaviorや2物体の関係を扱うUIAttachimentBehavior、電場や磁場を設定できるUIFieldBehaviorがあります。
備考
先ほどの自由落下させて完全弾性衝突するプログラムのredViewの開始位置に印をつけました。
誤差があり線を超えたり、線まで届かなかったりします。
大まかな動きを再現するには良いですが、ぴったり数ポイント分の動きを実現したい場合この誤差は無視できないように思います。
- 投稿日:2019-07-30T13:00:17+09:00
UIKit Dynamicsで物理演算を使った自然なアニメーション
UIKit Dynamics
Viewに物理演算を用いたアニメーションを設定できます。
ドキュメントはこちらUIDynamicAnimator
Viewに物理に基づいたアニメーションを提供する根幹となるもの
var dynamicAnimator: UIDynamicAnimator! override func viewDidLoad() { super.viewDidLoad() dynamicAnimator = UIDynamicAnimator(referenceView: self.view) } }重力を与える
storyboard上に配置した赤いViewに条件を追加します。
重力を与えるにはUIGravityBehaviorを使用します。let gravityBehavior = UIGravityBehavior(items: [redView]) dynamicAnimator.addBehavior(gravityBehavior)ここでデフォルトの重力の大きさは1.0で、大きさ1.0は1000 point/second^2の加速度を意味します。
デフォルトの重力の向きは(0.0, 1.0)です。パラメータ
パラメータとして次のようなものが設定できます。
プロパティ・メソッド名 型 説明 gravityDirection CGVector 重力ベクトル(大きさと方向) angle CGFloat 重力ベクトルの方向(ラジアン) magnitude CGFloat 重力ベクトルの大きさ setAngle(_:, magnitude:) (CGFloat, CGFloat) -> Void 重力ベクトルの方向(ラジアン)と大きさ 他にsetAngle(_ angle: CGFloat, magnitude: CGFloat)メソッドを使用しても設定できます。
例えばaddBehavior(_:)する前に以下のように設定すると、gravityBehavior.gravityDirection = CGVector(dx: 2.0, dy: 2.0) gravityBehavior.magnitude = 1.0一行目は右下に向かって重力の大きさ2.828..($2\sqrt{2} $)で動くような設定になります。
二行目でmagnitudeを1.0にすると、その方向を保ったままベクトルの大きさが1.0になるので最終的に重力ベクトルは(0.707..., 0.707...)となります。衝突境界
衝突境界を追加したい場合にはUICollisionBehaviorを使用します。
デバイスの枠を境界とする
translatesReferenceBoundsIntoBoundaryはreferenceViewを境界として扱うかどうかというBool値です。
referenceViewは最初にUIDynamicAnimatorを初期化した時に設定したViewです。
先ほどこれにself.viewを設定したので、この場合デバイスの画面の端が境界になると考えられます。let collisionBehavior = UICollisionBehavior(items: [redView]) collisionBehavior.translatesReferenceBoundsIntoBoundary = true dynamicAnimator.addBehavior(collisionBehavior)自由に境界を設定
CGPointでどこからどこまでを境界とみなすかを指定します。
第一引数で指定するIDは後でこの境界だけ削除する場合などに使います。let collisionBehavior = UICollisionBehavior(items: [redView]) collisionBehavior.addBoundary(withIdentifier: "floor" as NSCopying, from: CGPoint(x: self.view.bounds.width/2 - 20,y: self.view.bounds.height/2 + 200), to: CGPoint(x: self.view.bounds.width/2 + 20, y: self.view.bounds.height/2 + 200)) dynamicAnimator.addBehavior(collisionBehavior)この他にUIBezierPathを使用して境界を設定することもできます。
パラメータ
collisionModeで何を衝突対象とするのかを指定できる。
CollisionBehavior.Modeで指定できるのは以下。
CollisionBehavior.Mode 説明 動作 .items UICollisionBehaviorに紐付いているアイテム同士だけが衝突する .boundaries 設定した境界のみが衝突対象となり、アイテム同士は衝突しない .everything アイテム同士も境界も衝突する デフォルトは.everything。
弾性係数・抵抗・摩擦
ある物体に対する弾性係数や抵抗など初期条件になるようなものを設定するにはUIDynamicItemBehaviorを使用します。
let dynamicItemBehavior = UIDynamicItemBehavior(items: [redView]) dynamicItemBehavior.elasticity = 1.0 dynamicItemBehavior.resistance = 0 dynamicItemBehavior.friction = 0 dynamicAnimator.addBehavior(dynamicItemBehavior)パラメータ
設定できる項目には以下のようなものがあります。
プロパティ・メソッド名 型 説明 density CGFloat 相対的な質量密度(1.0の密度を持つ100 x 100ポイントのitemに、大きさ1.0の力を加えると、100 point/secondで加速する) elasticity CGFloat 弾性率の大きさ(1.0で完全弾性衝突) friction CGFloat スライドする時にかかる摩擦の大きさ(1.0で強い摩擦、それ以上の値を指定することも可) resistance CGFloat 抵抗の大きさ(CGFLOAT_MAXが最高値、1.0を設定した時は力が加えられなくなるとすぐに停止する) allowsRotation Bool 回転を許可するか(デフォルトでtrue) angularResistance CGFloat 角抵抗の大きさ isAnchored Bool アイテムの位置が固定されているか addLinearVelocity(_:, for:) (CGPoint, UIDynamicItem) -> Void 速度を与える(1秒あたりに動くpoint数を指定) addAngulerVelocity(_:, for:) (CGFloat, UIDynamicItem) -> Void 角速度を与える(1秒あたりに動くラジアンを指定) 外力
アイテムに外力を加えるにはUIPushBehaviorを使用します。
鉛直投げ上げをするとき、プログラムは以下のようになります。let pushBehavior = UIPushBehavior(items: [redView], mode: UIPushBehavior.Mode.instantaneous) pushBehavior.pushDirection = CGVector(dx: 0.0, dy: -5.0) dynamicAnimator.addBehavior(pushBehavior)ここで1.0の力とは、連続で1.0の力を与えたとき、密度値が1.0の100ポイントx 100ポイントのビューが100 point/second^2の加速度を持つような大きさをいいます。この値をUIKit Newtonと呼びます。
パラメータ
プロパティ名・メソッド名 型 説明 mode UIPushBehavior.Mode 力を加えるのが連続的(.continuous)か1度だけ(instantaneous)なのか pushDirection CGFloat 力のベクトル(大きさと方向) angle CGFloat 力のベクトルの方向(ラジアン) magnitude CGFloat 力のベクトルの大きさ setAngle(_:, magnitude:) (CGFloat, CGFloat) -> Void 力のベクトルの方向(ラジアン)と大きさ setTargetOffsetFromCenter(_:for:) (UIOffset, UIdynamicItem) -> Void 力が物体のどこにかかるか。指定しない場合は中心にかかる その他
他にもバネのような動きを実現するUISnapBehaviorや2物体の関係を扱うUIAttachimentBehavior、電場や磁場を設定できるUIFieldBehaviorがあります。
備考
先ほどの自由落下させて完全弾性衝突するプログラムのredViewの開始位置に印をつけました。
誤差があり線を超えたり、線まで届かなかったりします。
大まかな動きを再現するには良いですが、ぴったり数ポイント分の動きを実現したい場合この誤差は無視できないように思います。
- 投稿日:2019-07-30T07:02:36+09:00
Swift Package Manager はじめの一歩
はじめに
Apple公式のパッケージマネージャーのSwift Package Manager(以下SwiftPM)を今回使用してみました。
パッケージマネージャーとはライブラリの依存関係を管理してくれるツールで、
CocoaPods
やCarthage
と同じようなものです。https://github.com/apple/swift-package-manager
はじめに
SwiftPMが動作するか確認しましょう。
XcodeをインストールされていればTerminalから下記のコマンドが実行できます。$ swift package --version Apple Swift Package Manager - Swift 5.0.0 (swiftpm-14490.62.2)また、ヘルプを確認するときは下記です。
swift package --help
プロジェクトを作成する
SwiftPMは作業ディレクトリを作成しないので、自分で作成する必要があります。
今回はHello-SwiftPM
という名前の作業ディレクトリを作成します。$ mkdir Hello-SwiftPM $ cd Hello-SwiftPM/今回はコマンドラインツールの作成方法です。
オプションに--type executable
を追加する必要があります。
これを追加するとmain.swift
も同時に作成されます。$ swift package init --type executable Creating executable package: Hello-SwiftPM Creating Package.swift Creating README.md Creating .gitignore Creating Sources/ Creating Sources/Hello-SwiftPM/main.swift Creating Tests/ Creating Tests/LinuxMain.swift Creating Tests/Hello-SwiftPMTests/ Creating Tests/Hello-SwiftPMTests/Hello_SwiftPMTests.swift Creating Tests/Hello-SwiftPMTests/XCTestManifests.swiftオプションはそのほかに
entity
library
system-module
があります
ビルド
$ swift package build
Xcodeプロジェクト作成
$ swift package generate-xcodeproj
リリースビルド
$ swift build -c release