[Swift Playgrounds] – Twitterクライアント作ろうとしてみた – 自由記述編

2016.09.24

おばんです、イベントに参加するときはハッシュタグつけてツイートしまくって、自分のアイコンばかりが流れる現象が起こる田中です。

今回はSwift Playgroundsの『Blank』について解説していってせっかくなのでTwitterクライアントを作ろうとしてみた話を書いてみます。
(結果としてこのブログで取り扱う方法ではTwitterクライアントを作れなかったのであしからず)

IMG_0002

IMG_0003

Swift Playgroundsとは?

こちらをご覧ください。

[Swift Playgrounds] – Swift Playgroundsことはじめ – 全体紹介編

Blankとは

BlankとはSwift Playgroundsにおいてプログラムが一切記述されていないまっさらな状態から始める、自由記述用のモードです。
普段からXcodeでSwiftを書いている方であれば、新規に.playgroundファイルを作成するようなモードだと理解いただければ大丈夫です。

IMG_0041

試し書き

ループ処理を書いてみる

例えば100回printする繰り返し処理を書いてみます。

let loopNum = 100
for i in 1...loopNum {
    print(i)
}

なんの問題もなく動きます。

UIKitを使ってみる

iOS開発においては切っても切れないUIKitも使えるようなので使ってみます。

import UIKit

let view = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
view.backgroundColor = UIColor.orange

なんの問題もなく動きます。(Playgroundなのでviewをその場で見ることもできます)

Twitterクライアントを作ろうとしてみる

UIKitが問題なく動くということはその他のフレームワークも使えるのでは...!?
ということでAccountsフレームワークとSocialフレームワークを使ってTwitterの情報を取得してみます。

以下ソースコード全文。
書いてある内容はTwitterにアクセスするためのACAccountを取得する処理マデ。

import UIKit
import Social
import Accounts

var twitterAccount: ACAccount?

class LoginManager {

    var store = ACAccountStore()
    var type: ACAccountType!

    init() {
        self.type = store.accountType(withAccountTypeIdentifier: ACAccountTypeIdentifierTwitter)
    }

    func login(completionHandler: (error: NSError?) -> ()) {
        if !SLComposeViewController.isAvailable(forServiceType: SLServiceTypeTwitter) { 
            print("SLComposeViewController NotAvailable.")
            return
        }

        // store.accountsが取得できている
        // [ktanaka117]
        print(store.accounts)

        store.requestAccessToAccounts(with: type, options: nil) { [weak self] granted, error in
            guard let _self = self else { return }

            if !granted {
                print("Not granted.")
                return
            }

            if error != nil {
                print("error: \(error)")
                return
            }

            // nil
            print(error)
            // true
            print(granted)
            // Succeeded access!!
            print("Succeeded access!!")

            // !!! 取得できない !!!
            print(_self.store.accounts)

            // --- クロージャ内の以下の処理は実行されていない模様 ---
            let accounts = _self.store.accounts(with: _self.type)
            print("aaa")
            print(accounts)
            print(_self.store.accounts.first)
            if let _account = accounts?.first as? ACAccount {
                print(_account)
            }
        }
    }
}

let loginManager = LoginManager()

// completionHandlerが呼ばれないので、この中は実行されない
loginManager.login {
}

結果としてはソースコード中のコメントに書いてある通り、requestAccessToAccounts()内にて正常に動作しない模様。
errorもなく、grantedも正常に通過するものの、クロージャ内部でstoreにアクセスできていないようです。

気づいた点

  • 通常のアプリと同様、requestAccessToAccounts時にはアクセス許可を求めるダイアログが表示される。
  • requestAccessToAccounts()内でなんらかのトラブルが起こっている模様。
  • Swift Playgrounds内で通常の通信処理は可能なようなので、(別プロジェクトにて画像をダウンロードするサンプルを書いてみたところ、正常動作した)Twitterクライアントを作りたい場合は地道にアクセストークンの取得などを通信処理を書いて行う必要がある。

まとめ

うまく動作しなかったのでまとまりが悪くなってしまいますが、出来ることの限界にチャレンジしてみたような感じで楽しかったという感想です。
今回のサンプルはiOSのプロジェクトとして書いたものでは正常に動いたのですが、Playgroundに慣れていないためその制約で書き方が間違っているなどありましたらご指摘いただけると幸いです。