Programming Notes
nacho4d avatar

Programming Notes

@nacho4d

Notes on git + github

I've been using SVN for quite a long time. Recently, started using git and github and really like it! I still need to take notes on some commands so this is what this post is about.
There is an excellent book but is too long to get it every time I need something. So here, I summarize what I believe are the most important/frequent things.

Installation

Download the installer from here or use MacPorts or Homebrew and issue:
# for MacPorts
$ sudo port install git-core +svn +doc +bash_completion +gitweb
# for Homebrew
$ brew install git-core

Setup

Required configuration:
#required:
$ git config --global user.name "firstname lastname" 
$ git config --global user.email nacho4d@nacho4d.com
Specially when working with github, these strings must be the same strings as the ones appearing in github Settings
Optional configurations that I find handy
#optional
$ git config --global core.editor emacs
$ git config --global merge.tool vimdiff
$ git config --global color.ui true 
$ git config format.pretty oneline

To see settings inside /etc/gitconfig and ~/.gitconfig do:
$ git config --list

Creating a repo from scratch

$ cd My/LocalRepo/Directory/
$ git init
$ git add *.m 
$ git add README.txt 
$ git commit -m 'This is the message for the first commit'

Creating a remote repo in github

Follow the instructions in github.
(**Warning**: Github needs a README file to show the project correctly on the web. Make sure you have one)

Cloning a repo from github

Get the address of the repo from github and enter like so:
$ git clone git://github.com/schacon/grit.git

File lifecycle

Explaining the lifecycle is not easy (specially if you come from SVN). But I think below explanation is not incorrect :)
  • Untracked: when a file is not version controlled by git
  • Unmodified: when the file is controlled by git and is not modified since the last staging
  • Modified: when the files is controlled by git and it was modified since the last staging
  • Stagged: when the file is in the index, git commit only commits stagged files

Staging a file:

The add command also is for staging not only for tracking files
$ git add filename.txt
$ git status

Ignoring file:

