Help us understand the problem. What is going on with this article?

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

susieyy
フリーランス - スタートアップエンジニアリングアドバイザー - iOS技術顧問 - プロトタイプ開発
https://susieyy.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした