トップ 追記

Cocoa練習帳

iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど

2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|

2018-01-17 [macOS][iOS]サーバーレスアーキテクチャで悩んでます

今回は、AKIBA.swift 第12回 質疑トーク回! で発表した内容だ。この回は、発表者の課題を参加者とディスカッションして解決するという内容のため、この投稿には結論はないので悪しからず。

作りたいアプリは
  • サーバを避けたい
    • プログラム作成が面倒
    • 維持費がかかる
    • アプリがヒットしてしまい、サーバへのアクセスが増えると、開発者の負担がます
    • 規模が大きくなると、性能問題や、ダウンした際の対応など、課題が出てくる
  • 必要な機能は?
    • データの読み書きの機能が用意されている。
    • バックアップとしても利用できる。
    • 持っている複数の機器で共有できる。
    • 容量制限を超えたら、ユーザに料金の請求が行く。
    • 他ユーザと共有できる機能があると嬉しい。
  • 検討しているサービス
    • iCloudストレージサービス
      • キー値ストレージ
      • ドキュメントストレージ
      • CloudKit
    • Firebase
      • Realtime Database
      • Cloud Firestore
      • Cloud Storage
    • IBM Cloud (Bluemix) は?
    • AWS は?
  • iCloudキー値ストレージ
    • UserDefaultsのクラウド版。
    • ユーザごとに1 MB以内。
    • 指定できるキーは1024個まで。
    • 各キーに対応する値のサイズはそれぞれ1 MB以内。
  • iCloudドキュメントストレージ
    • macOSの場合、~/Library/Mobile Documents/iCloud~バンドルID/ 配下に格納される。
    • Info.plist に NSUbiquitousContainersキー を追加すれば、iCloud Driveに格納される。
      
<key>NSUbiquitousContainers</key>
      
 <dict>
      
 <key>iCloud.com.example.MyApp</key>
      
 <dict>
      
 <key>NSUbiquitousContainerIsDocumentScopePublic</key>
      
 <true/>
      
 <key>NSUbiquitousContainerSupportedFolderLevels</key>
      
 <string>Any</string>
      
 <key>NSUbiquitousContainerName</key>
      
 <string>アプリ名など</string>
      
 </dict>
      
 </dict>
  • iCloud CloudKit
    • 容量制限があり、超えると開発者の負担となる。
    • アプリケーションのモデルの格納先を想定していない。
    • 差分などのデータの受け渡しや、ユーザ間でのデータの共有のためのサービス。
  • Firebase Realtime Database
    • データの保存と同期がリアルタイムで。
    • クロスプラットフォーム(iOSやAndroid)。
    • 料金プラン
      
開発者の負担の上限が設定できる。
      • 無料
        同時に100接続。1GB。10GB/月。
      • 月額固定($25/月)
        
同時に100k接続。2.5GB。20GB/月。
      • 従量課金
        
同時に100k/db。$5/GB。$1/GB。
  • Firebase Cloud Firestore
    • Realtime Databaseの次のデータベース。
    • Realtime Databaseと比較すると、階層的なデータに対応している。
  • Firebase Cloud Strage
    • ストレージ。
    • 共有できる
    • 料金プラン
      • 無料
        
5GB。1GB/日。2万操作/日。5万取得操作/日。
      • 月額固定($25/月)
        
50GB。50GB/日。100k操作/日。25万取得操作/日。
      • 従量課金
        
$0.026/GB。$0.12/GB。$0.05/10k。$0.004/10k。

2017-12-25 [BUKURO.swift]振り返りと目標

二年前に勉強会の運営方法が変わり一時は活動が停止しそうな状況となりましたが、皆さんのご協力のもと何とか継続してきました。最近は開催頻度を下げ発表の質を高め、他勉強会にも積極的に参加し、内容を見直しして結果なのか、新たな参加者も増えてきました。