$ cat .gitignore 
*.[oa]     #ignores .o and .a files
*~         #ignores files that end in ~
build/     #ignores build directory
doc/*.txt  #ignores txt files inside of doc directory, is not recursive
(Glob patterns are accepted)

Seeing stagged and unstagged changes
$ git status
$ git diff
$ git diff --cached
$ git diff --stagged

Committing

$ git commit
and enter the message in the editor. Or:
$ git commit -m "message for this commit" 
Or: just commit everything (including not staged files)
$ git commit -a -m "message for my commit with -a option"

If a file was forgotten you can always amend current staged files to the last commit
$ git add forgotten_file.txt 
$ git commit --amend
# and to change the commuter date too:
$ GIT_COMMITTER_DATE="`date`" git commit --amend --date "`date`"

Removing files

$ rm fileToRemove.txt
$ git rm fileToRemove.txt
and remove a file only from the stagged are
$ git rm --cached readme.txt

Working with Branches

# list of local branches
$ git branch

# list of all (local and remote) branches
$ git branch -a

# list of remote branches only
$ git branch -r
Create a local branch named uiFixes (from current branch). Then rename it to ui-fixes, check it out, commit something to it, publish it and finally delete it from the remote
$ git branch uiFixes
$ git branch -m uiFixes ui-fixes
$ git branch ui-fixes
$ git checkout ui-fixes
$ git branch
... some changes happened here ...
$ git commit -am "fixes where done"
$ git push origin ui-fixes
... now others can see/use/merge,etc this branch
$ git push origin :ui-fixes

Tagging

Create a tag v1.0 and push it to the remote. Then push all tags.
Delete tag v1.0 from local repository and finally delete it from the remote.
If a branch is not merged it cannot be deleted so in that case you can force it with -D option
$ git tag v1.0
$ git push origin v1.0          
$ git push --tags               
$ git tag -d v1.0
$ git push origin :refs/tags/v1.0

Renaming a branch:
Create a new tag with that references to the old tag then delete the old one.
# create the new tag
$ git tag new_tag old_tag
# delete the old tag locally
$ git tag -d old_tag
# delete the old tag from the remote
$ git push origin :refs/tags/old_tag

Checking out a tag:
# Create a branch and checkout
git checkout -b 1.6 refs/tags/v1.6
# Just checkout out the tag
# (Useful when looking at it and no changes are planned to be done)
$ git checkout refs/tags/v1.6

Logging

Shows a list of commits:
# Show last 10 commits
$ git log -n 10

# Show commits with a graph
$ git log --graph

# Compact 
# git log --graph --pretty=oneline --abbrev-commit

Diffs

compare a file with current HEAD
$ git diff file.h

Stash

# stash current changes without a label
$ git stash
# stash current changes with a label
$ git stash save "Put a message here"
#
# stash only unstaged (or non-added) changes
# Note that newly created (and non-added) files will remain in
# your working directory. Also, your working directory must be
# clean (i.e. all changes need to be added) when you `git stash
# pop` later on.
$ git stash -k

$ ...

# list of all stashed things
$ git stash list
# will show something similar to:
stash@{0}: On feature/52: Put a message here
 
$ ...


# Apply the stash to the current branch
$ git stash apply 
# Apply and remove it from the stash list
$ git stash pop

$ git stash clear

Misc:

# show info about remote branches
$ git remote show origin
# export last commit in the current branch
$ git archive -o latest.zip HEAD

Rebase

# interactively rebase (change/modify) the last 4 commits:
$ git rebase -i HEAD~4

# Mainly I use it for:
# "squash" various commits in a single one
# "reword" the message of the commit

# forced push of a branch (not merging)
$ git push origin feature/new-feature -f



Patches

# Make a patch of a certain commit:
$ git format-patch <SHA>^..<SHA>
# It will create a file, let's say: file.path.

# Check the changes that are in the path:
$ git apply --stat file.path

# Apply the patch
$ git apply file.path
# or
$ git am file.path

Update your fork from Original repo

# Add (additional) remote
$ git remote add --track master mleung git://github.com/mleung/feather.git
# 'master' is the tracking branch and 'mleung' is the tracked branch from the given repo

# verify 
$ git remote

# get lattest changes from mleung
$ git fetch mleung

# merge those changes (mleung/master) into your current branch
$ git merge mleung/master

Gitflow, etc

# check out "develop" remote branch and then start git flow
$ git fetch
$ git checkout -t origin/develop
$ git branch

# initialize git flow
$ git flow init

# publish and track "develop" manually
$ git push origin develop
$ git branch --set-upstream develop origin/develop
$ git remote show origin

# feature start and finish
$ git flow feature start markdown-links
$ git commit -am "markdown now shows links in blue color"
$ git flow finish markdown-links

# hotfix start and finish
$ git flow hotfix start my-hotfix
$ git commit -am "I have solved a really serious bug"
$ git flow hotfix finish my-hotfix

TODO:

creating and merging local branches (?)
merging and pushing to remote repository (?)
git merge (?) not only to master branch but to any branch
git revert (?) to any point in the past
git reset (?)
git remote (?)
git help **commmand**(?)


References:


Grand Central Dispatch

最近、研究のPCのプログラムをiPhoneに移植することに挑戦していてマルチスレッドプログラミングを授業とかでやったが実践で使うのは初めてで、色々と勉強になったから 参考になったもののまとめとしてこの記事を書くことにした。
色々と忘れそうで...

以下GCDと呼ぶGrand Central DispatchはMacOS 10.6から使えてブロックを使いまくるライブラリです( 笑)WWDC2009に参加したときブロックの話が多くてイメージしていたが実際に使う機会がなくて やはり研究の様な重い処理や時間が掛かる様なものじゃないと使うまでもないし-[NSObject performSelectorOn...]やNSOperationなどがあって低レベルのブロックを普段使うまでもありませんね。
WWDC2010ではGCDで盛り上がった.GCDはオプンソースになって現時点でMacOSとiOS以外に実装したOSはFreeBSDのみ

特に参考になったサイトは:
などなど


では、

インポート

まず、GCDはフレームワークではない、dylibなので
#import <dispatch/dispatch.h>
と書くだけでGCDのAPIが使える。

キューの作成

  • メインキュー : メインスレッドで実行
    dispatch_queue_t main = dispatch_get_main_queue();

  • グローバルキュー : バックグラウンドで実行
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
    //priories:
    //DISPATCH_QUEUE_PRIORITY_HIGH
    //DISPATCH_QUEUE_PRIORITY_DEFAULT
    //DISPATCH_QUEUE_PRIORITY_LOW

  • プライベートキュー : バックグラウンドで実行、名前付きのキュー
    dispatch_queue_t queue = dispatch_queue_create("com.nacho4d.myApp.myQueue",NULL);
    デフォルトではプライオリティは DISPATCH_QUEUE_PRIORITY_DEFAULT だが変えることが出来る:
    dispatch_queue_t high = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,NULL);
    dispatch_set_target_queue(queue,high);
    

    他のタイプのキューとの大きな違いはブロックや関数が逐次的に実行されていくこと。他のキューではタスクをエンキューしても実際にどの順番で実行されるかが分からないが、プライベートなキューでは必ずキューの頭からタスクを実行していくのでシリアルなキューを実現できる。
    プライベートなキューを作成するとRetainカウントが1なので、 最後にリリースをすることを忘れずに
    dispatch_release(high);
    

キューの停止

停止できるが、実行中のブロックを止めることができません。停止がその次のブロックから適用される、つまりNSOperationQueueのsetSuspended:と全く同じ
dispatch_suspend(queue);

非同期と同期

実行するキューを指定し、ブロックを非同期的にまたは同期的に実行
dispatch_async(queue,^{/* 非同期 */});
dispatch_sync(queue,^{/* 同期 */});
例:
dispatch_queue_t queue = dispatch_queue_create(“com.app.task”,NULL)
dispatch_queue_t main = dispatch_get_main_queue();

