Shoken Startup Blog

KitchHike Founder/CTO

第2回 Swift 勉強会@TechBuzz でLTしてきた #swiftjp

f:id:sfujisak:20140718204142j:plain

LTしてきました。

第2回 Swift 勉強会@TechBuzz http://atnd.org/events/51944

写真は@edo_m18さんの作成されたFlappy Birdの3D版。やってみたい。大画面でやると楽しそう。

発表者リスト

  • LLプログラマ向けSwift ExtensionsとテストライブラリQuickの紹介 @syokenz
  • Pattern match with case class @Lewuathe
  • Swift (with SceneKit) で簡単な3Dゲームを作ってみた @edo_m18

LLプログラマ向けSwift ExtensionsとテストライブラリQuickの紹介 @syokenz

私の発表は1番目でした。ExtensionsとテストがSpecライクに書けるライブラリのQuickを紹介しました。Quickは実際にアプリ開発で使っていますが、おすすめです。

Pattern match with case class @Lewuathe

Swiftでは、switch文の比較時に "~="演算子が呼ばれます。 NSObjectを継承したclassに、コンストラクタに渡された引数リストでパターンマッチを行える"~="演算子実装することで、Scalaにあるcase class的なことをできるようにした、という発表。

ソースコード

https://github.com/Lewuathe/SwiftCase

Swift (with SceneKit) で簡単な3Dゲームを作ってみた @edo_m18

前半は3Dゲームアプリ開発を通して、SwiftXcodeでのハマりどころを解説されました。 後半はライブコーディング。15分ほどでScene Kitを使った簡単なアプリを解説付きでコーディングされました。

ソースコード

https://github.com/edom18/HelloScene

ライブコーディング

ライブコーディングの1コマ。Scene Kitを使って、簡単な3Dを描画するところまでを説明されました。3Dやゲームの解説を聞いたのは初めてだったので、大変勉強になりました。知識が無い僕にも、説明がすごくわかりやすかったです。コーディングの操作も軽快で、見ているだけでとても楽しいものでした。

f:id:sfujisak:20140718203904j:plain

第4回 Swift 勉強会 LT会@wantedlyでLTしてきた #hack_wantedly

f:id:sfujisak:20140717201558j:plain

LTしてきました。

第4回 Swift 勉強会 LT会@wantedly http://wantedly.connpass.com/event/7043/

明日、別の勉強会で発表する予定があって資料を作っていたので、これはチャンスと思って立候補。 資料のブラッシュアップにも繋がった。アウトプット大事。

写真は、ライブコーディングをされた方(名前失念)の発表中のものです。写真から推測できるように、ライブコーディングは大変盛り上がりました。

LTリスト

  • Swiftで数学 @kubonagarei
  • Swiftの言語仕様 発表者名失念
  • Extensions 私 @syokenz
  • ライブコーディング 発表者名失念
  • Swiftのアプリ開発でハマったこと @susieyy

@susieyyさんの資料

所感

  • 参加者は15人くらいだった。ちょうど話やすい人数。
  • 懇親会まで参加。懇親会の参加率高い。
  • 良い雰囲気の勉強会だったので、また参加したい。

Swiftのfuncの引数に出てくるアンダースコアやシャープの意味について調べた

Swiftではfuncでメソッドを定義する。 funcの引数に出てくるアンダースコアやシャープはExternal Parameter Namesという。 これはメソッドの引数をラベル化する場合に使う。Rubyのキーワード引数と似ている。

Swiftでは第二引数以降はラベルを付けて呼び出す必要がある

func join(s1: String, s2: String, joiner: String) -> String {
    return s1 + joiner + s2
}
join("hello", "world", ":") // => コンパイルエラー

join("hello", s2: "world", joiner: ":") // => OK

https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Functions.html

アンダースコア ( _ ) は、引数が自明でラベルが必要ない場合に使う

