MultipeerConnectivityの復習

こんにちは、がわわです。
ブログを書くのをだいぶサボってました。Golangでうまくいかずやる気を失っていました。

今日はSwiftの話です。

MultipeerConnectivityとは:
WifiBluetoothで端末間通信を行いやすくするフレームワーク


ざっくり手順:

  • MultipeerConnectivityに必要なオブジェクトたちを用意する
    • MCPeerID:識別子
    • MCSession:セッション
    • MCAdvertiserAssistant:ピアを他のピアから見つけてもらうようにするヘルパークラス
    • MCBrowserViewController:ピアの検索・接続・要求ができる
  • MCSessionのインスタンスがsendDataメソッドを呼び出して送信する
  • 受け取る時はMCSessionのデリゲートメソッドのdidReceiveDataメソッドが呼ばれる

スライスから削除する(deleteみたいな関数はない)

deleteみたいな関数はないようなので自分で書きましょう。

ダメな例

func delete(s []int, i int) []int {
    s = append(s[:i], s[i+1:]...)
    return s
}

func main() {
    s := []int{1, 2, 3, 4, 5}
    s = delete(s, 2)
    //slice:[1 2 4 5], len:4, cap:5
    fmt.Printf("slice:%d, len:%d, cap:%d\n", s, len(s), cap(s))
    //s == [1 2 4 5 5]
    fmt.Println(s[:cap(s)])
}

このままだと見た目は削除できているように見えるんですけど、容量が削除されていないため不要な値が残っているようです。
なので、容量まで削除しましょう。

良い例

func delete(s []int, i int) []int {
    s = append(s[:i], s[i+1:]...)
    //新しいスライスを用意することがポイント
    n := make([]int, len(s))
    copy(n, s)
    return n
}

func main() {
    s := []int{1, 2, 3, 4, 5}
    s = delete(s, 2)
    //slice:[1 2 4 5], len:4, cap:4
    fmt.Printf("slice:%d, len:%d, cap:%d\n", s, len(s), cap(s))
    //s == [1 2 4 5]
    fmt.Println(s[:cap(s)])
}


参考サイト:
Go言語のスライスを理解しよう
Go のスライスの内部実装 - Block Rockin’ Codes

Golangで任意の型にあたるものはinterface{}

こんにちは。がわわです。

自分が詰まった部分は「Google App EngineのDatastoreで*Keyの配列をjsonで返す」というところでした。
以下は、ヘッダーに書かれたユーザーIDのtweet一覧をTweetというカインドから引っ張ってきて、keyとtweetjsonで返す関数を書こうと思ったダメな例です。

ダメな例

func GetTweets(w http.ResponseWriter, r *http.Request){
	c := appengine.NewContext(r)
	q := datastore.NewQuery("Tweet").
		Filter("UserId =", r.Header.Get("X-USERID"))
	var tweets []Tweet
	keys, err := q.GetAll(c, &tweets)
	if err != nil { panic(err) }
	
	//Keyが定義されていないからコンパイルエラー
	response := map[string][]*Key {
		"Keys": keys,
		"Tweets": tweets,
	}
	json, err := json.Marshal(response)
	if err != nil { panic(err) }
	w.Header().Set("Content-type", "application/json")
	w.Write(json)
}

正しい例

	//interface{}に任意の型を入れられる
	response := map[string]interface{}{
		"Keys": keys,
		"Tweets": tweets,
	}

interface{}とはメソッドが何もない空のインターフェースということですが、任意の型を入れられるものだということがわかりました。

参考サイト:
急いで学ぶGo lang#6 インターフェイス | Developers.IO

A Tour of Go63~72学習メモ

  • goroutineは軽量なスレッド
  • go funcでfuncを別スレッドで実行できる
  • 同期する際はチャネルを使う
  • チャネルに値を受信するまで送信されないし、受信の準備ができるまでチャネルから送信されない
  • ch := make(chan 型)の形で生成
  • チャネルにはバッファ(許容量)があるmakeの第二引数に設定できる
  • チャネルは先入先出
  • v, ok := <-c でokがtrueならチャンネルは開いてる、falseなら閉じている
  • rangeなどこれ以上くる値がないことを知らせる場合は送信側のチャネルをcloseで閉じる
  • selectでgoroutineをcaseの条件で一致するまでブロックし、一致したcaseを実行、複数一致ならランダム
  • selectでブロックしないで送受信するならdefault文を書く

演習問題は所々飛ばしてとりあえず文法を学ぶことを優先にやってきたA Tour of Goも今日で終わり!
明日からは自分が作ってるアプリを再開して早めに終わらせたいな。

A Tour of Go55~62学習メモ

  • インターフェース型のerrorError() stringという文字列を返すメソッドが定義されている
  • 返すエラーを自分で定義する際はstructを定義して、Error() stringのメソッドを実装
  • httpパッケージからHTTPリクエストの処理機能が提供されている
  • インターフェース型のHandlerにServeHTTP(w ResponseWriter, r *Request)というメソッドが定義されている

A Tour of Go58の解答

package main

import (
	"fmt"
	"net/http"
)

type String string
type Struct struct {
	Greeting string
	Punct string
	Who string	
}

func (str String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s", str)
}

func (str *Struct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s%s%s", str.Greeting, str.Punct, str.Who)
}

func init() {
	http.Handle("/string", String("I'm a frayed knot."))
	http.Handle("/struct", &Struct{"Hello", ":", "Gophers!"})
	http.ListenAndServe("localhost:4000", nil)
}

悩んだところ

  • yamlファイルのscript: _go_appの部分はscriptの前にスペース2個。pythonはこういうところが厳密なので注意。
  • func init()で書かなければならない。今までmain()でチュートリアルが進んでいたのでここで詰まってしまった。
  • fmt.Fprintfを使わないと表示されないので注意
  • http://localhost:4000/string, structでアクセスしないといけないのにhttp://localhost:4000だけでアクセスしていた

14.3項を理由にAppleにリジェクトをくらった時の解決法

こんにちは。がわわです。

iPhoneアプリには審査がありガイドラインが規定されています。

14.3
Apps that display user generated content must include a method for filtering objectionable material, a mechanism for users to flag offensive content, and the ability to block abusive users from the service

引用:App Store Review Guidelines - Apple Developer

タイトルにある14.3項とは意訳すると「ユーザーが生成したコンテンツがある場合、そのコンテンツを表示しないようにする仕組みを作らなければならない」というものです。
僕はこれでリジェクトをくらいました。

解決法は以下全て(最後のはあると望ましいです)。

  • 運営に通報できるようにする(管理画面からコンテンツを削除できるとAppleに伝えておく)
  • 利用規約を作る
  • コンテンツを生成したユーザーを非表示にする(僕の場合は実装していませんがあると望ましいです)

Appleに伝える際はiTunesConnectのマイAppの「App Reviewに関する情報」のメモに書いておけば良いでしょう。
僕の場合はリジェクトをくらった際に問題解決センターでやりとりしている際に説明しましたけど。

なにはともあれ、1ヶ月以上かかった審査も終わりました!
"Thank you for choosing iOS and the App Store."とか言われてもめげなくて良かった!

ちなみにアプリはこれです。

ダウンロードしてくださると嬉しいです。