dispatch_async(queue,^{
 CGFLoat num = [self doSomeMassiveComputation];

 dispatch_async(main,^{
  [self updateUIWithNumber:num];
 });
});
または
dispatch_queue_t queue = dispatch_queue_create(“com.app.task”,NULL);

__block CGFloat num = 0;

dispatch_sync(queue,^{
 num = [self doSomeMassiveComputation];
});

[self updateUIWithNumber:num];

ブロックを後で実行

-[NSObject performSelector:afterDelay]などのメソッドの代わりに使えるdispatch_after関数がある.利点:メソッドは不要

void dispatch_after(
   dispatch_time_t when,
   dispatch_queue_t queue,
   dispatch_block_t block);

例:0.3秒後にメインスレッドでブロックを実行する(UIKitのUITextViewを扱うのでメインスレッドに変えている).
dispatch_after(300, dispatch_get_main_queue(), ^{
        UITextView *textView = (UITextView *)[controller.view viewWithTag:12345];
        [textView removeFromSuperview];
        textView = nil;
    });

Forループの並列化

重い処理を分けて行って高速化を!
void dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)(size_t));
例えば、CoreVideoのイメージバッファーの中から特定なチャネルだけコピーしたい場合は普段このように行うでしょう:
uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
size_t width = CVPixelBufferGetWidth(imageBuffer); 
size_t height = CVPixelBufferGetHeight(imageBuffer); 

char *imageData = llahProcessor.inputImageDataBaseAddress;
int stepWidth = width*3; //stepWith of output image
for (int j = 0; j < height; j++) {
 for (int i = 0; i < width; i++) {
  int out_pixIndex = j*stepWidth + i*3;
  int in_pixIndex = j*bytesPerRow +i*4;  
  imageData[out_pixIndex]   = baseAddress[in_pixIndex]; //B
  imageData[out_pixIndex+1] = baseAddress[in_pixIndex+1]; //G
  imageData[out_pixIndex+2] = baseAddress[in_pixIndex+2]; //R
 }
}

しかし、dispatch_apply関数を用いて並列化を行うことができます:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_apply(height, queue, ^(size_t j) {
   for(int i = 0; i < width; ++i ) {
    int out_pixIndex = j*stepWidth + i*3;
    int in_pixIndex = j*bytesPerRow +i*4;
    imageData[out_pixIndex]   = baseAddress[in_pixIndex]; //B
    imageData[out_pixIndex+1] = baseAddress[in_pixIndex+1];//G
    imageData[out_pixIndex+2] = baseAddress[in_pixIndex+2];//R
   }
});
GCD並列処理を行っているので理論上では早いですが、例えば640x480の画像でforループの480個を同時に走らせとうしている!つまり実際に並列処理をするには480個のキューが必要だがそんな膨大な数のキューを作るには少し時間が掛かるしおそらく全部作れないのでエンキューされるforループのあるでしょうし 640x480の画像を処理を一瞬で終わるのでこの例は現実的ではないですえ。dispatch_apply関数の使い方だけに着目してください。マルチスレッドの話は難しくて長過ぎて教科書を読むが一番ですね

シングルトン

Colin Wheeler氏が指摘するようにブロックを使ったシングルトンの方がマルチスレッドセフティでその為に dispatch_onceを使います. dispatch_onceはアプリケーションが実行している間に一回のみ実行されると保証してくれる関数で便利ですね。
+(MyClass *)singleton {
 static dispatch_once_t pred;
 static MyClass *shared = nil;
 
 dispatch_once(&pred, ^{
  shared = [[MyClass alloc] init];
 });
 return shared;
}
まぁ〜 これでGCDのことをちょっと忘れたときにちらっと見れば思い出すかと ... うむ

怠け者の為のObjective-Cのメモリ管理

私はメモリ管理関連のの記事を沢山読います.特にiPhone開発初めてからリークなきクラッシュなきアプリの開発に心掛けた。(モバイルデバイスだから下手に扱うとすぐメモり不足の警告が出されたりするから)

そして、最近ツイッターでこの記事(英文)を見つけたので、簡潔で非常に分かりやすくて日本の方に是非読み頂ければという意思でこの記事を翻訳することにした.(簡潔で非常に分かりやすいですよ!)
私はネイティブではないので、おそらく間違っているところがあるだろうが、エッセンスを理解して頂ければと思う.(→最近友人に見てもらって色々と修正をしてくれたので大感謝!)



James Gregoryさんが想像しているよりObj-Cでメモリの管理は簡単

