読者です 読者をやめる 読者になる 読者になる

ぬけてるエンジニアの備忘録

イケてない情報の掃き溜め。。。

【Swift】Springで簡単アニメーション

Swift

github.com

GitHubのトレンドリポジトリで見つけたSpringというアニメーションライブラリが凄まじく良かったので紹介してみる。
★もかなりついててすでに有名で今更な感じかもしれませんが参考になる人がいれば。

環境 Xcode 7.0.1 Swift

まずはcocoapods

と思いましたが、公式にはcocoapodは未対応のようでした。

今回は手動でプロジェクトに

GitHubソースコードをダウンロードしましょう。 その中のSpringフォルダを自身のプロジェクトに追加してください。

f:id:Yuchang:20151006175326p:plain

storyboardでアニメーションをつける。

f:id:Yuchang:20151006183227p:plain UIButtonだとCustomClassにSpringButtonと指定する。
UILabelだとSpringLabel UIImageViewだとSpringImageViewといった感じ。



f:id:Yuchang:20151006164430p:plain 続いてこんな感じでアニメーションを指定する。今回はshakeを指定した。

Runしてみるとたったこれだけでアニメーションが実装できたと思います。

コードからもアニメーションを指定できる

import UIKit

class ViewController: UIViewController {

    @IBOutlet var button: SpringButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button.animation = "pop"
        button.curve = "easeIn"
        button.duration = 1.0
        button.animate()
    }
}

【Swift】Parseを使ってデータ取得してみた

Swift Parse

parse.com
Parseを使ってサーバーからデータ取得、表示するまでをやってみた。

環境 Xcode7.0 Swift

今回の手順として

  • ParseSDKをプロジェクトに導入
  • Parseサイトの登録・初期設定まで済ましておく
  • Parseサイトで設定したApplication IDと、Client Keyをアプリに設定
  • storyboardでTableView等を設置した画面を作成
  • データを取得してViewに表示する

ざっくり言うとこんな感じ。

まずはcocoapodsでParseSDKを導入する


Podfile

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

pod 'Parse'


pod install

これで導入完了。


Parse

f:id:Yuchang:20150929115420p:plain
こんな感じでParseサイトであらかじめアプリで取得したいデータをセットしておく。



AppDelegate.swift

import Parse
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        
     Parse.setApplicationId("アプリケーションID", clientKey:"クライアントキー")
        
     return true
}

didFinishLaunchingWithOptionsでApplication IDとClient Keyを設定する。



storyboard

f:id:Yuchang:20150929144307p:plain UIViewControllerUITableViewを設置する。この時にdatasourcedelegateも設定しておく。


ViewController.swift

import UIKit
import Parse

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
    
    @IBOutlet weak var tableView: UITableView!
    var tableData:Array<AnyObject> = Array<AnyObject>()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "cell")
        
        self.loadData()
    }
    
    func loadData() {
        let query: PFQuery = PFQuery(className: "sample_data")
        query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
            
            if (error != nil){
                // エラー処理
                return
            }
            
            for row:PFObject in objects! {
                self.tableData.append(row)
            }
            
            self.tableView.reloadData()
        }
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.tableData.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
        let imageFile: PFFile? = self.tableData[indexPath.row].objectForKey("thumbnail") as! PFFile?
        imageFile?.getDataInBackgroundWithBlock({ (imageData, error) -> Void in
            if(error == nil) {
                cell.imageView!.image = UIImage(data: imageData!)!
                cell.textLabel!.text = self.tableData[indexPath.row].objectForKey("title") as? String
            }
        })
        return cell
    }
    
}

実装はここまで。

実行してみると


本当に簡単にWebサーバーからデータ取得、表示までを実装する事ができました。サーバーサイドの知識or実装が無くてもParseをうまく使えばそれなりのアプリが作れてしまいますね。
今回はおそらくもっとも簡単な使い方?を試しただけですので今後もParseを使って色々とやってみようと思います。

UNIXという考え方を読んだ

読書

UNIXという考え方―その設計思想と哲学

UNIXという考え方―その設計思想と哲学

言わずと知れたこの名書を今更ながら読んでみました。
プログラミング初めて三年くらいたったけどもっと早く読めば良かったとかなり後悔した。

今見てみるとプログラミング始めた初期に、この本とリーダブルコード辺りを読みながら意識してひたすら実行しながらコード書いてたら一番上達するんじゃないか?ってくらい思ってしまう。

【Swift】AlamofireImageでURLから画像取得

Swift

github.com

Alamofire用の画像コンポーネントライブラリAlamofireImageの導入メモ。

