トップ 追記

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|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|

2019-02-20 [git][OSS]Upstream開発

GitHubで公開されているオープンソースなコードを利用する際、修正が必要になった場合の対応方法として、Upstream開発の手順を説明する。

Upstream開発とは、簡単に説明すると、修正内容を本家にpull requestを投げて取り込んで貰い、独自に手を加えてしまった結果、本家から枝分かれする状況を避ける方法だ。

利用しているOSSへの貢献にもなるので、一石二鳥とも言える。

_ GitHubでforkする

GitHubで本家から自分の領域にforkする。

理由は、本家のリポジトリは普通はpush権限がないので、修正は自分のリポジトリに対して行う。

_ 自分の作業領域にcloneする

$ git clone git@github.com:murakami/cocos2d-x.git
$ cd cocos2d-x

_ 本家と内部のリポジトリをリモートに追加する

forkしたリポジトリで修正作業を行うのでなく、別に内部のリポジトリが存在する前提で、本家と内部のリポジトリをリモートに設定する。

その理由は、後で分かる。

$ git remote add upstream git@github.com:cocos2d/cocos2d-x.git
$ git remote add bitz ssh://git@git.bitz.co.jp/bitz/cocos2d-x.git
$ git remote
bitz
origin
upstream

設定されていることを確認。

_ 本家とfork先を同期する

$ git fetch upstream
$ git pull upstream ブランチ名
$ git push origin ブランチ名

_ 内部リポジトリの修正内容をfork先にchery-pickで取り込む

$ git fetch bitz
$ git checkout -b feature/修正ブランチ名
$ git cherry-pick XXXXXX
$ git push origin feature/修正ブランチ名

_ 本家に対してPull requestを作成する

GitHubのforkしたリポジトリのPull reqestsで、本家のブランチに対してPull requestが作成する。

forkしたブランチは公開されているものなのと、余計なログで汚れていないことが望ましいということで、forkしたブランチで開発作業を行うのは避けたほうがいい。


2019-02-11 [cocoa][swift]作譜用言語PL/0 表駆動の構文解析

『Algorithms + Data Structures = Programs』は、ニクラウス・ヴィルト氏の著名な書籍で、翻訳された書籍の表題は『アルゴリズム+データ構造=プログラム』だ。サンプルは、Pascalで記述され構造化プログラミングのバイブル的な書籍だ。

その次の版は、『アルゴリズムとデータ構造』と『翻訳系構成法序論』の二冊に分かれ、Modula-2で記述されている。その次の版は、Oberonで記述されているらしいが、残念ながら入手は困難だ。

ニクラウス・ヴィルト氏は、AppleのObject Pascalの開発にも関与したという話を聞いたことがある。

『翻訳系構成法序論』の感想は、最少限度の知識のみを必要とし、簡素な内容となっていて、初学者の教科書としては理想的ではないかと思っている。

それでは、続きを始める。

前回は、ゴリゴリと記述していたコードを「表駆動の構文解析」では、汎用的なコードを処理するという内容だ。

読み取った記号が終端記号か非終端記号か、そして、次の処理に移動するのか、if分の条件分岐のように、別候補に移動するのかを保持する表、Swiftでは構造体やクラスがそれに対応するので、実装してみる。

class Node {
    public var successor: Node? = nil
    public var alternative: Node? = nil
    public var terminal: Bool = true
    public var terminalSymbol: Character = "\0"
    public var nonterminalSymbol: Header? = nil
}

上記では未定義だった見出しに相当するのが以下だ。

class Header {
    public var symbol: Character = "\0"
    public var entry: Node? = nil
}

これを使いと前回の分析子の処理は以下となる。

func parse(goal: Header, match: inout Bool) {
    var s: Node? = goal.entry
    repeat {
        if s!.terminal {
            if s!.terminalSymbol == ch {
                match = true
                readChar()
            }
            else {
                if s!.terminalSymbol == empty {
                    match = true
                }
                else {
                    match = false
                }
            }
        }
        else {
            parse(goal: s!.nonterminalSymbol!, match: &match)
        }
        if match {
            s = s!.successor
        }
        else {
            s = s!.alternative
        }
    } while s != nil
}

_ ソースコード

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

2019-01-27 [cocoa][swift]作譜用言語PL/0 構文に対する分析子の作成

