2013年8月11日 星期日

說說,Android與iOS之中的偏好設定。


好緊張,我想我必須要對iOS和Android作個整理,當連"true"和"YES"會寫錯的時候,開始覺得,腦袋裡面的資料庫開始需要再進行更深度的重新整理了。

所以先來首蘇軾的〈定風波〉配上冷氣和下雨聲音開場:
莫聽穿林打葉聲,何妨吟嘯且徐行。竹杖芒鞋輕勝馬,誰怕?一蓑煙雨任平生。 
料峭春風吹酒醒,微冷,山頭斜照卻相 迎。回首向來蕭瑟處,歸去,也無風雨也無晴。
好,然後開始。


我想從最基本的儲存動作開始,在Android之中,大概可以劃分為5種儲存動作,主要可以分為:
  1. Shared Preferences(分享式喜好設定):儲存私有的簡單資料在鍵-值配對
  2. Internal Storage:儲存私有的資料在裝置的記憶體(手機中)
  3. External Storage:儲存公開資料在外部的儲存空間(如SD卡)
  4. SQLite Databases:儲存結構化的資料在私有的資料庫
  5. Network Connection:儲存資料在網路上的網路伺服器中
詳見這裡,以及官方文檔。

而關於IOS,我發現最不一樣的地方就是好像都一樣,尤其是第3點的部份,在Android市場淘汰機制下,許多裝置目前也開始衍生出了不需要SD卡擴充的機型,而分別推出內建
16G或是32G的外部儲存容量款。

至於在code的概念上,我覺得是關於Shared Preference差異最大,
在Android裡面,我們可以設定不同的SharedPreference物件,他將會儲存在指定的資料夾之中,並且對他作存取。於是我們可以作一個class把他封裝起來:


//封裝偏好設定的class
public class SharePreferencesHelper {
    Context mContext;
    //建立一個屬於偏好設定的名字
    final String NAME = "SharePreferencesHelper";
    //一個私有的靜態的SharedPreferences檔案
    static SharedPreferences mSharedPreferences;
    
    //一個開關用途的key值,我們透過方法實作他的設定與獲取。所以外部不需要調用到他
    final String KEY="switchSomeThing";
    
    
    //建構子,確保SharedPreferences實例存在
    public SharePreferencesHelper(Context mContext) {
        this.mContext = mContext;
        if(mSharedPreferences==null)
            mSharedPreferences = mContext.getSharedPreferences(NAME,
                                                               android.content.Context.MODE_PRIVATE);
    }
    //實作的方法1
    public void setON() {
        mSharedPreferences.edit().putBoolean(KEY, true).commit();
    }
    //實作的方法2
    public void setOFF() {
        mSharedPreferences.edit().putBoolean(KEY, false).commit();
    }
    //實作的方法3
    public boolean getValue() {
        //這裡可以getBoolean(), getString() 依照需求用方法封裝起來
        return mSharedPreferences.getBoolean(KEY, false);
    }
    
}

這樣就很方便,甚至可以把全部都當作String來儲存,以後只要指定Key值,並且作適當的轉型就可以動作了。其他範例可以參考官方文件裡面也會有詳細說明。

而iOS之中,就更為簡便了,主要創立調用的方法是,他會被存成一個.plist檔案:

NSUserDefaults *userPrefs = [NSUserDefaults standardUserDefaults];

存取值得方法也有很完整的方法可以調用,例如:

//設定某個值
 [userPrefs setValue: Value值  forKey:Key值];
//獲取某個值
[userPrefs valueForKey:Key值];

當然也會有boolean或是依照特別user account所設立的偏好等其他方法。

詳細可以參考這個網頁,或是官方的文檔。


話說一直看JAVA 風格的API Reference之後,突然跑去看Apple的API Reference整個有點彆扭呀。


---------- 我是碎碎念的分隔線 ----------

話說,開始碰iOS至今也有大概也有一個多月左右的時間了,有遇到一些問題與挑戰,我想我應該把他紀錄起來,在學生時代,學校會產生許多比iOS還要多的Android開發者,這不是壞事,畢竟免費又自由唄。但是在業界,Android的開發成本似乎的確比iOS還要高很多,有許多人開始從Android跳到iOS的行列,於是雙棲的過程之中,也碰到了許多困難。

