[macOS]クラスを作成する
前回のコマンドライン・プログラムをクラスを使うように書き換えた。
作成したクラスは以下のとおり。
import Foundation
import GameplayKit
class LotteryEntry {
var entryDate: Date
private var _firstNumber: Int
var firstNumber: Int {
return _firstNumber
}
private var _secondNumber: Int
var secondNumber: Int {
return _secondNumber
}
init() {
self.entryDate = Date()
self._firstNumber = 0
self._secondNumber = 0
}
deinit {
print("Destroying \(self)")
}
func description() -> String {
let dateFormatter = DateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "ja_JP") as Locale!
dateFormatter.timeStyle = .short
dateFormatter.dateStyle = .short
let date = dateFormatter.string(from: entryDate)
return "\(date) = \(firstNumber) and \(secondNumber)"
}
func setNumbersRandomly() {
self._firstNumber = GKRandomSource.sharedRandom().nextInt(upperBound: 99) + 1
self._secondNumber = GKRandomSource.sharedRandom().nextInt(upperBound: 99) + 1
}
}
主関数は以下のように変更した。
import Foundation
var array = [LotteryEntry]()
for i in 0..<10 {
/*
let number = i * 3
array.append(number)
*/
var entry = LotteryEntry()
entry.setNumbersRandomly()
entry.entryDate = Date(timeIntervalSinceNow: (60.0 * 60.0 * 24.0 * 7.0 * Double(i)))
array.append(entry)
}
print(array)
for entry in array {
print(entry.description())
}
exit(EXIT_SUCCESS)
新規作成したクラスLotteryEntryは、ヒレガス本ではNSObjectを継承したクラスだったが、Swiftなので何も継承しないクラスとした。そこで、後で気がついたのだが、クラスの内容をダンプするために、description()関数を追加したのだが、これは、NSObjectの場合だったようだ。
ヒレガス本では、NSCalendarDateが使われていたが、これは廃止されたクラスなので、Dateクラスを利用している。
乱数の生成は、GameplayKitフレームワークを利用している。
ソースコード GitHubからどうぞ。https://github.com/murakami/workbook/tree/master/mac/lottery - GitHub
関連情報 Aaron Hillegass
Cocoa Study (connpass)
Cocoa勉強会 (connpass)
Cocoa Study (ATND)
MOSA (connpass)
【Cocoa練習帳】 http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
[macOS]継承vs使用
最新の環境でCocoaプログラミングを復習していると、思わぬ発見がある。
クラスの継承を選択するのはCococaプログラミングの初心者が陥りやすい罠で、熟練者は使用を選択する。
C++のような強い型付けの言語では、継承は必要不可欠だが、Objective-Cのような弱い型付け言語では、継承はタイプング量を減らすための、その場しのぎだそうだ。この考えは、InterfaceBuilderでも感じられる。
Swiftは強い型付け限度だが、それによって、大量の間違った継承の選択による問題発生を危惧したのか、Structの利用を推奨し、プロトコル指向を勧めているみたい。
ただ、Struct好きおじさんによる、間違ったStructの選択による悲劇が耳に入ってきているので、何事もほどほどが一番のようだ。
ソースコード GitHubからどうぞ。https://github.com/murakami/workbook/tree/master/mac/lottery - GitHub
関連情報 Aaron Hillegass
Cocoa Study (connpass)
Cocoa勉強会 (connpass)
Cocoa Study (ATND)
MOSA (connpass)
【Cocoa練習帳】 http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
[macOS]Foundation Tooleを試す
XcodeのNew Projectで、macOSのCommand Line Tooleを選択する。プロジェクト名は、ヒレガス本の通り"lottery"とする。
ヒレガス本で紹介されていたコードを自分がオーソドックスだと思っているSwiftでコーディングしてみる。
import Foundation
var array = [Int]()
for i in 0..<10 {
let number = i * 3
array.append(number)
}
print(array)
exit(EXIT_SUCCESS)
まず、ヒレガス本でAutoreleasePoolだったのをARCで記述している。
NSNumberは、SwiftのIntの配列とし、var宣言することによって、変更可能としている。
配列に格納されるのは、NSNumberから素直にIntとしている。
最後に、終了時に何もしないとプロセスは0を返すようだが、明示的にexit()を呼んでいる。
ソースコード GitHubからどうぞ。https://github.com/murakami/workbook/tree/master/mac/lottery - GitHub
関連情報 Aaron Hillegass
Cocoa Study (connpass)
Cocoa勉強会 (connpass)
Cocoa Study (ATND)
MOSA (connpass)
【Cocoa練習帳】 http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
[macOS]macOS Cocoaプログラミングをはじめる
macOSのCocoaプログラミング状況は近年大きく変わった。理由は、iOSのCocoa touchからのフィードバックということになるのだろう。
iPhone SDKが出た時は、UI関連のフレームワークは、OS XとiPhoneで大きく異なったが、最新のフレームワークでは、iOSプログラミングの要領でmacOSプログラミングができるようになっていることに驚くプログラマーも多いと思う。この進化を続けているmacOS Cocoaプログラミングを今のタイミングで入門する際に役立つ情報を集めてみた。
最初に読んだ方が良い、全体を俯瞰する資料といえば、以下だろう。
具体的なコードの説明が足りないため、物足りないが、ある程度の技術が身についた後でも、気づかされる情報が説明されているので、お勧めだ。
macOSプログラミング環境は大きく変わってきている。Swiftもそうだし、ViewControllerなども大きく変わった。市販の書籍もこの進化に追いついていない。でも、逆の見方をすれば、どの書籍も最新の環境にあっていないので、どんな古い書籍でも役立つと言えるのでは?
ということで、著者が選択したのは、昔から人気があったヒレガス本。それも、最初の日本語訳版を頭から最新の環境に読み替えて取り組んでいこうと、個人的に考えている。
この書籍を紹介しているサイトを探したが、古すぎて見つけられなかった。残念。
ソースコード GitHubからどうぞ。https://github.com/murakami/workbook/tree/master/mac/RandomApp - GitHub
関連情報 Mac App Programming Guide
Cocoa Study (connpass)
Cocoa勉強会 (connpass)
Cocoa Study (ATND)
MOSA (connpass)
【Cocoa練習帳】 http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
[macOS]始めよう
macOSプログラミングがマイブームだ。手始めに、初期のヒレガス本を最新の開発環境で頭からやってみることにする。
新規プロジェクトを作成。macOSでCocoa Applicationを選択。