有名な『Algorithms + Data Structures = Programs』の後半を独立して誕生した『COMPILERBAU:』を翻訳した『翻訳系構成法序論』を今の電子計算機環境で取り組んでみた。

使用するプログラミング言語Swiftを選択したのだが、コンパイラの実装には少々向いていない部分があるので、まずは、一文字読み込んで処理するサンプルを記述してみた。

import Foundation
 
let parser = Parser()
import Foundation
 
class Parser {
    var ch: Character = "\0"
    var lineString: String = ""
    
    init() {
        readChar()
        S()
    }
    
    func readChar() {
        lineString = readLine()!
        ch = lineString[lineString.index(lineString.startIndex, offsetBy:0)]
        lineString = String(lineString.suffix(lineString.count - 1))
    }
    
    /*
     開式記号に対応する手続き。
     */
    func S() {
    }
}

それでは、教科書のサンプルコードを記述してみよう。

以下の約束事があるとする。

A="x"|"("B")".
B=AC.
C={"+"A}.

これは以下のようになる。

x
(x)
(x+x)
((x))
((x+(x+x)))

これを実装してみると以下となる。

/* 分析子 */
class Parser {
    var ch: Character = "\0"
    var lineString: String = ""
    
    init() {
        print("\(#function)")
        readChar()
        A()
    }
    
    func A() {
        //print("\(#function)")
        if ch == "x" {
            readChar()
        }
        else if ch == "(" {
            readChar()
            A()
            while ch == "+" {
                readChar()
                A()
            }
            if ch == ")" {
                readChar()
            }
            else {
                error()
            }
        }
        else {
            error()
        }
    }
 
    func readChar() {
        if lineString.count <= 0 {
            lineString = readLine()!
        }
        ch = lineString[lineString.index(lineString.startIndex, offsetBy:0)]
        lineString = String(lineString.suffix(lineString.count - 1))
        print(ch)
    }
    
    func error() {
        print("error: \(#function)")
        exit(-1)
    }
}

ここまでは、約束事を愚直にコードで処理しているという感じだ。

_ ソースコード

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

2019-01-14 [cocoa][swift]Swift Protobufについて

JSON(JavaScript Object Notation)は、通信などで利用されているデータ交換フォーマットだ。人によって読み書きが容易で、かつ、計算機にとって簡単に解釈や生成が行える。また、システムの標準的なライブラリが対応していて導入が楽という利点もあり、広く利用されている。

JSONにかわるものとしてMessage Packというフォーマとがあって、コンパクトで率的に扱えるということで、自分の周りでは使われだしている。ただ、macOS/iOSプログラマーとして難点なのは複数のライブラリが存在するのだが、安心して利用できる決定打がないということだ。また、IDL (Interface Definition Language) による読み書きコードの生成の需要があるのだが、Message Packは利用側が独自に用意するしかないということだ。

IDLが利用できるデータ交換フォーマットは色々あるのだが、Googleがオープンソースとして公開してたProtocol Buffersというデータ交換フォーマットのSwiftライブラリをAppleが用意していることを知った。そこで、どのような使いごこちなのか試してみることにした。

これを例えば、~/binにコピーして、~/.bash_profileなどでパスを通しておく。

PATH="$HOME/bin/protoc-3/bin:$HOME/bin:$PATH"

次に、Swift Protobuf プラグインを組み込む。

最も手軽な方法は、Homebrewだと思う。

$ brew install swift-protobuf

でも、今回はgithubからクローンするやり方を選んだ。

$ git clone https://github.com/apple/swift-protobuf.git
$ cd swift-protobuf

リリース・バージョンを確認する。

$ git tag -l

この記事を書いている時に最新だった1.3.1を選んでビルドする。

$ git checkout tags/1.3.1
$ swift build -c release -Xswiftc -static-stdlib

.build/release に、protoc-gen-swift というファイルが生成されているので、これを例えば ~/bin にコピーする。

以下のようなprotoファイル"my.proto"を用意する。

syntax = "proto3";
 
message BookInfo {
   int64 id = 1;
   string title = 2;
   string author = 3;
}

これを以下のコマンドでswiftコードに変換する。

$ protoc --swift_out=. my.proto