メモリ管理はということばを聞くとスクリプティングする若者たちとJava世界の人が怖がることを私は知っています。でも、実はそんな怖くないんだよ。詳細を言う前にJames Gregoryさんはどう思うかを見てみよう.


iPhoneにないの?!。マジ、アップルよ 一体なんだよ!? ガーベージコレックションがなぜそんなに凄いかと説明しようとするギークが沢山いるから、ここは短く言う。すばらしい理由が基本的に2つある.
一つ目、さらに他の言語のメモリのオーナーシップ(所有権)、いつリリースするベキかとかを理解する暇はないから.
二つ目、開発言語の特徴の中で 開発のプロセスを最も加速するガーベージコレックション(GC)の他に思い当たらないからだだ.
アンドロイドにはあるし、ハードウエアに直接関係しているプログラム以外(つまり、ほど全て)の場合は効率的だ。初代のiPhoneにはなかった理由が分かるかもしれないが 最近のiPhoneにない訳ないだろう。メモリ管理があまりにも大変でこれだけで初心者の開発者にiPhoneよりはアンドロイドを始めることを薦めると思うよ.



えっ!? それは違うよ。メモリ管理について怠け者たちが、大変だと誤解しているんじゃないかなぁ〜。

「さらに他の言語のメモリのオーナーシップ(所有権)、いつリリースするベキかとかを理解する暇はないから」というのは、デベロッパーがめんどくさいな と思っているだけじゃないかなぁ〜。

オブジェクト指向的なメモリ管理の基本は一緒。C++やらObjectPascalでもGCなしの言語なら みんな一緒だ. コンピュータサイエンスの基本の概念でObjective-Cに使うのはほぼささいなことだ.

もし、私は面接官で面接受けている人がそういうこと言ったら、その時点で面接が終了したなぁ、きっと.

しかし、私はGCがあるべきだと思うよ. GCの利点が知らなかったり、分っていないと勘違いしないでください。だから「手動のメモリ管理が大した苦労ではない」というときに あなたはそれを聞いた方がいいと思う。特にObjective-Cでは.

デスクトップのCocoaで開発する(私は結構書くなぁ)ときにCGを使うときがある. プログラムが少し大きくなって、ちょっと調べたり研究したりしているときにCGを使うことが多い。一旦自分が調べたことや試していたことが証明できたらCGを無効にして、全てをリファクタリングするから.

だから、時々GCを使うなら、いつも使えばいいじゃ〜. メモリの管理しなくてもいいから. それにプライベートフレームワークを作って再利用する傾向があるから、それらを動かす為にCGが無効になっているか有効になっているかを見なくてもよくなるし.

Objective-Cのretain/releaseの仕組みは 根本的なメモリ管理とGCの中間的な仕組みだから. C++とかと違って実際にオブジェクトをfreeするわけではない.代わりに「僕は このオブジェクトを使い終えたよ!」と言ってやって あとランライムに任せばいい.




基本の4つのルール

Objective-Cを学ぶときに覚えなければルールが4つだけ.
  • オーナーシップを持つなら、リリースするベキ
  • オーナーシップを持たないなら、リリースしちゃダメ
  • 自分のクラスの実装でdeallocをオバーライドし、オーナーシップを持ったものをリリースするベキ
  • deallocを直接呼び出すベキでない
それは全てだ. 上の2つが最も重要で オーナーシップの基本を次に説明する.

ルール1: オーナーシップを持つとき

Objective-Cでは オブジェクトをallocか、initか、newをしたらオーナーシップを持つころになる.例えば、


簡単だね、これより詳細な説明も思いつかないぐらい。しかし、確認の為に
allocしたらオーナーシップを持つことになる.
copyしたらオーナーシップを持つことになる.
newしたらオーナーシップを持つことになる.(newはalloc/initのショットカットだけ)
〜〜〜Jamesさん、もしまだ読んでいたら 既に4分の1を終えているから、もう少し読んだらソフト掛けるようになるゼ〜〜〜

ルール2:オーナーシップを持っていないとき

これはちょっとややこしいんだ. もっていないときはもっていないんだよ. だから、もしalloc/init/newいずれもしていなかったら 持っていないのだ. 次の例を見てみよう:

そのNSStringのオーナーシップを持っている?いいえ、alloc/copy/newもしなかったから持っていない.
そのNSImageは?はい、持っている.allocしたから.
そして、そのNSData? これも、いいえ. alloc/copy/newどれもしなかったからだ.
ちなみに、本当はこう直すベキ:

〜〜〜そうだね、GCより遥かに大変だわ! 普段ココアの開発者はどういうふうにやってんの?〜〜〜

ルール3と4: dealloc

これは一番大変なところだ. クラスの中にretainしているインスタンス変数があったら、オブジェクトがdeallocされるときにそれらのインスタンス変数をreleaseしないといけない.これを示すのは次の例:

