Swiftでカメラロールから写真データを保存する話
おはようございます。あおかび (ん)です。
この間やっとアプリケーション作りがひと段落したので、
その間に学んだことをずらずらっと書いていこうと思っております。
今回はSwiftを使ってカメラロールから写真データを引っ張ってくる方法を書いていきたいと思います。
ボタンを一つ置いて、そのボタンがクリックされたらカメラロールにアクセス、
その画像をローカルデータとして保存しておくところまでやっておきたいと思います。
DBの部分は今回は割愛します。
1.ボタンを配置して、カメラロールにアクセス
ViewController.swiftにまず、AssetsLibraryをimportした後、
UIViewControllerに加えてUIImagePickerControllerDelegateとUINavigationControllerDelegateを継承(?)しましょう。
/* ViewController.swift */ import UIKit import AssetsLibrary class testViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
つづいてviewDidLoadメソッドにてボタンを配置、アクションは今回はaccessCamerarollとしました。
override func viewDidLoad() { self.view.backgroundColor = UIColor.whiteColor() super.viewDidLoad() let button: UIButton = UIButton() button.frame = CGRectMake(100, 100, 100, 100) button.setTitle("Access!", forState: UIControlState.Normal) button.backgroundColor = UIColor.blueColor() button.addTarget(self, action: Selector("accessCameraroll:"), forControlEvents: UIControlEvents.TouchUpInside) self.view.addSubview(button) }
そのaccessCamerarollメソッドは次のようになっています。
// カメラロールから写真を選ぶためのメソッド func accessCameraroll(button: UIButton) { if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) { let controller = UIImagePickerController() controller.delegate = self controller.sourceType = UIImagePickerControllerSourceType.PhotoLibrary self.presentViewController(controller, animated: true, completion: nil) } }
ここまででとりあえずカメラロールにアクセスすることはできました!
次はカメラロールから選択した写真を保存しましょう。
2.選択した写真をローカルストレージに保存
写真を選択した時に呼ばれるメソッドに
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) { }
というメソッドがあります。この関数内で、選択した画像を保存していきましょう。
// 写真を選択した時に呼ばれるメソッド func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) { if info[UIImagePickerControllerOriginalImage] != nil { let image: UIImage? = info[UIImagePickerControllerOriginalImage] as! UIImage? let pictURL: NSURL = info[UIImagePickerControllerReferenceURL] as! NSURL var library: ALAssetsLibrary = ALAssetsLibrary() var data: NSData? let sema: dispatch_semaphore_t = dispatch_semaphore_create(0) let queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) var getImage: UIImage? dispatch_async(queue, {() -> Void in library.assetForURL(pictURL, resultBlock: {(asset: ALAsset!) -> Void in let representation: ALAssetRepresentation? = asset.defaultRepresentation() getImage = UIImage(CGImage: representation!.fullResolutionImage().takeUnretainedValue())! data = UIImagePNGRepresentation(getImage!) dispatch_semaphore_signal(sema) }, failureBlock: {(error: NSError!) -> Void in println(error) dispatch_semaphore_signal(sema); }) }) dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); saveImage(data!) } picker.dismissViewControllerAnimated(true, completion: nil) let mainViewController: MainViewController = MainViewController() self.navigationController?.pushViewController(mainViewController, animated: true) } // 画像をローカルストレージに保存するメソッド func saveImage(data: NSData) { let dataPath = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as! Array<String>).first!.stringByAppendingPathComponent("test.jpg") var fileManager: NSFileManager = NSFileManager() data.writeToFile(dataPath, atomically: true) }
これで画像が保存されたはずです。
最初はAVFoundationとか使ってカメラにアクセスしたりしてたんですが、なんかうまくいかなかったですね...
コーディング能力、プログラミング能力の両方がこのままではやばい気がするよなー
勉強頑張っていきます。ありがとうございました、かびでした。。。
P.S.
コードの全容
import UIKit import AssetsLibrary class testViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { override func viewDidLoad() { self.view.backgroundColor = UIColor.whiteColor() super.viewDidLoad() let button: UIButton = UIButton() button.frame = CGRectMake(100, 100, 100, 100) button.setTitle("Access!", forState: UIControlState.Normal) button.backgroundColor = UIColor.blueColor() button.addTarget(self, action: Selector("accessCameraroll:"), forControlEvents: UIControlEvents.TouchUpInside) self.view.addSubview(button) } // カメラロールから写真を選ぶためのメソッド func accessCameraroll(button: UIButton) { if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) { let controller = UIImagePickerController() controller.delegate = self controller.sourceType = UIImagePickerControllerSourceType.PhotoLibrary self.presentViewController(controller, animated: true, completion: nil) } } // 写真を選択した時に呼ばれるメソッド func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) { if info[UIImagePickerControllerOriginalImage] != nil { let image: UIImage? = info[UIImagePickerControllerOriginalImage] as! UIImage? let pictURL: NSURL = info[UIImagePickerControllerReferenceURL] as! NSURL var library: ALAssetsLibrary = ALAssetsLibrary() var data: NSData? let sema: dispatch_semaphore_t = dispatch_semaphore_create(0) let queue: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) var getImage: UIImage? dispatch_async(queue, {() -> Void in library.assetForURL(pictURL, resultBlock: {(asset: ALAsset!) -> Void in let representation: ALAssetRepresentation? = asset.defaultRepresentation() getImage = UIImage(CGImage: representation!.fullResolutionImage().takeUnretainedValue())! data = UIImagePNGRepresentation(getImage!) dispatch_semaphore_signal(sema) }, failureBlock: {(error: NSError!) -> Void in println(error) dispatch_semaphore_signal(sema); }) }) dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); saveImage(data!) } picker.dismissViewControllerAnimated(true, completion: nil) let mainViewController: MainViewController = MainViewController() self.navigationController?.pushViewController(mainViewController, animated: true) } // 画像をローカルストレージに保存するメソッド func saveImage(data: NSData) { let dataPath = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as! Array<String>).first!.stringByAppendingPathComponent("test.jpg") var fileManager: NSFileManager = NSFileManager() data.writeToFile(dataPath, atomically: true) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } }
Swiftで NavigationBarを出したり引っ込めたりする話
こんばんは、かびさん@あおかびんです。
21日間ブログを書くというチャレンジに失敗しまくっている次第ですが
また気をとりなおしていきたいと思います。
さて、NavigationBarで前の画面に戻れる機能は便利なのですが
場合によっては表示させたくないということがあるかと思います。
そこで出したり引っ込めたりする方法を書いていきたいと思います。
流れは
- 画面遷移はNavigationControllerに任せる
- 画面を描画する前にNavigationBarの設定をする
こんな感じになるかと思います。
実際に書いてみましょう。
1.AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { // 最初に表示する画面を指定する let firstView: MainViewController = MainViewController() // NavigationControllerを設定する let myNavigationController: UINavigationController = UINavigationController(rootViewController: firstView) // おまじない self.window = UIWindow(frame: UIScreen.mainScreen().bounds) self.window?.rootViewController = myNavigationController self.window?.makeKeyAndVisible() return true } ・・・ }
最初に表示する画面からNavigationControllerを設定する感じですね。
次はMainViewControllerを設定します。
2. MainViewController.swift (NavigationBarを表示しない)
class MainViewController: UIViewController { … // ボタンが押された時の処理 func touchButton(sender: UIButton){ let subViewController: SubViewController = SubViewController() self.navigationController?.pushViewController(subViewController, animated: true) } // 画面をロードする前に呼ばれるメソッド override func viewWillAppear(animated: Bool) { // NavigationBarを隠す処理 self.navigationController?.setNavigationBarHidden(true, animated: true) } … }
これによって画面をロードする時にNavigationBarを表示しない設定をします。
次は、このボタンを押したあとでSubViewControllerの方ではNavigationBarを表示しましょう。
3. SubViewController.swift (NavigationBarを表示する)
class SubViewController: UIViewController { ・・・ override func viewWillAppear(animated: Bool) { self.navigationController?.setNavigationBarHidden(false, animated: true) } ・・・ }
これを追加することによって、<BackのついたNavigationBarを表示できると思います。
こんな感じですかね。
ブログを更新するのを忘れちゃうのは嫌だよな。。。
やっぱ通知つけようかな。。。
以上、あおかびんでした。
SwiftのUIViewController間でデータを受け渡す話
おはようございます、かびさん@あおかびんです。
iPhoneアプリをSwiftを使って開発しているのですが
UIViewController間でデータを渡したいときに
AppDelegate.swiftに変数を追加すると渡せるということだったので
その方法を記述したいと思います。
1.AppDelegate.swift
AppDelegate.swiftファイルの中に、値を保持する領域を宣言します。
具体的には、
class AppDelegate: UIResponder, UIApplicationDelegate { var message: String? ・・・ }
こんな感じですかね。
2.SendViewController.swif (受け渡しView)
値に書き込むためにはAppDelegateクラスの変数を用意して、
その変数のクラス変数(?)を経由して書き込む形になります。
class SendViewController: UIViewController { var delegate:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate ・・・ // ボタンを押したときの処理 func touchButton(sender: UIButton){ // AppDelegateのmessageに押されたボタンのtagを代入 self.delegate.message = String(sender.tag) // NavigationControllerを使ったページの遷移 let receiveViewController: ReceiveViewController = ReceiveViewController() self.navigationController?.pushViewController(receiveViewController, animated: true) } }
こんな感じで記述しました。
(今回NavigationControllerを使っているので、ちょっとややこしいかもしれない)
3.ReceiveViewController.swift (値の受け取りView)
class ReceiveViewController: UIViewController { var delegate:AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate override func viewDidLoad() { super.viewDidLoad() println(self.delegate.message) } ・・・ }
2と同じように呼び出しを行って、値を吐き出しています。
多分うまくいくんじゃないかな
ダメだったら連絡ください、修正します。。。
これを知らなかったからViewのinitをoverrideしようと苦戦してた。。。
スキル無さすぎダメダメのダメ。
すみません、以上あおかびんでした。
学校の課題を解くためにHaskellを使った話
こんにちは、かびさん@あおかびんです。
学校の課題で、ちょっとした計算問題を解くときに
普通に解くのが面倒くさいなーと思って
前まではPythonの対話を使って計算をしていたのですが、
この間確率統計のときに
先生「100万の中から1万個取り出す組み合わせはやろうと思ってもできない」
という発言があり(実際にはマクローリン展開かなんか使えばできるみたいな解説のため)
「できそう」と思ってしまったが故にPythonで書こうとしたら案の定計算できない。
また、3の20乗を計算する問題が出て、
計算するのにわざわざコード書くのも面倒だなと。
そこでHaskellを導入してやりました。その手順を書きます。
1. Haskell PlatformのDLとインストール
こちら、Haskell Platformの公式DLサイトよりHaskell PlatformをDLします。
ちなみに、brewを使わないのは
Haskell関係のパッケージ(?)をインストールするcabalが
brewだとうまく動いてくれないので、こちらのHaskell Platformを使います。
あとはDLしたpkgを開いてインストールしてください。
2.ターミナルでhaskellの対話シェルを起動する。
インストールが終わったら対話形式でhaskellを実行してみましょう。
コマンドラインで
ghci
と入力すると、最初の激重initの後haskellのインタラクティブシェルが起動します。
閉じるときは
:q
コマンドを入力すれば大丈夫。
(発展)3.100万から1万個を取り出す組み合わせ問題を解かせる。
適当なエディタを使って、test.hsに次のソースコードを書き込んで保存しましょう。
手元にファイルがなかったので、後で追記します。
(発展)4.分数の累乗とかを求めてみる。
haskell先輩は分数も扱うことができます。ありがたいですね!
ghciを起動したら、次のコードを入力してください。
import Data.Ratio
すると、%区切りで分数を扱うことができます。
1 % 3 * 1 % 4 -- 3分の1 × 4分の1 1 % 12 -- 12分の1
また、このまま累乗も計算できる。
((1 % 3) * (1 % 4)) ^ 20 -- (3分の1 × 4分の1)の20乗 1 % 3833759992447475122176 -- おおきなかず分の1
簡単な数式を入れるときはhaskellを使うようになりました。
すごく便利なghciでしたね。
以上、あおかびんでした。
SwiftのUIButtonで画面遷移をする話
こんばんは、かびんさん@あおかびんです。
今日はSwiftのUIButtonで画面遷移を行ったので
それをメモ書きします。
override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = backgroundColor for i in 0...2 { let task: UIButton = UIButton() let icast:CGFloat = CGFloat(i - 1) let action: Selector = Selector("touchButton" + String(i) + ":") task.backgroundColor = UIColor.whiteColor() task.layer.masksToBounds = true task.setTitle("task" + String(i), forState: UIControlState.Normal) task.setTitleColor(UIColor.blackColor(), forState: .Normal) task.addTarget(self, action: action, forControlEvents: .TouchUpInside) task.layer.masksToBounds = true task.frame = CGRectMake(width / 2 - fieldWidth / 2, height / 2 - fieldHeight + (40.0 * icast), fieldWidth, fieldHeight) self.view.addSubview(task) } } internal func touchButton0(sender: UIButton){ // 遷移するViewを定義する. let editViewController: TaskEditViewController = TaskEditViewController(i: 0) editViewController.modalTransitionStyle = UIModalTransitionStyle.CoverVertical self.presentViewController(editViewController, animated: true, completion: nil) }
タッチイベントを取得したらその名前のセレクタが実行されるという形式。
UITextfieldのデザインを調整したいんだよな・・・。
以上あおかびんでした。
Slackにてhubotで会話監視を導入した話
こんにちは、かびさん@あおかびんです。
今回はSlackすごく便利ですよね、よく使っています。
Slackのgeneralチャンネルを全体報告の連絡のみに絞るため
@channelが付いていない発言には小言を言うbotを作りました。
ソースコードはこんな感じ。
attention.coffee
module.exports = (robot) -> robot.hear /(.*)/i, (msg) -> if ///^@channel: ///i.test(msg.match[1]) return else msg.send "<君ぃ・・・連絡事項は文頭に@channel: をつけないとダメじゃないか。それ以外の話は #random でやりたまえ。"
ちょっとウザみのあるbotに仕上げました。
ただ、先頭からしか@channelを検知しないのと、
ファイルのアップロードとかには対応できていないのが現状です。
誰かいい方法を教えてください。
以上、あおかびんでした。