これまでAlamofireだけでは画像の非同期取得はサポートされていませんでしたがAlamofireImageを一緒に使う事で非常に簡単に画像の非同期取得も出来るようになったようです。

環境 Xcode 7.0

CocoaPods

$ gem install cocoapods


Podfile

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!

pod 'AlamofireImage', '~> 1.0'
$ pod install

これで導入は完了する。ちなみに依存関係にあるAlamofireもセットでインストールされる。
Alamofireの使い方は簡単に過去に紹介しています。

nukenuke.hatenablog.com

一番簡単な方法でやってみる

import AlamofireImage

インポートを記述


@IBOutlet weak var imageView: UIImageView!

storyboardでUIImageViewを設置しておく


self.imageView.af_setImageWithURL(NSURL(string:"https://httpbin.org/image/png")!)

これだけで画像を取得できます。

プレースホルダーも設定できる

let URL = NSURL(string: "https://httpbin.org/image/png")!
let placeholderImage = UIImage(named: "placeholder")!

self.imageView.af_setImageWithURL(URL, placeholderImage: placeholderImage)



色々フィルタも掛けられる

let URL = NSURL(string: "https://httpbin.org/image/png")!
let placeholderImage = UIImage(named: "placeholder")!

let filter = AspectScaledToFillSizeWithRoundedCornersFilter(
    size: imageView.frame.size, 
    radius: 20.0
)

self.imageView.af_setImageWithURL(
    URL, 
    placeholderImage: placeholderImage,
    filter: filter
)

これで取得した画像が角丸にできます。

トランジションも設定できます

let URL = NSURL(string: "https://httpbin.org/image/png")!
let placeholderImage = UIImage(named: "placeholder")!

let filter = AspectScaledToFillSizeWithRoundedCornersFilter(
    size: imageView.frame.size, 
    radius: 20.0
)

self.imageView.af_setImageWithURL(
    URL, 
    placeholderImage: placeholderImage,
    filter: filter,
    imageTransition: .CrossDissolve(0.2)
)

非常に簡単にURLから画像の非同期取得が行えました。

【Swift】delegateを完全克服するためのまとめ

Swift

iOSアプリ開発に関わると必ずと言って良いほど耳にするdelegate(デリゲート)。これが分かりにくくて苦しんだ人は多いのではないでしょうか。今までUITableViewとかUIScrollViewを使って何となくdelegate(デリゲート)の実装はやった事はあるけど自作delegate(デリゲート)を実装する時に困った場合なんかに参考にしてみて下さい。

そもそもdelegate(デリゲート)ってなに

The Swift Programming Language (Swift 2): Protocols

Delegation
Delegation is a design pattern that enables a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type. This design pattern is implemented by defining a protocol that encapsulates the delegated responsibilities, such that a conforming type (known as a delegate) is guaranteed to provide the functionality that has been delegated. Delegation can be used to respond to a particular action, or to retrieve data from an external source without needing to know the underlying type of that source.


簡単に言うとあるクラスから処理の一部を他のクラスに任せたり、他のクラスへメッセージを送る等の目的でよく使われるデザインパターンです。
デザインパターンはよく聞く言葉ですね。GoFなんかで有名なあれです。


ここからはサンプルを作成して実際の作成方法を記載します。

環境 xcode7.0

まず流れとして

  1. SampleView(通知元)にプロトコルを用意する。
  2. SampleView(通知元)でデリゲートメソッドを呼ぶ(処理をデリゲートインスタンスに委譲する)
  3. ViewController(通知先)でSampleView(通知元)で定義したデリゲートメソッドを実装する。


デリゲートを実装する時に考えることは何を委譲するか(なんの処理を呼ばせるのか)を決めるだけです。ぶっちゃけ誰に委譲するか(どこから呼ぶのか)は考えなくて良いです。

SampleView(通知元クラス)の用意

import UIKit

class SampleView: UIView {

    override func drawRect(rect: CGRect) {
        let button = UIButton()
        button.setTitle("Tap", forState: .Normal)
        button.frame = CGRectMake(0, 0, 50, 50)
        button.backgroundColor = UIColor.redColor()
        button.addTarget(self, action: "tappedButton:", forControlEvents:.TouchUpInside)
        
        self.addSubview(button)
        self.backgroundColor = UIColor.blackColor()
    }
    
    @IBAction func tappedButton(sender: AnyObject) {
        self.backgroundColor = UIColor.greenColor()
    }
}

まずは、protocol(プロトコル)の実装

SampleView(通知元クラス)
import UIKit

// SampleViewDelegate プロトコルを記述
@objc protocol SampleViewDelegate {
    // デリゲートメソッド定義
    func didChangeBackgroundColor(str:String)
}