上記の例では、SomeObjectは二つのインスタンス変数がある. thingsとsomeOtherThingsだ. initメソッドを見て分かるのは 二つをオブジェクトを生成して、それらをインスタンス変数にアサインしていること.
thingsに関しては [NSMutableArray arrayWithObjects]を使っているからretainを呼び出す必要がある. alloc/copy/newいずれもしない. autoreleaseしたオブジェクトを返すコンビニエンスメソッドを使ったから 明示的にretainをしなければいけない. autoreleaseしたオブジェクトとは何かと思っているかもしれないが それはその次に説明する. とりあえず、上記に説明したメモリ管理の基本だけを頭に入れておいてください.
deallocメソッドに 生成したオブジェクトをリリースしているだけです。それ以上はなにもありません.
(ちなみに、コンビニエンスメソッドとは:alloc/init/newで始まらないオブジェクトを生成してくれるメソッド。例: [NSArray array]はコンビニエンスメソッド、[[NSArray alloc] init]はコンビニエンスメソッドではない。ご存知の通り、コンビニエンスというのは便利の意味を持っていて、releaseしなくてもいいから便利という理由で名前持っているらしい. @nacho4d)


プローパーティ

Objective-C 2.0はプローパティーを提供してくれる.その詳細はここでは話さないが プローパーティのライフサイクルの中で混乱が生じやすいところがあるので 少しだけ触れたいと思う. ルールは2つのみ
プローパティーの属性はretainまたはcopyだったら deallocにnilをセットするベキ.
initメソッドなどでプローパーティを初期化(init)しているならば autoreleaseにするベキ.
例を見てみよう.


titleプローパーティに関して NSStringのコンビニエンスメソッドを使って生成しているからautoreleaseしたオブジェクトが返ってきて 何もする必要がありません.
subtitleプローパティーに関して 私たち、自分で、オブジェクトを新しく(alloc/initを使って)生成しているのでautoreleaseをする必要があります.
理由はこれから説明します. alloc/initを使ってretainカウントが1になり、subtitleにアサインすると一個増えるので2になってしまう. autorelease無しで行うとリテインカウントが決して1に戻らなず メモリリークが発生してしまう. だからautoreleaseを入れることで リテインカウントが1個減らしている.

オートリリースとは?

実は完全に嘘をついた、完全に.これは実は結構複雑な仕組みで その複雑さはオートリリースプール(Autorelease pool)という形で来ている。それは一体なんだ? オートリリースプールはreleaseメッセージを送られる対象オブジェクトのリストを持っている。いつ送られるかというとプール
は破壊される(destroyed)また排出させた(drained)ときです。 しかし、それはいつ起きるかを気にしなくても大丈夫です. 正しくautoreleaseメッセージを送っておければ オブジェクトがちゃんとリリースされるからだ.

さて、基本のルールに従って行えば オブジェクトを返すメソッドについての疑問がある筈だなぁ。このオブジェクトのオーナーシップを誰が持っているの?ここはオートリリースプールの出番だ.
例えば:

そのNSImageのオーナーシップを誰が持っている? ここはねぇ、この例では、メッセージを送ったオブジェクトはオーナーシップを持つことになる.よって送られた側にreleaseメッセージを送る必要がある。しかし、これは悪い例です.正しいのは次のよう:

Autoreleaseメッセージが最後にあることをに着目しよう.autoreleaseをすると そのオブジェクトがオートリリースプールに追加され poolが破壊されるときに releaseメッセージが送られます.
(なぜ一個上のが悪い例でこれは良い例かという説明を次にします。
実はメモリ管理の観点から見ると両方とも問題はありません。後でreleaseするか、さきにautoreleaseをするかどっちも一緒です。
しかし、前者の方がCocoaのコンベンションの一つに違反しています。 
私は上に書いたコンビニエンスメソッドの定義によると、alloc/init/newで始まるメソッドを送るとオーナーシップを持つことになります。
逆に言えば、そうで始まらないメソッドを送るとオーナーシップを持たないことになりますね。そして、getAnImageは何かの形でオブジェクトを生成しています。かつ、alloc/init/newで始まらないから コンビニエンスメソッドですよね?こう言ったコンビニエンスメソッドが CocoaのコンベンションによるとAutoreleasedオブジェクトを返す筈だよね?、だから コンベンションに従って書くようにしましょう. @nacho4d)

オートリリースプールの中にさらに別のオートリリースプールはあってもいいので、大量の一時的なオブジェクトを生成するときに便利. そして、もしマルチスレッドの処理をしていれば、新しいスレッド用のオートリリースプールを作る必要があります.

まとめ