来年も、勉強会の活動を通じてプログラマーが楽しくプログラミングできるよう目標を掲げて活動していきたいと思いますので、宜しくお願いします!

  • 勉強会に参加された方全員が学び得る場を提供!
  • 勉強会に参加できない方も学び得るよう、勉強会の成果をアウトプットする!
  • プログラマの拠り所となる!

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-24 [macOS][iOS]iCloud Driveに文書を格納する

前回のおさらいから。

ADC文書によると、iCloudストレージを利用する方法は以下となる。

  • キー値ストレージ
  • iCloudドキュメントストレージ
  • Core Dataストレージ
  • CloudKitストレージ

前回、iCloudドキュメントストレージに読み書きしたが、macOSだと ~/Library/Mobile Documents/iCloud~バンドルID/ 配下だった。

iCloud Drive配下でないのだが、どうやればiCloud Driveに読み書きできるのか?調べてみた。

CapabilitiesでiCloudを有効にし、Info.plist に NSUbiquitousContainersキー を追加すればいいようだ。

<key>NSUbiquitousContainers</key>
    <dict>
        <key>iCloud.com.example.MyApp</key>
        <dict>
            <key>NSUbiquitousContainerIsDocumentScopePublic</key>
            <true/>
            <key>NSUbiquitousContainerSupportedFolderLevels</key>
            <string>Any</string>
            <key>NSUbiquitousContainerName</key>
            <string>アプリ名など</string>
        </dict>
    </dict>

NSUbiquitousContainersキー には、コンテナ識別子を設定する。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/KeepADiary - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-22 [macOS][OpenGL]OpenGLに再挑戦(其の弐)

前回の続き。

まず、分かったのは、こまめにglGetError()でエラーが発生しているのか確認すること。その結果、glVertexPointer()の呼び出しで、GL_INVALID_ENUM が発生していることが分かった。

そして、OpenGLのバージョンが2.1だったのが、以下の設定で4.1になることが分かった。設定してしまうと、古いAPIが使えなくなるので、一旦、見送るが。

glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_3_2_CORE_PROFILE);

エラーの内容から、バッファオブジェクトを使用しない方法だったが、使用する方法でないと弾かれるのではと考え、試してみることにした。

GLuint  bufferID;
 
void init(void)
{
    assert(glGetError() == GL_NO_ERROR);
    
    /* ディザ処理を無効にする */
    glDisable(GL_DITHER);
    assert(glGetError() == GL_NO_ERROR);
    
    std::string ver((const char*)glGetString(GL_VERSION));
    assert(! ver.empty());
    std::istringstream verStream(ver);
    
    int major, minor;
    char dummySep;
    verStream >> major >> dummySep >> minor;
    const bool useVertexArrays = ((major >= 1) && (minor >= 1));
    NSLog(@"OpenGL Ver. %d.%d", major, minor);
    
    /* 三角形の頂点を定義する */
    const GLfloat data[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    };
    
    if (useVertexArrays) {
        /* バッファIDを取得する */
        glGenBuffers(1, &bufferID);
        
        /* バッファオブジェクトをバインドする */
        glBindBuffer(GL_ARRAY_BUFFER, bufferID);
        
        /* 配列の値をバッファオブジェクトにコピーする */
        glBufferData(GL_ARRAY_BUFFER, 3 * 3 * sizeof(GLfloat), data, GL_STATIC_DRAW);
        
        glEnableClientState(GL_VERTEX_ARRAY);
        assert(glGetError() == GL_NO_ERROR);
        
        glVertexPointer(3, GL_FLAT, 0, bufferObjectPtr(0));
        
        GLenum glErrorCode = glGetError();
        NSLog(@"%s (error code:0x%x)", __func__, glErrorCode);
        assert(glErrorCode == GL_NO_ERROR);
    }
    assert(glGetError() == GL_NO_ERROR);
    
    /* ディスプレイリストを作成する。 */
    gListID = glGenLists(1);
    glNewList(gListID, GL_COMPILE);
    assert(glGetError() == GL_NO_ERROR);
    
    if (useVertexArrays) {
        glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, &gListID);
    }
    else {
        glBegin(GL_TRIANGLES);
        glVertex3fv(&data[0]);
        glVertex3fv(&data[3]);
        glVertex3fv(&data[6]);
        glEnd();
    }
    assert(glGetError() == GL_NO_ERROR);
    
    glEndList();
    
    //NSLog(@"%s (error code:0x%x)", __func__, glGetError());
    assert(glGetError() == GL_NO_ERROR);
    
    /* 描画 */
    glutDisplayFunc(display);
    
    /* リサイズ処理 */
    glutReshapeFunc(resize);
    
    /* キーボード */
    glutKeyboardFunc(keyboard);
    
    /* 特殊キー */
    glutSpecialFunc(special);
    
    /* マウス */
    glutMouseFunc(mouse);
    
    /* ドラッグ */
    glutMotionFunc(motion);
    
    /* バックグランド処理 */
    glutIdleFunc(idle);
    
    /* コンテキスト・メニュー */
    glutCreateMenu(main_menu_callback);
    glutAddMenuEntry("Quit", QUIT_VALUE);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
}

