2013年7月5日 星期五

讓 iOS App 優雅的 Crash 吧!


開發 iOS App 最害怕的一件事就屬上架審核了!

不僅要讓 Apple 恣意的玩弄 App 所有的功能以外,更令人尷尬的事情是 - Bug 總會在這時候爭先恐後的冒出來,造成 crash reject(註1:教育訓練定理)。

如果剛好這些 Bug 們生性害羞靦腆,躲過了審查而順利的上架了,這時候卻換成使用者三不五時反應說程式一直當機,一直閃退(註2:使用者天生是讓系統崩潰的天才),但是你卻想破頭也不知道原因是什麼,這時候如果有個能將當下的錯誤訊息回報給你,至少有個方向可以去追查。

註1:教育訓練定理。教育訓練等正式場合,系統的 Bug 就有如脫韁的野馬一般,總在令人意想不到的情形下大肆奔放。
註2:使用者天生是讓系統崩潰的天才。不解釋......

今天要介紹的是,如何讓 App 崩潰的時候,能夠崩的優雅,崩的面不改色,崩的理所當然。

2013年4月22日 星期一

日本記行 - 横浜中華街

只要有華人,就會有中華街!

在日本久了,每天吃的不外乎冷食或是口味重的拉麵,實在很想念中式口味的食物,除了超市賣的偽中華料理或是一些標榜中華風的餐廳。可以查查Google Map看看附近有沒有 China Town 可以一解鄉愁!

日本很多地區都有中華街,其中就屬橫濱的中華街最大最有名!

2013年4月18日 星期四

日本記行 - 新宿(東京都庁舎)

在新宿住了一個周末,雖然旅館很爛...但是一點也不減薪宿的風采!第一天坐 JR 到新宿車站,一出車站就迷路了Orz...。

當天與人約在歌舞伎町,但是車站的出口有3、40個,事前準備的路線沒有派上用場,只好硬著頭皮仔細分析車站內的指示,一個小時後總算是讓我摸到了目的地,真是有驚無險啊!

因為在新宿只是短暫停留,只去逛了這次要介紹的東京都廳舍。

2013年4月16日 星期二

日本記行 - 筑波萬博紀念公園

如果是烏龍派出所的忠實觀眾的話,應該會看到兩津回憶小時候時,常常會有萬博會(萬國博覽會)這個活動,萬博是陪伴日本人成長的一個共同回憶,見證了日本經濟起飛又泡沫化的歷程。

根據 wiki 上面所寫的,每隔1~2年就會舉辦一次萬國博覽會,主辦國也不限定是日本,下面是日本比較有名的萬博場次。

2013年4月14日 星期日

日本記行 - 秋葉原(あきはばら)

因為這一次在日本一個月住的地方是茨城縣的筑波市,距離東京都坐 Tsukuba Express 大概45分鐘左右,其實還蠻方便的。

