Hatena::Groupiphone-dev

勢いでMacを買っちゃったんで iPhoneアプリ頑張って開発する

2010-03-06

CoreLocationの気まぐれ動作

| 02:45

悩んでいるのは二箇所。

1つ目、CoreLocationManagerが位置情報を拾いすぎる。

「位置情報を取得したよー」の時に呼び出されるのがdidUpdateToLocationのメソッド(didUpatalocationManager:didUpdateToLocation:fromLocation:)

ところが、一回、位置情報取得してこいと掛け声(startUpdatingLocation)を掛けると、このメソッドがなぜか何度も呼び出される。


CoreLocationManagerに関しては、こちらのページに簡潔にまとめられているようなので、参考にしてみる。

CLLocationで現在位置を取得する: iPhoneアプリ開発備忘録

すると、

didUpdateToLocationメソッドは、Locationのデータがアップデートした際に呼ばれるので、複数回呼ばれることがある。従って、このメソッドの後続処理で画面遷移などを行う場合は、アップデート通知を1回のみにする必要がある。その実装は、locationManagerメソッド内でstopUpdatingLocationを呼び出せばよい。

と書いてある。なるほど。

でも、こちらで試す限りstopUpdatingLocationのメッセージを出しても、didUpdateToLocationのメソッドが呼び出されている。

(ちなみに、stopUpdatingLocationを使った時には2回呼び出され、使わない時には3回呼び出されている。)


なぜ?

うちんとこのiPhoneは、そんなに位置測りたいの?計測が好きなの?

電波他の環境によって位置情報を計測しにくい、取得に時間がかかるという状況は予想していたけど、その逆は予想外だわ。

GPS衛星は、うちの上空10mくらいのところを飛んでのかもしれない。

ひとまず、センサーが働きすぎて位置情報を一度に何度も持ってくることもある という前提でアプリを書き直した。

ちょっと腑に落ちないところもあるけど。


2つ目、Objective-C + Cocoaの経験値が低い。

経験値が足りないため、やはり作業効率が低い。

先日も、単純なポカミスが原因の動作不良が起きたのだけど、原因がなかなか分からず難航した。

たしか、こんなケース。

  UILabel *label = ほげほげ

  label = @"foofoo"; // ← label.textとするところなのだが、.textを書き落とした。

こうしたケースだったら、当然コンパイルエラーを出してくれるものと勝手に期待していたのだけど、なぜかコンパイルを通り、ランタイムエラーで悩むハメに。

Objective-Cって型にわりと厳格な言語だと思っていたのだけど、案外そうでないのね。

「キャストくらいしろよ」的な警告くらいは出るかと思ってたのに驚きだ。

緩い調査課題

上のケースがコンパイルを通ってしまうというのは、ちょっと面白い現象だったので、時間があればどういう経緯があったのか調べてみようと思う。

まさか、UILabelがNSStringの継承オブジェクトということはないよね?

kaz_hiramatsukaz_hiramatsu2010/05/16 15:58stopUpdatingLocationのメッセージを出してもdidUpdateToLocationのメソッドが2回呼ばれる現象、自分も悩みました。
仕様なんですかね?
自分もこの前提で書きなおしました。

2010-03-02

Objective-Cにおけるenumとconstの差異が分からない

| 01:22

さほど重要ではないのだけど、定数を設定する時のObjective-Cの文法で少し疑問がある。

例えば、CLLocationAccuracyに設定する定数(kCLLocationAccuracyBest等の5つ)の定義を見ると、

  extern const CLLocationAccuracy kCLLocationAccuracyBest;
  extern const CLLocationAccuracy kCLLocationAccuracyNearestTenMeters;
  extern const CLLocationAccuracy kCLLocationAccuracyHundredMeters;
  extern const CLLocationAccuracy kCLLocationAccuracyKilometer;
  extern const CLLocationAccuracy kCLLocationAccuracyThreeKilometers;

となっている。

すでに記憶が定かでないのだが、はるか昔に使っていたC言語では定数を定義するときには、enumを使い

  enum hoge { FOO, BAR } hoge1;