ダメだ。やはり、glVertexPointer() を呼んだ後にエラーだ。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/mac/IRIS - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-21 [web]INTER-Mediator勉強会2017-#6

INTER-Mediator勉強会2017-#6 に参加してきたので報告する。

タイムテーブルは以下の通り。

18:00 ~ 開場・交流会
19:00 ~ プレゼン
『クライアントサイドでの書式指定』
『Docker for Macを使ってINTER-Mediatorを試用する』
21:00 ~ クロージング
21:00 ~ 有志による忘年会

今年度は地方での開催が何度か行われた。自分は、残念ながら参加できなかったのだが、来年こそは地方での勉強会に開催できたらと考えている。

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-20 [cocoa]関東swift勉強会2018-01のご案内

_ ■ 関東swift勉強会2018-01 ご案内

iOS/macOSのプログラミングの勉強会です。 Swift/UIKit /AppKit/Objective-Cの技術的な話題を取り上げます。

日時:2019/01/19(金) 19:30-22:00

会場:池袋コワーキングスペース OpenOffice FOREST http://co-forest.com

3階の受付で、swift勉強会又はcocoa勉強会ですとお伝えください。人数によって会場の席が変わる時があります。

集合:現地

座席代:夜間ドロップイン 一人1,000円(各自でお支払いください)

申込:https://cocoa-kanto.connpass.com/event/75006/

発表:募集中です。conpassのアンケート機能で適当に発表内容を書いてもらえば、こちらで以下に追加します。

* 「アウトライプロセッサ進捗会議」(macOS/Swift) 成田

* 「Developer's Tech Lab」(その他)  質問コーナーです。iOS/macOSのプログラミングの質問に答えます。

Cocoa勉強会 関東について:

以下のFacebookグループから、ご参加下さい。

https://www.facebook.com/groups/cocoa.kanto/

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-19 [macOS][OpenGL]OpenGLに再挑戦

三次元グラフィックスについて触れる機会も増えているということで、OpenGLに再挑戦。

『OpenGLの神髄』のサンプルプログラムを試してみた。

#import <iostream>
#import <sstream>
#import <Foundation/Foundation.h>
#import <OpenGL/gl.h>
#import <OpenGL/glu.h>
#import <GLUT/glut.h>
 
int gWidth = 600;
int gHeight = 500;
const int QUIT_VALUE(99);
GLuint  gListID; /* ディスプレイリストID */
 
void display(void)
{
    /* カラーバッファの初期化 */
    glClear(GL_COLOR_BUFFER_BIT);
    
    /* モデリング変換、z軸の負の方向に幾何形状を4単位移動する。 */
    glLoadIdentity();   /* 単位行列 */
    glTranslatef(0.0f, 0.0f, -4.0f);
    
    /* 幾何形状を描画する。 */
    glCallList(gListID);
    
    /* バッファの入れ替え */
    glutSwapBuffers();
    
    assert(glGetError() == GL_NO_ERROR);
}
 