把他紀錄起來,以下不負責列點碎碎念:
  1. code:
    一開始碰到iOS的時候,心想:"這是什麼火星文!"後來其實也開始習慣了,這是有好處的,幫助我在iOS與Android的coding style作區隔記憶。iOS比較像是c++的內容,而也有獨特的方法調用規則,我想,保持著勇氣,就能夠習慣與成長。
  2. 命名的哲學:
    Android很喜歡用get and set,可是我發現iOS不會這樣作,大多獲取資料的方法就是直接"valueOf:"開頭,而設定的部份在UI相關的設定較多沒有"set"開頭的字樣,所幸在Xcode裡面,方法調用都有自動生成的機制,這幫助很大,比較不會遇到"怎麼可能想得到可以這樣作?"的問題。
  3. API Reference:
    這塊其實我糾結了很久,約有2到3年的時間已經很習慣Java style的API Reference,突然看到一排畫下來沒有表格樣式的介紹,突然有種不知道在寫什麼的感覺。俗話說得好:"英文很重要"。除了這個之外,我覺得,如果能夠先熟悉iOS呼叫與設計method的style,然後習慣辨識在iOS API Reference粗體字代表標題的意思,我想,其實iOS 的文檔也還滿好讀的。
  4. 硬體調用的架構:
    架構上真的,不太一樣。iOS方便的地方在規定較為嚴格,也因為設備也很單一,所以像是UI上考慮的解析度就差不多那幾種,調用其他硬體的方法也相對Android明確,就算想要繞路,也可能遇到iOS沒有提供source code或是審核可能不通過的情況下,我們實現方法的方向就是一種,這也算是方便開發者的一種作法。Android在實現上就較為不一定,同樣在UI的設計上,在xml的layout上雖然有官方建議的方式,卻也有些人用比例的方法調整layout的設計,或是switch不同解析度的畫面讀取不同的layout。
大概是這樣,還在學習,以後有心得或是更正的內容再補上。

















2013年8月10日 星期六

筆記,iOS閃光燈、振動功能,以及計時器


作個簡短的筆記,因為嘗試的程式發現流程根本有問題,
所以把相關的實作的功能作個紀錄,之後再來想流程怎麼修改。

首先是振動部分,振動很簡單,必須先import AudioToolbox.framework然後填入:

#import "AudioToolbox/AudioServices.h"

調用:

AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);

就解決了,沒辦法調整長振動和短振動時間。

接著就是閃光的部份,我把他寫成一個method:

//閃光燈開關
-(void)flashSwitch:(BOOL)turnOn{
    NSLog(@"閃光燈開關: %d",isOn);
    
    NSArray *array=[AVCaptureDevice devices];
    for(AVCaptureDevice *p in array){
        
        if([p hasTorch]){
            if([p isFlashModeSupported:AVCaptureTorchModeOn]){
                if([p lockForConfiguration:nil]){
                    p.torchMode=turnOn;
                }//lock and check lock
                [p unlockForConfiguration];
            }//end if LED
        }//end if hastorch
    }//end 

這邊有些怪怪的,因為沒有作break動作,而iphone或ipad不就是只有背後才有閃光燈嗎?
然後這邊因為我想要實現按鈕按下時候開啟閃光,按鈕放開時候關閉:這裡會發現如果閃光燈開關方法直接實作在按鈕的觸發事件裡的話會讀不到,猜測應該是線程處理的問題,於是,NSNotificationCenter就登場了:


//發送通知
[[NSNotificationCenter defaultCenter]
     postNotificationName:@"通知的key值"
     object:self];

//註冊通知監聽
[[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(receiveTestNotification:)
                                                 name:@"通知的key值"
                                               object:nil];
//通知觸發的方法
- (void) receiveTestNotification:(NSNotification *) notification
{   
    if ([[notification name] isEqualToString:@"通知的key值"]){
       //觸發方法寫在這個裡面
    }
}

這跟Android的Broadcast概念是一樣的,我把他用在按鈕回饋操作閃光燈的開關行為上,運轉正常。

這邊要注意,在註冊通知監聽那邊,有個object參數,可以作為傳值用途,輸入nil(null)就是給他空的值啦!


最後我用了一個Timer的動作,用來計時,操作的內容如下:

//開啟計時
NSTimer *timer=[ NSTimer scheduledTimerWithTimeInterval:時間間格 target:self selector:@selector(method:) userInfo:nil repeats:YES];

//結束計時
if(timer)
    [timer invalidate];

//計時觸發的方法
-(void)method:(NSTimer *)theTimer{
//要作什麼事情寫在裡面就好
}


然後,這是timer 開啟計時的參數說明,懶得打所以放原文上來:
seconds
The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead.
target
The object to which to send the message specified by aSelector when the timer fires. The target object is retained by the timer and released when the timer is invalidated.
aSelector
The message to send to target when the timer fires. The selector must correspond to a method that returns void and takes a single argument. The timer passes itself as the argument to this method.
userInfo
The user info for the timer. The object you specify is retained by the timer and released when the timer is invalidated. This parameter may be nil.
repeats
If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.
以上。





追蹤者