思ったより、そんな怖くないし、複雑ではなかろう. 勿論GCを全然簡単だが、例えGCがあっても手動メモリ管理に向いている処理が沢山があって、手動メモリ管理がメーディアやゲームなどのアプリケーションでもっとも使われている。
このようなアプリケーションにはメモリ管理は極めて重要な役割で、知らないとうまくいかない場合が沢山あるよ. ありがたいことに CocoaとObjective-Cを使うとそんなに苦労しなくて済む.

参考文献

実はアップルのドキュメンテーションで十分な筈だが、すばらしい記事が沢山かあって...
などなど...

More Web OS programming - Adding Models, Views, Controllers to your project.


In WebOS programming everything is about conventions, you create a  certain assistant in the predefined folder with a predefined name. The same for models, views, stylesheets, etc.
This makes the app structure very simple ;)

This is the continuation of the last post so here I go again...

Creating Assistant (or Controllers), Scenes (Views) and Models

In WebOS each scene needs an assistant. Hence creating a scene creates a view and its controller at the same time:

$pwd
/Users/nacho4d/Documents/palmWorkspace
$palm-generate -t new_scene -p "name=myView" Superapp

which means: generate a new scene for Superapp project using the template new_scene and its name is going to be myView.

palm-generate will create a myView-assistant.js file inside Superapp/app/assistants directory and a myView-scene.html file inside a new myView directory inside app, like so:
Superapp/app/myView/myView-scene.html
and finally will add the path of both new files to Superapp/sources.json file. If you prefer it, you can do this process manually and everything will work and give you the possibility of customizing names and places of your new files ;) But that is beyond this post.

There are 4 templates for palm-generate (-t option) and the default is new_app

hello_app        Generates a new application containing a "Hello World" scene.
hello_scene     Generates a "Hello World" scene.
new_app         Generates a new (empty) application.
new_scene      Generates a new (empty) scene.

We do the same process for Models, but manually since there is no template in palm-generate for this.

Create a directory models inside app.
Create a myModel.js and add its path to sources.json file.

So if you create a boxView and its assistant (or controller):
$palm-generate -t new_scene -p "name=boxView" Superapp

and created a box model:
$cd Superapp/app
$mkdir models
$cd models
$touch box.js
$cd ../../
$open sources.json -a Coda.app
then add box.js path like so:

[
    {
     "source": "app/assistants/stage-assistant.js"
    },
    {
        "scenes": "boxView",
        "source": "app/assistants/boxView-assistant.js"
    },
    {
     "source": "app/models/box.js"
    }
]

finally your project should have the following structure:


Be carefull and not make mistakes specially in the paths. (It took me one hour to realize the reason my app was not loading correctly was I missed adding the ','  after the second element of the array in sources.json!! lol)

Web OS programming - My very first Palm Pre 2 app (that really does nothing!)

I find programming model in WebOS very intuitive and easy. I really like it and even though I have no real device to test anything, there is an emulator and I think is very complete (probably better than the first iPhone Simulator app)

These are some notes on how to create Palm Pre apps using Terminal in the Mac but this should not be different in any other Unix like OS.
There is a Eclipse Plugin that should make things easier but I don't like very much Eclipse, is kind of sluggish, I prefer Xcode or NetBeans but there are no Web OS Development official plugins for these IDEs now. So my best choice is Terminal + Coda (Coda is awesome!!).
Moreover, Coda has Terminal inside of it so no need to really open Terminal.app in the Mac.

  • Download and install the SDK and Emulator (needs Virtual Box), follow instructions from here
  • Open the terminal and do:
//Step1: create a workspace directory
$mkdir palmWorkspace
$cd palmWorkspace

//Step2: create a project with name HelloWorld
$palm-generate -p "{title:'Hello World', id:com.nacho4d.hello, version:'1.0.0'}" HelloWorld
generating new_app in /Users/nacho4d/Documents/palmWorkspace/HelloWorld

//Step3: package the project (something equivalent to building an iPhone app)
$ palm-package Helloworld
creating package com.nacho4d.hello_1.0.0_all.ipk in /Users/nacho4d/Documents/palmWorkspace

//Step4: install the packaged project in the connected device, if none then install in the Emulator *4
$palm-install com.nacho4d.hello_1.0.0_all.ipk 
installing package com.nacho4d.hello_1.0.0_all.ipk on device "emulator" {41270192eca5e9403d535ba2f9e40b4483cda4ac} tcp 50997

//Step5: start the app
$ palm-launch com.nacho4d.hello               
launching application com.nacho4d.hello on device "emulator" {41270192eca5e9403d535ba2f9e40b4483cda4ac} tcp 50997

//Step6: close your app through a command. 
$palm-install -c com.nacho4d.hello_1.0.0_all.ipk
closing application com.nacho4d.hello on device "emulator" {41270192eca5e9403d535ba2f9e40b4483cda4ac} tcp 50997 


Now, regarding...

Step 2: palm-generate [OPTION...] APP_DIR
palm-generate -p option is optional. Hence, you could do $palm-generate HelloWorld and would create an app with title: HelloWorld id:com.yourdomain.helloworld and version:1.0.0.