Tsukuba Express 停靠站
終點站就是秋葉原站了,所以我第一個自由行的地點就挑了秋葉原!我總共去了3次,每一次去都有不同的體驗 ( *´艸`*)

根據 wiki上所寫的,原本秋葉原是住宅區,後來發生了大火,改建成為青果市場。二戰後開始有電器店進駐,搖身一變變成了電器城。慢慢的因為家庭電器的沒落,逐漸被電腦以及ACG的產業所取代,成為了現在我們看到的秋葉原。


2012年3月4日 星期日

Android - MapView上面的圖片跟著縮放 Part 2

隔了七個多月的時間,我之前寫的Android - MapView上面的圖片跟著縮放 在ptt上面又被挖出來了,這次比較不一樣的是,原本由程式帶入的點位,要改成由使用者在地圖上面長按後,將所按壓的位子放一個圖片,而這個圖片一樣要可以隨著地圖縮放!

所以我下班之後花了一點時間把之前的寫的範例修改成本次的需求,不過有一點要特別說明的是,之前的圖片縮放法太耗資源了,所以我改成了用 Matrix 的方式去縮放。

以下就是本次的範例說明

2012年2月13日 星期一

2012年1月2日 星期一

Git Server via HTTP with Apache2 on Ubuntu 11.10

折磨我好久的Git Server安裝終於建立成功了,這淘氣的東西讓我這Linux生手搞了三個禮拜才安裝好...真是....嘰咕修~~~
趕緊把它寫下來,免得之後發生意外,又要三個禮拜去回想...

首先環境是 Ubumtu 11.10 on vmware station 8,network 用 NAT,設定port forwarding讓外部電腦可以經由Host的ip直接連結進去。

接下來是指令,開啟終端機,開始輸入吧!


#安裝apache2
apt-get install apache2
#安裝git
apt-get install git-core
#建立存放repository的base(位置可以自訂)
mkdir /var/git
#在repository底下建立新的專案
cd /var/git
mkdir MyNewProject.git
#初始化專案git設定
cd /var/git/MyNewProject.git
git --bare init
#修改權限(設給www-data <= apache用)
chown -R www-data.www-data .
#注意後面有一個小點 => .
#再次修改權限(不知道為什麼要設到777這麼大)
chmod 777 . -R
#注意有一個小點 => .
#更新git server info
git update-server-info
#安裝dav模組
a2enmod dav_fs
#編輯apache serve 的設定檔
gedit /etc/apache2/conf.d/git.conf
#填入下列內容,注意專案名稱與路徑的對應
#passwd.git 密碼檔案名稱可以自訂
Alias /MyNewProject.git /var/git/MyNewProject.git
<location /mynewproject.git>
DAV on
AuthType Basic
AuthName "Git"
AuthUserFile /etc/apache2/passwd.git
Require valid-user
</Location>
#新增帳號密碼
htpasswd -c /etc/apache2/passwd.git 帳號
#接著會要你輸入密碼
#重新起動apach
/etc/init.d/apache2 restart
最後用瀏覽器測試連線:http://your.domain.name.or.ip/MyNewProject.git(剛剛建立的專案資料夾)/HEAD
如果有跳出輸入帳號密碼的話,恭喜你!你成功安裝完成了!

2011年10月31日 星期一

AD網域認證發生錯誤:未知的錯誤 (0x80005000)

卡了我好久的 AD 網域讀取問題終於解決了,提供給有相同困擾的人。


AD讀取的程式碼(C#)
DirectoryEntry entry = new DirectoryEntry("LDAP://GOOGLE.COM.TW:389", "userName", "password");
entry.RefreshCache();

一直出現錯誤畫面:

解決的方法如下:
  1. 在 Windows Server 2003 中,userName不需要加 domain。
  2. ladp路徑要大寫  <=== 卡了我一個多禮拜的兇手。

如果你是這樣而排除錯誤的話,留個言讓我知道一下吧!

2011年9月30日 星期五

手機程式開發與兼顧硬體能力

作者: iincho (世界的盡頭) 看板: Soft_Job
標題: Re: [請益] 手機程式開發與兼顧硬體能力
時間: Thu Sep 29 01:25:57 2011


 既然有人希望在下介紹怎麼看Android code,這裡就稍微分享一下心得,
 不敢說每個模組都精通,但是大方向抓是抓得出來的,
 不過我不喜歡吊書袋,所以想看到什麼design pattern之流的不要太期待。

 首先講書,Android目前關於系統面寫得最好的是底下這本:

 Android技術內幕:系統卷, 作者楊豐盛,簡體書。

 網路上找得到部分試閱,不過後面的章節沒前面寫得好,但光看第三章就划算,
 對binder的講解應該是目前市面上最好的。

 應該很多人看過韓超那本"深入淺出 Android 系統原理及開發要點",
 不過就我來看這兩本根本不是同一個檔次的東西。

 台灣出的基本上只能買高煥堂寫的,其他的不要碰。高先生對系統的理解算非常強,
 就是欠了點文彩有些可惜,不過寫的東西比那些搞技術傳教的好多了,至少觀念都是
 正確的。

2011年9月1日 星期四

Objective-C 的記憶體回收機制(下)

終於比較有空補完下集了!這一集主要想要分享Objective-C的直接存取與間接存取的差異,以及function return value 的 retain、release 時機。

首先先看下面一個很簡單的 student class:


student.h
@interface Student: NSObject {
    NSString *iName;
    NSString *iStudentID;
    int age;
}

@property(nonatomic,copy) NSString *iName;
@property(nonatomic,copy) NSString *iStudentID;
@property(nonatomic,assign)  int age;

@end

student.m
#import "student.h"
@implementation student
@synthesize iName,iStudentID,age;

- (void) dealloc {
    [iName release];
    [iStudentID release];

    [super dealloc];
}

@end

2011年8月28日 星期日

Objective-C 的記憶體回收機制(中)

在上一篇文章裡面談到了自己對物件記憶體的操作,難道就只有開發者會對物件做計數器(retainCount)的操作嗎?答案是否定!有一些 api 會自動對物件的 retainCount +1或是 -1,最常見的例子就是陣列的操作。例如:

NSMutableArray *arr = [[NSMutableArray alloc] initWithCapacity : 0];//array.retainCount = 1

NSString *str1 = [[NSString alloc] initWithString : @"A"];//str1.retainCount = 1
NSString *str2 = [[NSString alloc] initWithString : @"A"];//str2.retainCount = 1

[arr addObject : str1];//str1.retainCount = 2
[arr addObject : str2];//str2.retainCount = 2

[arr removeObject : str1];//str1.retainCount = 1
[arr release];//array.retainCount = 0;str2.retainCount = 1

//系統回收 array

[str1 release];//str1.retainCount = 0
[str2 release];//str2.retainCount = 0

//系統回收str1&str2

Objective-C 的記憶體回收機制(上)

這陣子為了 iPhone 學了 Objectiv-C ,一直對他的記憶體管理機制頗有微詞(笑),什麼時候該釋放,什麼時候該保留,真的是一點頭緒都沒有!建議初學者先把 Apple 官方的關於記憶體回收的說明文件先讀過一遍。(網頁版,PDF版),內容有空的話我再翻譯!

首先先解釋為什麼變數有時候要加星號(*),有時候又不加。這是因為在 C 與 C++,以及基於這兩種語言加以改良的 Objective-C ,星號(*)代表的意思是指向某個記憶體的指標(pointer), 而不加星號(*)表示是取值,例如:

int number = 0;//取值

char[] name = ['n','a','m','e'];
char *str = name;//取址

2011年8月23日 星期二

html 檔案上傳控制項 onChange事件只會觸發一次

困擾了好久的問題,終於解決了!

原本的事件繫結

$("#file_upload").bind('change',function(){});

改成

$("#file_upload").live('change',function(){});

----以上是 JQuery 的用法-------

一般的做法是替換掉file_upload

$('#file_upload').replaceWith('<input id="file_upload" name="file_upload" type="file">');

2011年7月28日 星期四

Android - MapView上面的圖片跟著縮放

昨天在ptt的AndroidDev板看到有鄉民在問怎麼讓MapView上面的圖片跟著縮放,想起之前也有做過類似的測試,就寫了這篇和大家分享。

首先先看到layout檔的排版:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <com.google.android.maps.MapView
  android:id="@+id/mView_Main"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:apiKey="你自己的key">
 </com.google.android.maps.MapView>
</LinearLayout>

很簡單的一個地圖畫面。

Objective-C 的 self

今天查被Apple reject的原因,剛好看到有關self的一些解釋,趕緊記下來免得忘記。

假設現在有個類別Test,裡面有一個NSData的成員。

@interface Test : NSObject {
    NSData *iData;
}

@property(nonatomic,retain) NSData *iData;

@end

當我們使用 self.NSData 的時候,就等同於呼叫編譯器幫我們自動產生的getter方法,retain + 1。
當我們使用 self.NSData = [[NSData alloc] init],就等同於呼叫setter的方法。

而編譯器產生的getter/setter就等同於自己寫的:

-(void) setIData : (NSData *) newData {
  if(iData != newData){
    [iData release];
    iData = [newData retain];
  }
}

-(NSData *) getIData {
  return iData;
}

另外,在dealloc時,就不要再用self了!

2011年7月18日 星期一

Android上的好用鬧鐘 - Alarm Clock Xtreme

Android上面有很多套鬧鐘軟體,今天介紹的這一套是我覺得還不錯用的鬧鐘軟體,除了會盡責的叫你起床之外,還有專為懶人設計的貪睡功能,每天最美好的時光之一就是鬧鐘響起到下一次貪睡期間的小小賴床,好像不賴一下床,今天就沒有辦法開始一樣XD

另外一個推薦原因就是...正(繁)體中文是我翻的啦!老王賣瓜,自賣自誇一下!

Market 連結:Alarm Clock Xtreme
免費版本:有廣告
付費版本:0.99 美金,去除廣告
QR Code

2011年7月16日 星期六

Android 模擬器打不開

今天為了測試一支半成品,不敢貿然安裝在實機上,打算安裝在那慢的可以的模擬器來做測試,沒想到一按啟動就跳出了怪訊息:

invalid command-line parameter: Files\android-sdk-windows\tools/emulator-arm.exe.
Hint: use '@foo' to launch a virtual device named 'foo'.
please use -help for more information

幹什麼!造反了!

2011年7月15日 星期五

StringBuilder append null in Java and C# test

今天檢查了一下StringBuilder對於附加null的處理做了個小實驗。

Java:
import java.util.Calendar;

public class main {
 public static void main(String[] args) {
  testStringBuilder();
 }

 public static void testStringBuilder() {
  StringBuilder sBuilder = new StringBuilder();
  
  System.out.println("1. string of new StringBuilder()");
  if(sBuilder == null){
   System.out.println("string:[is null]");
  }else{
   System.out.println("result:string:[" + sBuilder + "],length:[" + sBuilder.length() + "]");
  }
  
  StringBuilder sBuilder2 = new StringBuilder("");
  
  System.out.println("2. string of new StringBuilder(\"\")");
  if(sBuilder2 == null){
   System.out.println("string:[is null]");
  }else{
   System.out.println("result:string:[" + sBuilder2 + "],length:[" + sBuilder2.length() + "]");
  }
  
  StringBuilder sBuilder3 = new StringBuilder();
  String nullString = null;
  sBuilder3.append(nullString);
  
  System.out.println("3. string of new StringBuilder() append null");
  if(sBuilder3 == null){
   System.out.println("string:[is null]");
  }else{
   System.out.println("result:string:[" + sBuilder3 + "],length:[" + sBuilder3.length() + "]");
  }
  
  StringBuilder sBuilder4 = new StringBuilder("");
  sBuilder4.append(nullString);
  
  System.out.println("4. string of new StringBuilder(\"\") append null");
  if(sBuilder4 == null){
   System.out.println("string:[is null]");
  }else{
   System.out.println("result:string:[" + sBuilder4 + "],length:[" + sBuilder4.length() + "]");
  }
 }