以前と異なるのは、以前は自分でアプリケーションのコントローラとなるクラスAppControllerを生成したが、最新の開発環境では、iOSと同様に、AppDelegateとViewControllerが生成済み。
以前ならAppDelegateを選択したと思うが、ViewControllerにコントローラの処理を追加。
AppDelegateは、こんな感じ。
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
ViewControllerに乱数生成のコードを追加。
import Cocoa
import GameplayKit
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
@IBOutlet var textField: NSTextField?
@IBAction func generate(sender: NSButton) {
let randomNumber = GKRandomSource.sharedRandom().nextInt(upperBound: 99) + 1
textField?.integerValue = randomNumber
}
@IBAction func seed(sender: NSButton) {
textField?.stringValue = "Generator seeded"
}
}
ソースコード
[iOS]CloudKitを使う
Hackdrライダーにも悩みがある。
燃料計がない単車に乗っているのだが、給油時にトリップメータの値(走行距離)と消費量(給油量)から燃費を計算しないといけない。先ずは、フューエルタンクの容量を把握すること。そして、トリップメータの値から残量を予測し、給油のタイミングを判断することになる。
メーカーから、これの為のアプリが提供されているのだが、WebViewを使った手抜きで、使いづらい。なので、自作することにした。
記録データはサーバ上に置きたいが、自分で立てるのは避けたい。調べたら、iCloud関連が良さそうだ。
利用できるストレージの種類は以下のとおり。
- キー値ストレージ
UserDefaultsと同様 - ドキュメントストレージ
文書ファイル - CoreDataストレージ
←廃止 - CloudKit
他ユーザと共有できるデータ
CloudKitを利用することにする。
XcodeのCapabilitiesでCloudKitを有効に設定。
CloudKit Dashboardで形式を定義する。
仮の追加コードを用意して見た。
@IBAction func add(sender: UIButton) {
let privateDatabase : CKDatabase = CKContainer.default().privateCloudDatabase
let refuelRecord: CKRecord = CKRecord(recordType: "Refuels")
refuelRecord["Identifier"] = NSUUID().uuidString as CKRecordValue?
privateDatabase.save(refuelRecord) {
record, error in
if error == nil {
print("Saved : \(record)")
} else {
print("Error : \(error)")
}
}
}
追加した内容を確認するコードだ。
@IBAction func search(sender: UIButton) {
let privateDatabase : CKDatabase = CKContainer.default().privateCloudDatabase
let predicate = NSPredicate(format: "Identifier != %@", "nil")
let query : CKQuery = CKQuery(recordType: "Refuels", predicate: predicate)
privateDatabase.perform(query, inZoneWith: nil, completionHandler: {
results, error in
print("\(results)")
})
}
ソースコード
GitHubからどうぞ。
https://github.com/murakami/MotorcycleNotebook - GitHub
関連情報
CloudKitクイックスタート
Cocoa Study (connpass)
Cocoa勉強会 (connpass)
Cocoa Study (ATND)
MOSA (connpass)
【Cocoa練習帳】
http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
勉強会のご案内
参加していた勉強会の運営に変更があり、今年度は、主に池袋と松戸で定期的に勉強会が解されるようになった。
渋谷で開催された勉強会は、以下のとおり。
- Cocoa Study at Shibuya #1
日時:2016/03/17(木) 19:30-21:00
会場:電源カフェbeez 渋谷 - Cocoa Study at Shibuya #2
日時:2016/04/14(木) 19:30-21:00
会場:電源カフェbeez 渋谷
渋谷の会場が都合で使えなくなったため、池袋で開催されるようになった。
- Cocoa Study at Ikebukuro #1
日時:日時:2016/06 19:30-22:00
会場:池袋コワーキングスペース OpenOffice FOREST - Cocoa Study at Ikebukuro #2 (2016/07/25)
- Cocoa Study at Ikebukuro #3 (2016/08/29)
- Cocoa Study at Ikebukuro #4 (2016/09/26)
- Cocoa Study at Ikebukuro #5 (2016/11/14)
- Cocoa Study at Ikebukuro #6 (2016/12/05)
松戸でも開催されるようになった。松戸では、今後は、初心者向け、かつ、macOS関連の発表を充実させて行く予定だ。ただ、会の内容を決めるのは発表者なので、参加者次第となるが。
今年度から、NPO法人MOSAの理事になり、MOSA自習室という勉強会を開催。
- 第1回 MOSA自習室 (2016/07/11)
- 第2回 MOSA自習室 (2016/08/08)
- 第3回 MOSA自習室 (2016/09/05)
- 第4回 MOSA自習室 (2016/10/14)
- 第5回 MOSA自習室 (2016/11/25)
どんな内容なのかは、各勉強会のページに発表資料のリンクがあるので、それで確認してほしい。
年明けも、以下の勉強会の開催が決まっているので、興味がある方は、申し込みを。
自分が考えている発表は、一つは、よりCoolなSwiftによるプログラミングを調べた『Swiftyを試してみる』と、macOSの開発をしたくなったので、近年、大きく変わったmacOS関連の基本的なアプリケーションについてを考えている。
関連情報
Cocoa Study at Ikebukuro #6 (BUKURO.swift)
Cocoa Study (connpass グループ)
Cocoa Study (ATND グループ)
Cocoa勉強会
Cocoa勉強会(関東)
Cocoa勉強会 関東 (connpass グループ)
Cocoa勉強会関西
Cocoa勉強会関西ビギナーズ
MOSA
MOSA (connpass グループ)
【Cocoa練習帳】
http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
何を学ぶべきか?
業務上、CやC++、Objective-C、Swift、Java、C#を同時に利用するという機会があるのだが、それで得られた感想は、プログラミング言語の違いによる差はない、だ。単に記法が異なるだけ。
違いが出るのは、どんなフレームワークを使っているかで、そういう意味から、Objective-CとSwiftの差はないと思う。
○○言語の方が簡単で効率的!といわれる場合があるが、ワインバーグさんが言っているように、これは経営側からの視点の言葉だと思う。○○言語の方が安全といわれる場合もあるが、これはあるレベルのスキルがある関係ないと思う。今後定年がなくなると言われる状況で、ずっとプロでやって行くことを考えると、安全なプログラミング言語でないと危険な仕事をしているようではと思う。
自分の経験から、自分がまだプログラミングの仕事ができているのは、以下を学ぶことができたからかなと考えている。
- Bourne Shell
- C言語
- Cocoa
Swiftを知って、あらためてC言語の素晴らしさを実感しているが、C言語のスキルを得るために、Swift主流の時代ににSwiftしか知らないのでObjective-Cを学ぶのは難しいとは思う。かと行って、hello, worldレベルの学習をしてもしょうがない。難しい状況だな。
Cocoaのような本格的で大規模なGUIライブラリを知っておくのは、大事だと思う。違うものが主流になっても、その経験は生きるので。
ソースコード GitHubからどうぞ。https://github.com/murakami/workbook/tree/master/ios/Hand - GitHub
関連情報 文化を調和させる
【Cocoa練習帳】 http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
[Swifty]プロトコル指向プログラミング
今回は、出だしは少し辛口。
MacOS時代、クラスライブラリMacAppを使用したプログラミングの手法として、オブジェクト・プログラミングというのがあった。これは、利用側が、必ずしもオブジェクト指向プログラミングをする必要がない。オブジェクト指向で実装されたライブラリを利用すればいいということだったと思う。
この考えは、NeXTstepでもあったと思っていて、継承以外のクラスを拡張する方法としてデリゲートが用意されていたり、InterfaceBuilderはクラスでなく、インスタンスを生成するところなどがそうではないだろうか?
自分はたいした職歴でないが、過去を思い出すと、継承を多用したプロジェクトは、必ず、スパゲッティになっていた。何が問題なのかなとボンヤリと思うと、継承をコードの共通化として利用し、オブジェクトとしての構成がよくなかったのではないか?では、そこを頑張ればいいのかというと頑張ると変な方向に行ってしまうような。
なかなか、この考えに考え抜いたスパゲティを生産される方は、その主張がパッと聞くと正論のように思われ、止めることはできず。逆に止めようとすると、論争になり、ますます、泥沼にはまっていたよな〜。
恐ろしいのは、この設計論争は、何もモノを生み出さない。趣味ですね。
Swiftでclass出なくstructを。継承でなくプロトコルを勧めているのも、多くの方々が、このスパゲティ・クラスに疲れ果ててしまったからかな思う。
イカンイカン。脱線しているので本題に戻る。
今回取り上げるのはWWDC2015のセッション『Protocol-Oriented Programming in Swift』。
課題を3つ挙げている。
- Implicit Sharing
- Inheritance All Up In Your Business
- Lost Type Relationships
一つ目は、リファレンス型のことを言っているようで、値を変えると、他で所有しているところで驚くという内容だ。ただ、これは、以前も説明した通りモジュール化の問題で、Model(Dataコントローラ)を用意するとか、必要な複製は行うとかすれば問題ないと考えている。
二つ目は、継承の問題で、パッと思いついたのは、親でreadonlyにしたが、一部の子でwriteしたくなり、そのためにそれ専用のメソッドを用意したり、逃げで苦労するということか。継承しすぎ、Baseクラスやめたら、ですね。
最後は型の問題で、親子で方がうまくいかず、他の子のことを考慮したり、親で子を考慮したりということか。
ということで、推奨されたのが以下の7つ。
- Supports value types (and classes)
- Supports static type releationships (and dynamic dispatch)
- Non-monolithic
- Supports retroactive modeling
- Doesn't impose instance data on models
- Doesn't impose initialization burdens on models
- Makes clear what to implement
詳細は割愛するが、それでプロトコル指向プログラミングということだが、何とか指向というと、スパゲティの悪夢が蘇って腰が引けてしまうが、まずは、自称オブジェクト指向プログラミングを制限するというのは、いいかも。
これで、悲劇が繰り返さないことを願う。
ソースコード GitHubからどうぞ。https://github.com/murakami/workbook/tree/master/ios/Hand - GitHub
関連情報 文化を調和させる
【Cocoa練習帳】 http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)
[Swifty]Self要件
本件、プロジェクトの構成の違いから、最後はグダグダになってしまったので、一通り巡ったということで、その中で気になったことを調べてみることにする。
プロトコルでSelfを返すように変更したが、何となく意味は分かるのだが、何なんだろう。The Swift Programming Languageを読み返してみたが、それらしい記述がない。検索したところ、おそらく、WWDCの発表からだろうか。Self要件と説明しているサイトを見つけた。
protocol DataType {
var numberOfItems: Int {get}
func addNewItemAtIndex(index: Int) -> Self
func deleteItemAtIndex(index: Int) -> Self
func moveItem(fromIndex: Int, toIndex: Int) -> Self
}
このプロトコルを適用したクラスの型として扱われるということのようだ。
ただ、これはプロトコルでのみ許されているようで、適用したクラスでは、そのクラスで宣言しないとエラーとなった。
struct Hand: DataType {
public var numberOfItems: Int {
return cards.count
}
public func addNewItem(at index: Int) -> Hand {
return insertCard(card: deck.nextCard(), at: index)
}
private func insertCard(card: Card, at index: Int) -> Hand {
var mutableCards = cards
mutableCards.insert(card, at: index)
return Hand(deck: deck, cards: mutableCards)
}
public func deleteItem(at index: Int) -> Hand {
var mutableCards = cards
mutableCards.remove(at: index)
return Hand(deck: deck, cards: mutableCards)
}
public func moveItem(fromIndex: Int, toIndex: Int) -> Hand {
return deleteItem(at: fromIndex).insertCard(card: cards[fromIndex], at: toIndex)
}
}
Self要件によって、プロトコルは、総称型のように、適用した型を抽象的に記述できるということのようだ。
ソースコード GitHubからどうぞ。https://github.com/murakami/workbook/tree/master/ios/Hand - GitHub
関連情報 文化を調和させる
【Cocoa練習帳】 http://www.bitz.co.jp/weblog/
http://ameblo.jp/bitz/(ミラー・サイト)