と書いていた。*1

Objective-Cのドキュメントを見ても、文法的に誤りではないようだし、実際こう書いて期待通りに動作している。

だが、このenum、上のextern const〜を使った場合との違いは何だろう?

こちら(Cocoaのためのコーディングガイドライン)のページによれば、

浮動小数点値の定数を作成するにはconstを使用してください。また、他の定数に関連のない、整数の定数を作成するためにもconstを使用することができます。そうでない場合は、列挙型を使用してください。

とある。

  • const を使うケース
    1. 浮動小数点値の定数を作る
    2. 整数の定数を作る(他の定数に関連のない定数の場合)
  • enum を使うケース
    1. 整数の定数を作る(他の定数に関連のある定数の場合)

ということだろうか?

前述のCLLocationAccuracyに設定するkCLLocationAccuracyBestといった値は、わざわざ浮動小数点を使ってはいないだろうから、constの2)のケースのはずだ。

"他の定数に関連のある"というのは他の定数の定義で使われているといった意味ならば、今、自分のプログラムenumを使っている部分もconstの2)に該当しそうだ。(やっぱり、constを使った方が良いのかな?)

いずれ、時間に余裕が出たら調べてみることにする。

*1DOS時代のC言語にはconstって存在してなかったような気がする。記憶違い?

NaoNao2010/08/19 09:29constは定数を定義する。円周率など定数を定義するときに便利。
enumは連続した整数を定義する。赤は1、青は2・・という風に、何かを数字で区別したい時に便利。

ID2ndID2nd2010/08/20 01:14Naoさん、アドバイスありがとうございます。
じつは、私もまったく同じように思っており、連続した整数の定義に enum を利用しようとしていました。

ところが、Apple のコードでは enum の代わりに const が利用されています。(エントリ本文の extern const CLLocationAccuracy から始まる 5 行が Apple のコードです。)

言語として誤りということではないでしょうし、あくまで、Apple の COCOA 用に記述するときの推奨事項なのだろうと予想しています。(時間さえあれば、調べて解明したい…)

ashura156ashura1562010/12/10 18:55Cでの enum と const の違いは
const - 代入できない変数(≒殆どのケースでシンボル付きの定数だと考えてよい)である事を示す型修飾子
enum - 型を持つ整数定数群。

enum を使う事で得られるメリットは型を持てる事です。必ずしも連番として定義する必要はないです。

typedef enum {

}Color;

ashura156ashura1562010/12/10 19:01失礼、途中で投稿してしまいました。続きを
例えば下記の様に enum を受け取る関数を定義することで、引数として特定のenum型の定数を期待することを明示できます。

typedef enum{
RED, GREEN,
}Color;

void setColor(Color color);

残念ながら C 及び Objective-C では enum は型の扱いが緩いので上掲の関数に int値渡してもコンパイルは通ってしまいますが。
(若干話題から逸れますが C++ ではキャストしないと int値は渡せません)

ID2ndID2nd2010/12/11 03:55
丁寧で分かりやすい解説をありがとうございました。

少々細かい話になってしまいますが、実は今回エントリに書いた 「 extern const CLLocationAccuracy kCLLocationAccuracyBest (略)」の Apple が書いたコードを見ているときに思い出しのが、まさに例示いただいた

 typedef enum{
  RED, GREEN,
 } Color;

の記述法でした。これと同じ様に

 typedef enum {
  best精度, better精度, low精度
 }

と書くのが最も自然であるように私には思えたのがそもそもエントリを書くきっかけでした。
 
今考えるとそう考えた背景には、constを使う場合には

 const hoge 1;

と何らかのイミディエイトな値を指定するのが一般的だ。数値を指定しないで const を使うのは不自然だ」という思い込みがあったからかもしれません。

ID2ndID2nd2010/12/11 03:56本題の話とは全く関係ありませんが、このテーマに多くの人がコメント寄せてくださるのを、かなり嬉しく思ってます。

所詮「どう書いたっていいじゃない」といわれてしまえばそれまでの話題で、ひっかかるのは私くらいかと思ってましたから。