void resize(int w, int h)
{
    /* ウィンドウ・サイズとOpenGLの座標を対応づける */
    glViewport(0, 0, w, h);
    
    /* 投影行列とアスペクト比を更新する */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50.0, (GLdouble)w / (GLdouble)h, 1.0, 10.0);
    
    /* 表示ルーチン用にモデルビューモードに設定する */
    glMatrixMode(GL_MODELVIEW);
    
    assert(glGetError() == GL_NO_ERROR);
    
    gWidth = w;
    gHeight = h;
}
 
void keyboard(unsigned char key, int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void special(int key, int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void mouse(int button, int state, int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void motion(int x, int y)
{
    DBGMSG(@"%s", __func__);
}
 
void idle(void)
{
    glutPostRedisplay();
}
 
void main_menu_callback(int value)
{
    if (value == QUIT_VALUE)
        exit(EXIT_SUCCESS);
}
 
void init(void)
{
    DBGMSG(@"%s", __func__);
 
    /* ディザ処理を無効にする */
    glDisable(GL_DITHER);
    
    std::string ver((const char*)glGetString(GL_VERSION));
    assert(! ver.empty());
    std::istringstream verStream(ver);
    
    int major, minor;
    char dummySep;
    verStream >> major >> dummySep >> minor;
    const bool useVertexArrays = ((major >= 1) && (minor >= 1));
    
    const GLfloat data[] = {
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    };
    
    if (useVertexArrays) {
        glEnableClientState(GL_VERTEX_ARRAY);
        glVertexPointer(3, GL_FLAT, 0, data);
    }
    
    /* ディスプレイリストを作成する。 */
    gListID = glGenLists(1);
    glNewList(gListID, GL_COMPILE);
 
    if (useVertexArrays) {
        glDrawArrays(GL_TRIANGLES, 0, 3);
        //glDisableClientState(GL_VERTEX_ARRAY);
    }
    else {
        glBegin(GL_TRIANGLES);
        glVertex3fv(&data[0]);
        glVertex3fv(&data[3]);
        glVertex3fv(&data[6]);
        glEnd();
    }
    
    glEndList();
    
    assert(glGetError() == GL_NO_ERROR);
    
    /* 描画 */
    glutDisplayFunc(display);
 
    /* リサイズ処理 */
    glutReshapeFunc(resize);
    
    /* キーボード */
    glutKeyboardFunc(keyboard);
    
    /* 特殊キー */
    glutSpecialFunc(special);
    
    /* マウス */
    glutMouseFunc(mouse);
    
    /* ドラッグ */
    glutMotionFunc(motion);
    
    /* バックグランド処理 */
    glutIdleFunc(idle);
    
    /* コンテキスト・メニュー */
    glutCreateMenu(main_menu_callback);
    glutAddMenuEntry("Quit", QUIT_VALUE);
    glutAttachMenu(GLUT_RIGHT_BUTTON);
}
 
int main(int argc, const char * argv[])
{
 
    @autoreleasepool {
        
        glutInit(&argc, (char **)argv);
        
        /* RGBカラーモード ダブルバッファ */
        glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
        
        /* 初期ウィンドウ・サイズ */
        glutInitWindowSize(gWidth, gHeight);
        
        /* 初期ウィンドウ位置 */
        glutInitWindowPosition(500, 100);
        
        /* タイトルバー */
        glutCreateWindow("IRIS GL");
        
        /* 初期化 */
        init();
        
        /* 主ループ(イベント駆動) */
        glutMainLoop();
        
    }
    return 0;
}

glDrawArraysで「Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)」が発生。なぜだ!

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/mac/IRIS - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-18 [macOS][iOS]EventKitを試す(イベントの追加と削除)

前回の続きで、イベントの追加と削除を試す。

イベントを追加する。

let event = EKEvent(eventStore: store)
event.title = "BUKURO.swift 2017-12"
event.startDate = Calendar.current.date(from: DateComponents(year: 2017, month: 12, day: 6, hour: 19, minute: 30, second: 00))
event.endDate = Calendar.current.date(from: DateComponents(year: 2017, month: 12, day: 6, hour: 22, minute: 00, second: 00))
event.calendar = store.defaultCalendarForNewEvents
do {
    try store.save(event, span: .thisEvent)
}
catch let error {
    print(error)
}

イベントを削除する。

do {
    try store.remove(event, span: .thisEvent)
}
catch let error {
    print(error)
}

動作確認が原因で関係者に通知が飛んでしまった。申し訳ない。

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/GettingThingsDone - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-17 [macOS][iOS]EventKitを試す

仕事効率化のアプリケーションには興味があって、タスク管理アプリを作ろうと考えている。その為の第一歩として、EventKitを試してみる。macOSとiOSの両方を考えているが、サンプルはiOSで。

iOSでは、Info.plistに以下のような定義が必要だ。

	NSCalendarsUsageDescription
	Access the data of the calendar.
	NSRemindersUsageDescription
	Access the data of the reminder.

macOSでは、com.apple.security.personal-information.calendars エンタイトルメントを含めるみたいだが、まだ試していないので紹介に止める。

初期化処理としてイベントストアへの接続というのがあるのだが、ユーザへの認証が必要となる。

let store = EKEventStore()
let status = EKEventStore.authorizationStatus(for: .event)
var isAuth = false
switch status {
case .notDetermined:
    isAuth = false
case .restricted:
    isAuth = false
case .denied:
    isAuth = false
case .authorized:
    isAuth = true
}
if !isAuth {
    store.requestAccess(to: .event, completion: {
        (granted, error) in
        if granted {
        }
        else {
            return
        }
    })
}

デフォルトのカレンダーに対して、過去一年分のイベントを取得する。

let startDate = Date(timeIntervalSinceNow: -365.0 * 24.0 * 60.0 * 60.0)
let endDate = Date()
let defaultCalendar = store.defaultCalendarForNewEvents
let predicate = store.predicateForEvents(withStart: startDate, end: endDate, calendars: [defaultCalendar!])
let events = store.events(matching: predicate)
print(events)

以下の通り、取得できた。

EventKit

_ ソースコード

GitHubからどうぞ。
https://github.com/murakami/workbook/tree/master/ios/GettingThingsDone - GitHub

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

2017-12-15 [macOS] TensorFlowをインストールする

CoreMLではモデルは開発者で用意しないといけない。TensorFlowの利用を考えて、インストールしてみる。

公式サイトの情報によると、macOSでは以下の選択肢がある。

  • virtualenv
  • "native" pip
  • Docker
  • installing from sources
  • Anaconda

お勧めはvirtualenvということなので、素直に従ってみる。

virtualenvをインストールする。

$ sudo easy_install pip
$ pip install --upgrade virtualenv

あれ、二個目のコマンドでエラーになる。パーミッション関連なので、sudoつけてみた。

$ sudo pip install --upgrade virtualenv

成功した。

virtualenv 環境を作成する。標準のPythonは2.7.10なので、以下のコマンドとなる。

$ virtualenv --system-site-packages ~/tensorflow

次はアクティベート。bashなので、以下のコマンドとなる。

$ source ~/tensorflow/bin/activate
(targetDirectory) $

pip 8.1がインストールされていることを確認する。

$ easy_install -U pip

TensorFlowをインストール。

$ pip install --upgrade tensorflow

動作確認する。

$ python
Python 2.7.10 (default, Jul 15 2017, 17:16:57) 
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> # Python
... import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
2017-12-15 22:40:19.713684: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.2 AVX AVX2 FMA
>>> print(sess.run(hello))
Hello, TensorFlow!
>>> 

成功したみたいだ。

_ 【Cocoa練習帳】

http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
Qiita

トップ 追記