Step 3: palm-package [OPTION...] APP_DIR
I said this step is something like building an iPhone but I don't think you will get any errors here. everything is HTML and Javascript so, you have to validate/check your code by yourself.

Step4: palm-install [OPTION...] [PACKAGE | APP_ID]
If your are using the emulator, you must start it manually(palm-install won't start it for you) but , starting it just before running this command probably will end in something like this:

$ palm-install com.nacho4d.hello_1.0.0_all.ipk 
palm-install: no devices found
palm-install: no device found

The first message is for real devices and the second is for the emulator. It seems that the emulator is not immediately available just after starting it. So, better start it at packaging time.

Step5: palm-launch [OPTION...] [APP_ID]

Step6: you can also close the app using the Emulator by swiping your app up. (I am very new to PalmPre and I didn't knew this ;) )


If your are using Coda, then do everything inside its built-in terminal!



You can even open the your workspace directory from its terminal, So won't even need the Finder. ;)

$cd palmWorkspace/
$open . -a Coda.app
... and do as usual ;)






Universal Ports


This is just a note for myself rather than a post... is just I always forget this:

sudo port upgrade --enforce-variants portname +universal

where portname should be replaced appropriately.

Notes on Memory Management in 
Objective-C - FMM(Frequently made mistakes)

To understand memory management is one thing (if it's no THE thing )you will be happy to know if you are or aim to be developer.
Cases like: developing a big project in mobile devices like the iPhone and then you realize you are running out of memory or  writing a simple app that suddenly crashes!
These might take hours of debugging to solve and I remember myself not so long time ago thinking - I wouldn't have this problem is I knew memory management rules well from the beginning -.

Everything remains in the object's retainCount and its ownership. This is what I am reviewing here.

Initializing Objects:
You can initialize an object using a alloc init methods, like:

NSArray *myArray = [[NSArray alloc] initWithObjects:@"Obj0", @"Obj1", @"Obj2", nil];
... do something with myArray
[myArray release];

or you can do it by using class methods or many convenience methods to create the object you want (without using alloc init).


NSArray *myArray = [NSArray arrayWithObjects:@"Obj0", @"Obj1", @"Obj2", nil];
... do something with myArray


So, what is the difference?
When you use alloc/init to create an object you own it. Owning and object or having its ownership implies that you are responsible of releasing it. When using init method the object is initialized and its retainCount is set to 1 and the system won't release it for you.
An object can be owned by one or more objects, implying that each of these owners must release it.

When you use one of many convenience methods like -arrayWithObjects: to create you object, you don't own that object. Why? Initialization might be the same, but the difference is that object will be added to an auto-release pool. Hence when the pool gets drained your object will be released also. (Actually, objects are often released earlier when they are not needed anymore)

That was the super easy part.  Now let's see how to pass an object we created to other objects' property.

Retain, assign or copy?

Consider the following code:
@interface UITextView : UIScrollView{



...
}

@property(nonatomic,assign) id delegate;;
@property(nonatomic,copy) NSString *text; 
@property(nonatomic,retain) UIFont *font;

@property (readwrite, retain) UIView *inputView;  


This is part of UITextView class in iOS SDK. Suppose we have an instance textView.


UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];

First, what everybody knows:


  • Retain: the passed object will be retained (its retainCount will increase generally by 1). Here,  textView will own the objects passed to font and inputView property.

  • Assign: the passed object will not be retained, (This is the default). If you don't set explicitly "retain" or "copy" then "assign" attribute will be assumed.

  • Copy: the passed object will be copied (generally a deep copy) Hence textView will own the object passed through text property. But the passed object and the retained object would be the same. When you have a deep copy it does not matter how you change the object from outside textView, it won't have effect, because it not same object as the one stored by text property. It's a mere copy.

Now we are fine with the theory, consider the following examples:

//A
UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[self.view addSubview:textView];
[textView release];
//B
NSString *myText2 = [[NSString alloc] initWithContentsOfFile:@"myTextFile.txt"
encoding:NSUTF8StringEncoding
  error:nil];
textView.text = myText2;
[myText2 release];
//C
textView.text = [[NSString alloc] initWithContentsOfFile:@"myTextFile.txt"
encoding:NSUTF8StringEncoding
  error:nil];
//D 
for (int i = 0; i < 100; i++)
textView.text = [[NSString alloc] initWithContentsOfFile:@"myTextFile.txt"
encoding:NSUTF8StringEncoding
  error:nil];
//E
UIView *keyboard = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 216)];
textView.inputView = keyboard;
[keyboard setBackgroundColor:[UIColor redColor]];

