Objective-C
iPhone
iOS
Swift

Swiftエンジニアが今週末キャッチアップしたいサンプルコードまとめ

More than 5 years have passed since last update.

Swiftが発表されてから、数日経過しましたがすでにたくさんのコードがGithubに上がっています。Swiftを始めたいエンジニアが参考になるサンプルをピックアップしてみました。

自分も今週末に珈琲を片手にコードを読んでみようと思います。

Search_·_swift.jpg


FlappySwift 4,700★

半日くらいで作られたFlappy Birdのクローンです。

SpriteKitを利用していて、メインのゲームロジックは200行弱ほどで書かれています。

Swiftでシンプルなゲームを作成するのに参考になります。

fullstackio_FlappySwift.jpg

GameScene.swift 一部抜粋

//

// GameScene.swift
// FlappyBird
//
// Created by Nate Murray on 6/2/14.
// Copyright (c) 2014 Fullstack.io. All rights reserved.
//

import SpriteKit

class GameScene: SKScene {
var bird = SKSpriteNode()
var skyColor = SKColor()
var verticalPipeGap = 150.0
var pipeTextureUp = SKTexture()
var pipeTextureDown = SKTexture()
var movePipesAndRemove = SKAction()

override func didMoveToView(view: SKView) {
// setup physics
self.physicsWorld.gravity = CGVectorMake( 0.0, -5.0 )

// setup background color
skyColor = SKColor(red: 81.0/255.0, green: 192.0/255.0, blue: 201.0/255.0, alpha: 1.0)
self.backgroundColor = skyColor

// ground
var groundTexture = SKTexture(imageNamed: "land")
groundTexture.filteringMode = SKTextureFilteringMode.Nearest

var moveGroundSprite = SKAction.moveByX(-groundTexture.size().width * 2.0, y: 0, duration: NSTimeInterval(0.02 * groundTexture.size().width * 2.0))
var resetGroundSprite = SKAction.moveByX(groundTexture.size().width * 2.0, y: 0, duration: 0.0)
var moveGroundSpritesForever = SKAction.repeatActionForever(SKAction.sequence([moveGroundSprite,resetGroundSprite]))

for var i:CGFloat = 0; i < 2.0 + self.frame.size.width / ( groundTexture.size().width * 2.0 ); ++i {
var sprite = SKSpriteNode(texture: groundTexture)
sprite.setScale(2.0)
sprite.position = CGPointMake(i * sprite.size.width, sprite.size.height / 2.0)
sprite.runAction(moveGroundSpritesForever)
self.addChild(sprite)
}

// skyline
var skyTexture = SKTexture(imageNamed: "sky")
skyTexture.filteringMode = SKTextureFilteringMode.Nearest

var moveSkySprite = SKAction.moveByX(-skyTexture.size().width * 2.0, y: 0, duration: NSTimeInterval(0.1 * skyTexture.size().width * 2.0))
var resetSkySprite = SKAction.moveByX(skyTexture.size().width * 2.0, y: 0, duration: 0.0)
var moveSkySpritesForever = SKAction.repeatActionForever(SKAction.sequence([moveSkySprite,resetSkySprite]))

for var i:CGFloat = 0; i < 2.0 + self.frame.size.width / ( skyTexture.size().width * 2.0 ); ++i {
var sprite = SKSpriteNode(texture: skyTexture)
sprite.setScale(2.0)
sprite.zPosition = -20;
sprite.position = CGPointMake(i * sprite.size.width, sprite.size.height / 2.0 + groundTexture.size().height * 2.0)
sprite.runAction(moveSkySpritesForever)
self.addChild(sprite)
}

・・・


swift-2048 600★

Objective-Cで作られた2048のゲームをSwiftに移植したコードです。

Enumのパターンマッチを活用している点が参考になります。

メインのロジックは500行弱です。

GameModel.swift 一部抜粋

・・・

// Represents an action applied to a tile; used to generate move orders
enum ActionToken {
case NoAction(source: Int, value: Int)
case Move(source: Int, value: Int)
case SingleCombine(source: Int, value: Int)
case DoubleCombine(source: Int, second: Int, value: Int)

// Get the 'value', regardless of the specific type
func getValue() -> Int {
switch self {
case let .NoAction(_, v): return v
case let .Move(_, v): return v
case let .SingleCombine(_, v): return v
case let .DoubleCombine(_, _, v): return v
}
}
// Get the 'source', regardless of the specific type
func getSource() -> Int {
switch self {
case let .NoAction(s, _): return s
case let .Move(s, _): return s
case let .SingleCombine(s, _): return s
case let .DoubleCombine(s, _, _): return s
}
}
}

・・・

// Convert all action tokens into move orders
func convert(group: ActionToken[]) -> MoveOrder[] {
var moveBuffer = MoveOrder[]()
for (idx, t) in enumerate(group) {
switch t {
case let .Move(s, v):
moveBuffer.append(MoveOrder.SingleMoveOrder(source: s, destination: idx, value: v, wasMerge: false))
case let .SingleCombine(s, v):
moveBuffer.append(MoveOrder.SingleMoveOrder(source: s, destination: idx, value: v, wasMerge: true))
case let .DoubleCombine(s1, s2, v):
moveBuffer.append(MoveOrder.DoubleMoveOrder(firstSource: s1, secondSource: s2, destination: idx, value: v))
default:
// Don't do anything
break
}
}
return moveBuffer
}

・・・


swiftz 300★

Swiftzは関数型プログラミングのためライブラリです。

便利な機能が追加されています。

JSONのパースはバリューの型を厳密の精査するようになったので、Objective-Cで記述するよりも冗長になりやすいのですが、このライブラリを利用すると使いやすくなります。

並列処理の記述も、NSOperation/NSOperationQueueを利用するよりも書きやすいです。

JSON:

let js: NSData = ("[1,\"foo\"]").dataUsingEncoding(NSUTF8StringEncoding,

allowLossyConversion: false)
let lhs: JSValue = JSValue.decode(js)
let rhs: JSValue = JSValue.JSArray([JSValue.JSNumber(1), JSValue.JSString("foo")])
XCTAssert(lhs == rhs)
XCTAssert(rhs.encode() == js)

Concurrency:

// we can delay computations with futures

let x: Future<Int> = Future(exec: gcdExecutionContext, {
sleep(1)
return 4
})
x.result() == x.result() // true, returns in 1 second

// Channels
let chan: Chan<Int> = Chan()
chan.write(1)
chan.write(2) // this could happen asynchronously
let x1 = chan.read()
let x2 = chan.read()
println((x1, x2)) // 1, 2

// we can map and flatMap over futures
x.map({ $0.description }).result() // "4", returns instantly
x.flatMap({ (x: Int) -> Future<Int> in
return Future(exec: gcdExecutionContext, { sleep(1); return x + 1 })
}).result() // sleeps another second, then returns 5


Quick 70★

BDDなテストフレームワークです。

RSpec, Specta, Ginkgoを参考にしてるそうです。記述はRSpecによく似ていて、SPECが書きやすそうです。またSwiftの内部DSLとしての可能性も感じます。

import XCTest

class PersonSpec: QuickSpec {
override class var isConcreteSpec: Bool { get { return true } }

override class func exampleGroups() {
describe("Person") {
var person: Person?
beforeEach { person = Person() }

it("is happy") {
XCTAssert(person!.isHappy,
"expected person to be happy by default")
}

describe("greeting") {
context("when the person is unhappy") {
beforeEach { person!.isHappy = false }
it("is lukewarm") {
XCTAssertEqualObjects(person!.greeting, "Oh, hi.",
"expected a lukewarm greeting")
}
}

context("when the person is happy") {
beforeEach { person!.isHappy = true }
it("is enthusiastic") {
XCTAssertEqualObjects(person!.greeting, "Hello!",
"expected an enthusiastic greeting")
}
}
}
}
}
}


まとめ

上記にピックアップしたコード以外にもたくさん面白そうで勉强になるコードがあるので、皆さんも探してみてください。


補足 RSS Reader 50★

筆者が作成した、シンプルなRSSのサンプルです。

cocoapodsのライブラリを利用して、100行程度で実装しているので、最初にアプリ開発の雰囲気をつかむには参考になるかと思います。

qiita - SwiftのRSS Readerを100行で作ったよ

move