class SampleView: UIView {
    
    //SampleViewDelegateのインスタンスを宣言
    weak var delegate: SampleViewDelegate?

    override func drawRect(rect: CGRect) {
        let button = UIButton()
        button.setTitle("Tap", forState: .Normal)
        button.frame = CGRectMake(0, 0, 50, 50)
        button.backgroundColor = UIColor.redColor()
        button.addTarget(self, action: "tappedButton:", forControlEvents:.TouchUpInside)
        
        self.addSubview(button)
        self.backgroundColor = UIColor.blackColor()
    }
    
    @IBAction func tappedButton(sender: AnyObject) {
        self.backgroundColor = UIColor.greenColor()
    }
}

通知元クラスでデリゲートメソッドを呼ぶ(処理をデリゲートインスタンスに委譲する)

import UIKit

// SampleViewDelegate プロトコルを記述
@objc protocol SampleViewDelegate {
    // デリゲートメソッド定義
    func didChangeBackgroundColor(str:String)
}

class SampleView: UIView {
    
    //SampleViewDelegateのインスタンスを宣言
    weak var delegate: SampleViewDelegate?

    override func drawRect(rect: CGRect) {
        let button = UIButton()
        button.setTitle("Tap", forState: .Normal)
        button.frame = CGRectMake(0, 0, 50, 50)
        button.backgroundColor = UIColor.redColor()
        button.addTarget(self, action: "tappedButton:", forControlEvents:.TouchUpInside)
        
        self.addSubview(button)
        self.backgroundColor = UIColor.blackColor()
    }
    
    @IBAction func tappedButton(sender: AnyObject) {
        self.backgroundColor = UIColor.greenColor()
        
        // デリゲートメソッドを呼ぶ(処理をデリゲートインスタンスに委譲する)
        self.delegate?.didChangeBackgroundColor("グリーン")
    }   
}

ここまでで通知元クラスの実装は終わり。

通知先クラスで通知元で定義したデリゲートメソッドを実装する。

ViewController(通知先クラス)
import UIKit
// 通知側で定義したプロトコル(SampleViewDelegate)の継承
class ViewController: UIViewController,SampleViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        let view = SampleView(frame: CGRectMake(100,100,100,100))
        // SampleViewがインスタンス化されたタイミングでデリゲートインスタンスにselfをセット
        view.delegate = self
        self.view.addSubview(view)
    }
    
    // SampleView DelegateMethod
    // SampleViewのBackgroundColorが変更された事を通知
    func didChangeBackgroundColor(str:String) {
        print(str);
    }
}

SampleViewのボタンをタップする度にViewControllerdidChangeBackgroundColorが呼ばれているのが分かると思います。
ここまででdelegateの流れは終了です。

おまけ

上記のように修飾子なしでデリゲートメソッドを定義すると、通知先で必ず実装しなければいけないメソッドrequiredになります。通知側でrequiredで定義されたメソッドを通知先で記述しなければエラーになってしまいます。
デリゲートメソッド定義の際にoptional修飾子を記述すると必ずしも実装しなくても良いメソッドにする事ができます。

// SampleViewDelegate プロトコルを記述
@objc protocol SampleViewDelegate {
    // デリゲートメソッド定義
    optional func didChangeBackgroundColor(str:String)
}

class SampleView: UIView {
    
    //SampleViewDelegateのインスタンスを宣言
    weak var delegate: SampleViewDelegate?

    override func drawRect(rect: CGRect) {
        let button = UIButton()
        button.setTitle("Tap", forState: .Normal)
        button.frame = CGRectMake(0, 0, 50, 50)
        button.backgroundColor = UIColor.redColor()
        button.addTarget(self, action: "tappedButton:", forControlEvents:.TouchUpInside)
        
        self.addSubview(button)
        self.backgroundColor = UIColor.blackColor()
    }
    
    @IBAction func tappedButton(sender: AnyObject) {
        self.backgroundColor = UIColor.greenColor()
        
        // デリゲートメソッドを呼ぶ(処理をデリゲートインスタンスに委譲する)
        self.delegate?.didChangeBackgroundColor?("グリーン")
    }
}
import UIKit

class ViewController: UIViewController,SampleViewDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
        let view = SampleView(frame: CGRectMake(100,100,100,100))
        view.delegate = self
        self.view.addSubview(view)
    }
}

optional修飾子を記述すればfunc didChangeBackgroundColor(str:String)を呼ばなくてもエラーにならない。

delegateはobj-cの頃から頻繁に使われていましたが、最近swiftに移行も進んで改めてdelegateを再確認するつもりでまとめてみました。