[keyboard release];
//F
textView.inputView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 216)];
//G
textView.inputView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 216)] autorelease];
//H
textView.text = [NSString stringWithContentsOfFile:@"myTextFile.txt"
  encoding:NSUTF8StringEncoding
error:nil];
//I
for (int i = 0; i < 100; i++)
textView.text = [NSString stringWithContentsOfFile:@"myTextFile.txt"
  encoding:NSUTF8StringEncoding
error:nil];

//J
MyDelegate *myDelegate = [[MyDelegate alloc] initWithSomething];
textView.delegate = myDelegate;
[myDelegate release];
//K
MyDelegate *myDelegate = [[MyDelegate alloc] initWithSomething];
textView.delegate = myDelegate;

//L
textView.delegate =  [[MyDelegate alloc] initWithSomething];


Some of these are very silly, a couple of them is just to show memory leaks in Instruments, but I see very often people write code like this in some programming boards and they are very illustrative.

A is just the initialization of our instance. This is not about properties.

B, C, D are samples regarding "copy" property attribute. This is the case of text property.

B is correct. Allocate and initialize myText2 (retainCount is 1), is then passed through text property then is copied, and since needed no more it's released. No leaks, we are fine.

C is wrong. You might be tempted to shorten your B code like C but this will cause memory leaks.
Reason: When you allocate and initialize your object it will have retainCount 1 and right after that it is passed through text property then is copied and you don't have a reference to release!.  This will be be more clearer in D.

D is just for illustrative purposes, you surely never want to do this. I did this just to make the leak very obvious in Instruments.
This is what I got in Instruments: pretty bad huh? Got 5 MB leaking (since my file size is 5KB)

Fig 1: Instruments showing leaked memory.


E and F are samples regarding "retain" property attribute. This is the case of inputView property.

E is correct, is basically like B, just this time keyboard is not copied, is the same object with it's retainCount increased. The big difference with copy is that if you change keyboard after you pass it to  textView.inputView it will do have effect on textView 's input view because is the same object.

F is wrong, is very similar to C, just this time the object you created using alloc and initWithFrame: methods is the same as the one stored through inputView property. Hence you have a reference and could solve this leak later (by doing [textView.inputView release];) but it will be ugly to my taste.

G is correct, this is what you want if you want to shorten E or correct F. I would use E rather than G.

H and I are samples regarding retain/copy but when using not owned objects. (object that will be autoreleased by an auto-release pool)

H is fine. In C, the bug was that object created just before passing it thought text property would not be released, but using the convenience method: -stringWithContentsOfFile:encoding:error: instead of initWithContentsOfFile:encoding:error: the problem is solved.
Why? when using those convenience methods the object returned is automatically polled in the most recent autorelease pool.
How do I recognize a convenience method? the rule is simple: if the word "init" is present in the method name (signature) then you will have the ownership of the object, meaning that you have to release it by yourself. Otherwise, is a convenience method, you will not have the ownership of the object because it will be added to an autorelease pool. You don't need to release it.

I is just to show that using this approach won't leak memory as D
This is what I got in Instruments:

Fig 2: Instruments showing allocation of first 100 text objects (starting the app).
Fig 3: Instruments showing released objects (app is already started).


Since I am allocating 100 times the same object then Allocations instrument shows a big amount of memory allocated at the beginning (shown in Fig 2). But since that memory is owned by the system, is drained when is not needed anymore (when the app finished loading), as shown in Fig 3

J,K and L are to show "assign" property attribute.
Assign behaves like retain in the sense is the same object (not a copy) is stored. The difference is that the object passed is not retained.

J is not wrong from the memory management point of view, but is not what you want because textView property will not retain myDelegate object. Hence releasing myDelegate right after setting the delegate through inputView property is meaningless, because the object will be deallocated.


K is what you want to do instead of J. This is correct.

L is the shortened version of K, since delegate property attribute is assign, textView will not retain myDelegate. Hence allocating and initializing and object and passing it is not a problem like in C or F.

So why assign this useful? it depends on your needs actually. The most famous usage is a delegate.
If object X retain an object Y that retains X, both objects will never be released, this is also a memory problem. you create objects that cannot be released. In this case assign becomes useful.

With this I've finished this quite long post. I hope it helped a little bit someone.
Actually I wanted to write also about how to write your own classes with properties, how to properly initialize and release them, but this post is too long already. A new post is better ;)



TODO:
Designing/Making/Using your own classes with properties

in UIViewController/ NSWindowController
in loadView/viewDidLoad
address problems like
NSString *string = [[NSString alloc] init];
string = [otherString stringByAppendingString:@"asd"];

NSString *string = [NSString string];
string = [otherString stringByAppendingString:@"asd"];

NSString *string = [otherString stringByAppendingString:@"asd"];

view didUnload:
self. retainProperty = nil;
[retainProperty release];
assignProperty = nil

in dealloc
[retainProperty release];
assignProperty = nil;
[copyProperty release];



This work is licensed under BSD Zero Clause License | nacho4d ®