// s2の前に_を書くと、
func join(s1: String, _ s2: String, joiner: String = " ") -> String {
    return s1 + joiner + s2
}

join("hello", "world", joiner: ":") // s2はラベル無しでOK

明示的にラベルで指定して欲しい時は、ラベルとして変数の前に外部から参照する文字列を置く

func join(first s1: String, second s2: String, joiner joiner: String) -> String {
    return s1 + joiner + s2
}

join(first: "hello", second: "world", joiner: ":")

シャープ ( # )は上記の外部から見えるラベルと、内部で使うパラメータが同じ名前の場合に簡略化できる

func join(s1: String, #s2: String, #joiner: String) -> String {
    return s1 + joiner + s2
}

join("hello", s2: "world", joiner: ":")

Shorthand External Parameter Names in Swift - Qiita

イニシャライザではデフォルト値が無くてもラベルが必要

class Example {
  init( counter: Int) { }
}

var example = Example(counter: 0) //ラベル必須
class Example {
  init( _ counter: Int) { }
}

var example = Example(0) //アンダースコアがあるとラベルはいらない

Swiftをターミナルで実行してWebAPIからjsonを取得してみる

Qiitaに投稿した。

Swiftをコマンドラインで実行してWebAPIからjsonを取得する - Qiita

コンパイル型言語なのにRubyirbのようなREPLモードができて楽しい。

f:id:sfujisak:20140613143148g:plain

ターミナルでSwiftを起動

$ sudo xcode-select -switch /Applications/Xcode6-Beta.app/Contents/Developer
$ xcrun swift 

実行したコード

ターミナルにコピペすれば動く。

import Foundation
// Thanks to tiqav api! ( http://dev.tiqav.com/ )
var request = NSURLRequest(URL: NSURL(string: "http://api.tiqav.com/search/random.json"))
var data = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil)
var json: NSArray = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.AllowFragments, error: nil) as NSArray
for item: NSDictionary! in json {
  println(item.objectForKey("source_url"))
}

SwiftでAVFoundationを使ったカメラアプリ

Qiitaに投稿した。

SwiftでAVFoundationを使ったカメラアプリのサンプル - Qiita

ソースコード

Swift Camera Sample

ViewController.swift

//
//  ViewController.swift
//  swift-camera-sample
//
//  Created by Shoken Fujisaki on 6/8/14.
//  Copyright (c) 2014 Shoken Fujisaki. All rights reserved.
//

import UIKit
import AVFoundation

class ViewController: UIViewController {
    
    var stillImageOutput: AVCaptureStillImageOutput!
    var session: AVCaptureSession!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // Start Camera
        self.configureCamera()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    func configureCamera() -> Bool {
        // init camera device
        var captureDevice: AVCaptureDevice?
        var devices: NSArray = AVCaptureDevice.devices()
        
        // find back camera
        for device: AnyObject in devices {
            if device.position == AVCaptureDevicePosition.Back {
                captureDevice = device as? AVCaptureDevice
            }
        }

        if captureDevice {
            // Debug
            println(captureDevice!.localizedName)
            println(captureDevice!.modelID)
        } else {
            println("Missing Camera")
            return false
        }
        
        // init device input
        var error: NSErrorPointer!
        var deviceInput: AVCaptureInput = AVCaptureDeviceInput.deviceInputWithDevice(captureDevice, error: error) as AVCaptureInput
        
        self.stillImageOutput = AVCaptureStillImageOutput()
        
        // init session
        self.session = AVCaptureSession()
        self.session.sessionPreset = AVCaptureSessionPresetPhoto
        self.session.addInput(deviceInput as AVCaptureInput)
        self.session.addOutput(self.stillImageOutput)
        
        // layer for preview
        var previewLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.layerWithSession(self.session) as AVCaptureVideoPreviewLayer
        previewLayer.frame = self.view.bounds
        self.view.layer.addSublayer(previewLayer)
        
        self.session.startRunning()
        
        return true
    }

}