Month: June 2015

Swift:tableViewSelectionDidChangeの注意事項

tableViewSelectionDidChange(aNotification: NSNotification)   を使うときとの注意事項です。

selectRowやdeselectRowを実行すると、その時点でtableViewSelectionDidChangeに飛んで行ってしまいます。そのときこれを実行させたくないなら、スイッチを用意してreturnする必要があります。そうでないと、カーソルが動かされたときの処理が行われます。

たとえば、カーソルを動かす➡︎その行位置の内容を表示するように動作する、という処理があるとします。

カーソルが動かされてtableViewSelectionDidChangeから処理が始まります。しかし、カーソルを動かしたところが表示したくないフォルダであったときに、次の行を選ぶと(selectRowを実行すると)、tableViewSelectionDidChangeに再度飛んで行ってしまいます。

スイッチのクリアはtableViewSelectionDidChangeでいいと思いますが、コードが読みにくくなるので、selectRowのあとにも入れてあります。

var mqSelectedRow:Int  = 0

func tableViewSelectionDidChange(aNotification: NSNotification)   {
 if cm.mqSelectedRow < 0 { 
 cm.mqSelectedRow    = 0 
 return 
} else { }

func ExecSelectRow(row:Int) -> Int {
 if row >= 0 && row < cm.wkArray.count  {
 cm.mqSelectedRow    = -1  
 xbTVFolder?.selectRowIndexes(NSIndexSet(index: row), byExtendingSelection: false)
 cm.mqSelectedRow    = 0  
 return row         
 } else  { return -9 }  

Swift:NSStringを使った文字列抽出

抽出結果がおかしい?

絵文字が入ったとき、substringFromIndexだと抽出結果がおかしくなったので、一文字ずつ抽出する方法に変更しました。pSourceの中の先頭pStringだけを除いて抽出する機能なのですが、どうなのでしょうね。ずっと前にも同じ問題が起きたように記憶します。

func CallRemoveHeadWords(pSource:String, pString:String) -> String {
 var words:String    = “”
 var inx:Int         = 0  
 for char in pSource {
  inx++  
  if inx > count(pString) { 
   words = words + String(char) 
  } else {  }             
  
return  words  
// var wTarget:Int = count(pString) 
// if wTarget > 0 && count(pSource) > wTarget {
// return (pSource as NSString).substringFromIndex(wTarget) as String
//} else { return  “” } 
}

追記12/27/2015: つい最近、解決方法がわかりました。

func CallPickupLastWords(pSource:String, pString:String) -> String {
let wInx:Int = pSource.characters.count – pString.characters.count
        if pString.characters.count > 0 && wInx >= 0 && wInx <= pSource.characters.count {
return (pSource.substringFromIndex(pSource.startIndex.advancedBy(wInx)))
}
else { return  “” }
}

Swift:再帰呼び出し(ループ)が一段落

再帰呼び出しをどう使うかでなく、再帰呼び出しの解析の仕方に時間がかかってしまいました。

前にも書きましたが、永久ループを引き起こす呼び出しと再帰呼び出しの区別がつかないことがわかり、解析に時間がかかりました。特に、同じfunc名内でなく、ネストになったどこかでそのfunc名を呼び出すケースもあり、単純にいきませんでした。

あと、再帰呼び出しのメソッド名が確定したあと、どうやって再帰呼び出しのメソッドを探すループから抜ければいいか、すぐに思いつきませんでした。結局、呼び出されたメソッド名と外部・内部の別、再帰呼び出しの有無を組み合わせたデータ構造を取る必要がありました。安直にスイッチやカウンタでループを回避しようとしたのですが、うまくいきませんでした。

それで、NSMutableArrayの三次元配列にデータ構造を変更することにしました。各アイテムへのアクセスは悪くなり、しかもコードが読みにくくなるのですが、常数をletで記号化することでまあまあの形に収まりました。

まだ機能追加したい項目がいくつかありますが、MesaEXIFを完成したあとに手がけることにしたいと思います。💢: リカーシブル。

スクリーンショット 2015-06-26 20.33.36

徒然:IHクッキングヒーター

ガスから電気に変えようとしています。

町田市か野田市に住んでいたとき、プロパンガスから都市ガスに変更になったことがあります。そのかすかな記憶が残っていて、ここのプロパンガスもいずれ都市ガスに変わるだろうとタカをくくっていました。

しかし、IHクッキングヒーターに変えれば、コストがセーブできる可能性があることがわかり、100V卓上型にするか、200Vビルトイン型にするか真剣に検討しました。結果、シャワー・風呂は当面ガスになるので、100V卓上型が妥当ということになりました。200Vにした場合、投資回収に時間がかかるのが問題のひとつでした。

それで、早速試してみたのですが、IHクッキングヒーターは速い、ということがわかりました。これは熱効率が高いからだそうで、電気代がガス代よりも安ければ、全面置き換えにするつもりです。

1,000Wセーブで動作するタイプなので、もう一台購入すれば、最大2セット同時に使ってもブレーカーは大丈夫です。

久々に嬉しいニュースでした。ただし、これで電気代がバーンと跳ね上がれば、泣きです。

Swift:もう一息のところ

モジュール構造図を描くツールがあと一息のところまで来ました。

再帰呼び出しは文法チェックをしていたのですが、入れ子になったところから再帰呼び出しがされた場合、ループ状態になることが判明しました。この原因系としては、再帰呼び出し、単なるループの二通りが想定されます。

安直に対処しようとした方法のすべてがうまくいかなかったので、結局、メソッドの中で呼び出されるすべての入れ子をチェックし、自分を呼び出していたとき、そこで処理を中断するようにしました。

想定外のところで再帰呼び出しのむずかしさを再学習しました。

また、ついでにNSMutableArrayについてかなりマスターできました。これは良かったです。

Swift:アプリの終わらせ方

Macはウインドウ閉じてもアプリを終了させたことになりません。

アプリを終わらせるには、次のようなラインを書く必要があります。実行は、viewdidloadのあと、AppDelegateに書いた次のコードが1 ➡️ 4 ➡️ 3 ➡️ 2の順番で実行されます。もちろん、printlnは確認のためのものです。

func applicationDidFinishLaunching(aNotification: NSNotification) {
 Insert code here to initialize your application
 println(“AppDelegate1 applicationDidFinishLaunching”) 
}  

func applicationWillTerminate(aNotification: NSNotification) { 
 // Insert code here to tear down your application
 println(“AppDelegate2 applicationWillTerminate”)
}  

func applicationShouldTerminate(sender: NSApplication) -> NSApplicationTerminateReply {
 // stuff and return stuff    
 println(“AppDelegate3 applicationShouldTerminate”) 
 return  .TerminateNow    
}           

func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool {
 println(“AppDelegate4  applicationShouldTerminateAfterLastWindowClosed “)
 return true  
}     

これはObjective-Cのときにはできていたのですが、Swiftになって曖昧になっていた懸案事項です。きょう、上記コードを改めて書く必要があり、確認したらこれでOKでした。

Swift:nilの判定?

コンパイルエラーをなくすことと実行時に意図通り動かせることは別の話。

もう少しで深みにはまるところでした。セルの中身がnilかどうか判定する箇所でまちがいを発見しました。

var wkArray:[NSDictionary]

if (cm.wkArray[inx][wIdentifier] as? String)  == nil { }

不正解
if (cm.wkArray[inx][wIdentifier]! as? String)  == nil! { }
if (cm.wkArray[inx][wIdentifier]! as! String)  == nil! { }

Swift:カラム幅の調整

全く理解できていませんが、なるほど!

カラム幅を設定するとき、次のように書けばいいことがわかりました。キャストするのがポイント。stackoverflowのコメントでは、as [NSTableColumn]となっていますが、Xcode6.3.2では、次のような書き方にしないといけないようです。ただし、その回答もこのキャストの仕方が妥当かどうか”?”という立場なので、そこは注意です。

@IBOutlet var   xbTVFolder: NSTableView?

for wcolumn in xbTVFolder!.tableColumns {
 (wcolumn as! NSTableColumn).width = CGFloat(200)
  (wcolumn as! NSTableColumn).maxWidth = CGFloat(200)
}

 

参考:How to set the width of an NSTableColumn in Swift …