my.pb.swift というファイルが生成されているはずだ。

次に、自分のXcodeプロジェクトに組み込む。

CocoaPodsやCarthageを利用する方法があるが、ここでは、Swift ProtobufのXcodeプロジェクトを自分のXcodeプロジェクトに組み込む方法でやることにする。

自分のXcodeプロジェクトに組み込むと、TARGETSのBuild PhasesのTarget DependencesにmacOS/iOS/tvOS/watchOS毎に追加できるようになっているので、必要なものを追加する。

そして、先ほど、生成した my.pb.swift を追加する。

すると、以下のように呼び出せるはずだ。

// Create a BookInfo object and populate it:
var info = BookInfo()
info.id = 1734
info.title = "Really Interesting Book"
info.author = "Jane Smith"
 
// As above, but generating a read-only value:
let info2 = BookInfo.with {
    $0.id = 1735
    $0.title = "Even More Interesting"
    $0.author = "Jane Q. Smith"
}
print("\(info2)")
 
// Serialize to binary protobuf format:
let binaryData: Data = try! info.serializedData()
 
// Deserialize a received Data object from `binaryData`
let decodedInfo = try! BookInfo(serializedData: binaryData)
print("\(decodedInfo)")
 
// Serialize to JSON format as a Data object
let jsonData: Data = try! info.jsonUTF8Data()
 
// Deserialize from JSON format from `jsonData`
let receivedFromJSON = try! BookInfo(jsonUTF8Data: jsonData)
print("\(receivedFromJSON)")

2019-01-08 [cocoa][swift]マイDocumentクラス

一月の勉強会でMVCについてディスカッションすることになった。そこで場が盛り上がるよう、ネタとして自分がよく採用するマイDocumentクラスに発表する。

アプリケーションの設計法としてMVCが話題となることが多いが、それは、MVCはデザイン・パターンが話題になる以前のもので、今のデザイン・パターンから見ると複数のパターンが組み合わさった大きな枠組みのものだというのも理由としてあるのかな?

早速本題に入る。Appleの文書で説明されている伝統的なMVCは以下のとおり。

Traditional version of MVC as a compound pattern

これは、この論文でも説明されている。

そして、Cocoa版は以下となる。

Cocoa version of MVC as a compound design pattern

ViewとModelは直接やりとりしない。間にControllerを挟んでいるのが特徴だ。このControllerだが、一種類でない。NSApplicationDelegateだったりNSDOcumentだったりNSControllerだったりNSViewControllerだったり、アプリケーション独自のクラスだったりする。

iOS開発を始めたときから独自のDocumentクラスを用意するようにしている。

@interface Document : NSObject
@property (strong, nonatomic) NSString              *version;
 
+ (Document *)sharedDocument;
- (void)load;
- (void)save;
@end
@interface Document ()
- (void)_clearDefaults;
- (void)_updateDefaults;
- (void)_loadDefaults;
- (NSString *)_modelDir;
- (NSString *)_modelPath;
@end
 
@implementation Document
 
@synthesize version = _version;
 
+ (Document *)sharedDocument;
{
    static Document *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[Document alloc] init];
    });
    return _sharedInstance;
}
 
- (id)init
{
    self = [super init];
    if (self) {
        _version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
    }
    return self;
}
 
- (void)dealloc
{
    self.version = nil;
}
 
- (void)load
{
    [self _loadDefaults];
    
    NSString    *modelPath = [self _modelPath];
    if ((! modelPath) || (! [[NSFileManager defaultManager] fileExistsAtPath:modelPath])) {
        return;
    }
}
 
- (void)save
{
    [self _updateDefaults];
    
    NSFileManager   *fileManager = [NSFileManager defaultManager];
    
    NSString    *modelDir = [self _modelDir];
    if (![fileManager fileExistsAtPath:modelDir]) {
        NSError *error = nil;
        [fileManager createDirectoryAtPath:modelDir
               withIntermediateDirectories:YES
                                attributes:nil
                                     error:&error];
    }
    
    NSString    *modelPath = [self _modelPath];
    [NSKeyedArchiver archiveRootObject:self.indexArray toFile:modelPath];
}
 
- (void)_clearDefaults
{
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"version"]) {
        [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"version"];
    }
}
 
- (void)_updateDefaults
{
    NSString    *versionString = nil;
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"version"]) {
        versionString = [[NSUserDefaults standardUserDefaults] objectForKey:@"version"];
    }
    if ((versionString == nil) || ([versionString compare:self.version] != NSOrderedSame)) {
        [[NSUserDefaults standardUserDefaults] setObject:self.version forKey:@"version"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}
 
- (void)_loadDefaults
{
    NSString    *versionString = nil;
    if ([[NSUserDefaults standardUserDefaults] objectForKey:@"version"]) {
        versionString = [[NSUserDefaults standardUserDefaults] objectForKey:@"version"];
    }
    if ((versionString == nil) || ([versionString compare:self.version] != NSOrderedSame)) {
        /* バージョン不一致対応 */
    }
    else {
        /* 読み出し */
    }
}
 
- (NSString *)_modelDir
{
    NSArray    *paths;
    NSString   *path;
    paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    if ([paths count] < 1) {
        return nil;
    }
    path = [paths objectAtIndex:0];
    
    path = [path stringByAppendingPathComponent:@".model"];
    return path;
}
 
- (NSString *)_modelPath
{
    NSString   *path;
    path = [[self _modelDir] stringByAppendingPathComponent:@"model.dat"];
    return path;
}
@end

macOSのDocument-Based. Applicationsについて説明する。

主要なクラスは、以下の3つ。

クラス 内容
NSDocument データ管理。
NSWindowController ウィンドウ管理。
NSDocumentController ドキュメント管理。

ファイルとDocument、Modelの関係を図だ。

Document

macOSのDocument-Based Applicationのクラスの関係を図示する。

Document-Based Apps
Key objects in a document-based app

2018-12-23 [cocoa][swift]Universal Links

以前、組み込みWebブラウザの会社に勤めていた関係で、独自の機能の呼び出しにURLスキームを利用する方法はよ馴染みがある。iOSでも同様にCustom URL Schemeを利用してアプリケーションを呼び出すことができるが、この方法は、スキームが重複と、意図しない外部サービスから呼べるという問題がある。

そこで登場したのがUniversal Links。

ただ、Custom URL Schemeの知識は必要だと思うので、まずは説明する。

_ # Custom URL Scheme

形式は、以下のとおり。

スキーム名://〜

スキーム名は、重複を避けるため、ドメイン名を逆から並べる、バンドルIDから派生した文字列がオススメされている。例えば、バンドルIDがcom.example.editorのアプリケーションの一覧画面を表示するスキーム名は、com.example.editor.listという感じにする。

Custom URL Schemeは、Info.plistに定義するが、Xcodeの画面から設定する方法もある。

まずは、Info.plistでの設定箇所を説明する。

  • URL typesの
    • Item nに
      • URL identifierにユニークな識別子を設定。バンドルIDから発生した文字列がオススメ。
      • URL Schemesに
        • Item nに、スキーム名を設定。複数設定可能。

Xcodeの画面から設定する場合は、TARGETS > Info > URL Types のIdentifierに識別子をURL Schemesにスキーム名を設定する。

iOS9以降では、安全性の観点からLSApplicationQueriesSchemesを設定するなどの対応が必要となる。

_ # Universal Links

iOS9以降から利用可能。なので、それより前のバージョンをサポートする場合は、Custom URL Schemeの対応も必要。

対応手順は以下のとおり。

Webサーバのルートに、関連付けファイル (apple-app-site-association) を配置する。

{
	"applinks": {
		"apps": [],
		"details": {
			"チームID.com.example.アプリ名(バンドルID)": {
				"paths":[ "*" ]
			}
		}
	}
}

ファイル名は apple-app-site-association。

Content-Typeは application/json。

Appleの資料では、署名がある場合のContent-Typeは、application/pkcs7-mimeという説明があるが、Webサーバとの通信はHTTPSが推奨されているので署名されてなくても、なので、訳あってHTTPの場合の対応のようだ。

ちなみに、署名する場合は、以下の感じのコマンドとなる。

$ openssl smime \
    -sign \
    -nodetach \
    -in "unsigned.json" \
    -out "apple-app-site-association" \
    -outform DER \
    -inkey "private-key.pem" \
    -signer "certificate.pem"

アプリケーション側の設定は以下のとおり。

XcodeのTARGETS > Capabilities > Associated Domains をONにして、Domainsにサーバのドメイン名を設定する。

これで、App ConnectのAppIDsが、この内容で更新されるはずだが、されていなかったら手動で変更する。

Universal Linksには、Universal Linksの設定が正しいかどうかを確認するサイトが用意されている。

  • App Search API Validation Tool
    https://search.developer.apple.com/appsearch-validation-tool/

Universal Linksからの呼び出しは、UIApplicationDelegateの、以下のメソッドで検出できる。

optional func application(_ application: UIApplication, 
                 continue userActivity: NSUserActivity, 
       restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool

2018-12-12 [cocoa][swift]ターミナルでgitの状態を表示する

ターミナルでgit操作をしている際に、プロンプトにgitの状態が表示されると便利だ。

Appleが提供する開発環境は、App Store経由で入手できるXcodeをインストールするだけで完了するが、開発者サイトから個別にダウンロードできるCommand Line Tools for Xcodeをインストールしたのちに、以下の対応を行うと、プロンプトにgitの状態が表示される。

.bashrcに以下を記述する。

# Git
 
if [ -f /Library/Developer/CommandLineTools/usr/share/git-core/git-completion.bash ]; then
	source /Library/Developer/CommandLineTools/usr/share/git-core/git-completion.bash
fi
 
if [ -f /Library/Developer/CommandLineTools/usr/share/git-core/git-prompt.sh ]; then
	source /Library/Developer/CommandLineTools/usr/share/git-core/git-prompt.sh
fi
 
GIT_PS1_SHOWDIRTYSTATE=true
GIT_PS1_SHOWUNTRACKEDFILES=true
GIT_PS1_SHOWSTASHSTATE=true
GIT_PS1_SHOWUPSTREAM=auto
 
PS1="\h:\W \u\$(__git_ps1)$ "
 
# End Of File

これで完了だ。


2018-12-11 [cocoa][swift]Cocoa.swift 2019-01 のご案内

_ # 第116回 Cocoa勉強会 関東

Cocoaを一人で勉強するのはつらくて長い道のり...
そんなあなたの
Cocoa.swift

_ # Cocoa.swift について

  • Cocoa勉強会 関東 Swift分科会 です。
  • ほぼ毎月、池袋コワーキングスペース OpenOffice FOREST で開催してます。
  • macOS/iOS/watchOS/tvOSプログラマーのための勉強会です。
  • プログラムに関する知識や経験を共有を目的としています。
  • 会の活動内容や発表資料、サンプルコードは公開を前提としています。
  • 申し込みは、connpassから。
    https://cocoa-kanto.connpass.com/

_ # 発表者へのお願い

  • 発表を希望される方は申し込み時のconnpassアンケートでお申し込みください。
  • 事前に資料のリンクをconnpassに登録していただけますと嬉しいです!

_ # Cocoa.swiftのご案内

  • 会場:池袋コワーキングスペース OpenOffice FOREST
    http://co-forest.com
  • 集合:現地
  • 座席代:夜間ドロップイン 一人1,000円

_ # スケジュール

  • 18:00 自習
  • 20:00 発表
    • 20:00〜20:30 「検討中」成田さん
    • 20:30〜20:45「FoundationDBについて」村上
    • 20:45〜21:00「私の方式:MyDocumentについて」村上
    • 21:00〜21:15 休憩
  • 21:15 意見交換会
    • MVCを考える
  • 21:45 次回日程の決定、片づけ
  • 22:00 解散

_ # Cocoa勉強会 関東について

  • 以下のFacebookグループから、ご参加下さい。
    https://www.facebook.com/groups/cocoa.kanto/

_ # 注意事項

  • 写真の撮影、録音録画は、発表者、もしくはその内容によっては、望まない場合もあります。 事前に確認をお願いいたします。またコワーキングスペース周囲の方へのご配慮もお願いいたします。
  • 被写体の肖像権等に関するトラブルについて、Cocoa.swift は一切関知いたしません。当事者同士での解決をお願いします。
  • イベント中に発生した怪我や盗難等のいかなるトラブルに、Cocoa.swift は一切責任を負いません。

2018-12-10 [cocoa][swift]Cocoa.swift 2018-10 を振り返る

Cocoaを一人で勉強するのはつらくて長い道のり...
そんなあなたの
Cocoa.swift

_ # Cocoa.swift について

  • Cocoa勉強会 関東 Swift分科会 です。
  • ほぼ毎月、池袋コワーキングスペース OpenOffice FOREST で開催してます。
  • macOS/iOS/watchOS/tvOSプログラマーのための勉強会です。
  • プログラムに関する知識や経験を共有を目的としています。
  • 会の活動内容や発表資料、サンプルコードは公開を前提としています。
  • 申し込みは、connpassから。
    https://cocoa-kanto.connpass.com/

_ # TabUIの実験

macOSのウィンドウのTabについての発表です。

_ # プライバシーとセキュリティ(リモート通知のデバイストークンの扱いなど)

GDPRで話題になる頻度が上がったプライバシーとセキュリティ。対応は個々でだと思いますが、サーバを利用しないなんて考えられない今のスマートフォン・アプリケーション開発者にとって、何らかの対応が必要になる可能性があります。
今回の発表では、iOSアプリケーション開発に関係がありそうな項目について、開発の現場で話題になっていることを取り上げてみました。

_ # AppleEventなど

MacintoshのSystem 7で登場したのがAppleイベント。Appleイベントはアプリケーション間コミュニケーション(IAC)のための仕組みです。
また、アプリケーションがOSA (Open Scripting Architecture) に準拠していると、AppleScriptなどのOSA言語で記述されたスクリプトで操作できることになります。 今回の発表では、初期の頃のお話から、基礎的なこと、今のお話まで取り上げてみました。

_ # MojaveのDark Mode

Macintoshが革新的だったのは、白色背景に黒文字を表示したことです。これは、macOSのAquaにも受け継がれたのですが、MojaveのDark Mode登場により状況が変わりました。説明を信じれば集中したいときはDark Modeが適しているそうです。
真偽はさておいて、Dark Modeに試してみて感じるのは、Dark Modeに完全対応していないアプリケーションが存在すると、画面が見苦しくなるということです。
今回の発表では、Dark Modeへの対応方法を駆け足で紹介してみました。

_ # え!それって参照渡し?

とても違和感を感じる用語があります。それは、『参照渡し』です。 え!違うだろ?と感じていたのですが、いい機会なので調べてみました。


2018-12-09 [cocoa][swift]Think AppleScript 2018.9 に参加してきた

このイベントは、Cocoa.swiftで何度か発表して盛り上げていただいた ぴよまるソフトウェア(AppleScriptの穴) さんのイベントということもありますし、ぴよまるソフトウェア(AppleScriptの穴) さんは、任意団体MOSAの準備チームに参加していただいているのもありますし、任意団体MOSAのイベントということもあり参加してきました。

また、自分自身もAppleScript自体にも興味がありますが、どんな方々がどんな話題で盛り上がっているのかも、気になっていました。

ただ、イベントの内容は、その場で、各人が事例を紹介するなどの形式のため、申し訳ございませんが、上手くメモれていません。申し込みページの内容をそのまま掲載となってしまいました。

_ # Think AppleScript 2018.9

AppleScriptについて語ろう! 最新情報紹介や自慢・質問なんでも!

_ # MOSA+Piyomaru Software共催

_ # AppleScriptイベント「Think AppleScript」

  • 開催日:2018年9月26日(水) 19:00〜21:30
  • 開催場所:池袋Open Office FOREST
    東京都豊島区東池袋3-7-9 AS ONE 東池袋ビル3階
  • 会場費:1,000円(3F受付で「ナイトドロップイン」料金1,000円をお支払いください)

AppleScriptについてのイベントです。情報共有、質疑応答などを目的とします

  • AppleScriptの歴史と位置づけ、拡大する利用範囲についてのご紹介
  • 海外の動向などのご紹介
  • 事例紹介など
  • 来場者からの質問をみんなで考える「Q&A」
  • AppleScriptに関するものであれば、著作、Blog、製品、導入事例などどんどん紹介してください! 大歓迎です! → ただし、出席者からの内容についての質問は可能なかぎりお答えください

_ # Piyomaru Software Blog「AppleScriptの穴」

  • http://piyocast.com/as/

トップ 追記