呃...

其實不會有什麼精深的東西,也就只是把我學習過程記錄一下...

2014年6月27日 星期五

chilkat blowfish for iOS data transmission PART2

繼上回的chilkat blowfish for iOS data transmission PART1安裝完成後,再來就是正式的引用啦。

以下這裡是官網給的範例,其實照著走就可以了..那我到底為啥花了這麼多時間 Orz

CkoCrypt2 *crypt = [[CkoCrypt2 alloc] init];

BOOL success;
success = [crypt UnlockComponent: @"Anything for 30-day trial"];
if (success != YES) {
    NSLog(@"%@",crypt.LastErrorText);
    return;
}
以上這串一定要寫進code,不寫的話不給用,也別想在他的include資料夾找他的source code破解,沒加密才怪啊,不過網路上可能有破解版就是?

//  Attention: use "blowfish2" for the algorithm name:
crypt.CryptAlgorithm = @"blowfish2";

//  CipherMode may be "ecb", "cbc", or "cfb"
crypt.CipherMode = @"cbc";

//  KeyLength (in bits) may be a number between 32 and 448.
//  128-bits is usually sufficient.  The KeyLength must be a
//  multiple of 8.
crypt.KeyLength = [NSNumber numberWithInt:128];

//  The padding scheme determines the contents of the bytes
//  that are added to pad the result to a multiple of the
//  encryption algorithm's block size.  Blowfish has a block
//  size of 8 bytes, so encrypted output is always
//  a multiple of 8.
crypt.PaddingScheme = [NSNumber numberWithInt:0];

//  EncodingMode specifies the encoding of the output for
//  encryption, and the input for decryption.
//  It may be "hex", "url", "base64", or "quoted-printable".
crypt.EncodingMode = @"hex";

//  An initialization vector is required if using CBC or CFB modes.
//  ECB mode does not use an IV.
//  The length of the IV is equal to the algorithm's block size.
//  It is NOT equal to the length of the key.
NSString *ivHex;
ivHex = @"0001020304050607";
[crypt SetEncodedIV: ivHex encoding: @"hex"];

//  The secret key must equal the size of the key.  For
//  256-bit encryption, the binary secret key is 32 bytes.
//  For 128-bit encryption, the binary secret key is 16 bytes.
NSString *keyHex;
keyHex = @"000102030405060708090A0B0C0D0E0F";
[crypt SetEncodedKey: keyHex encoding: @"hex"];

//  Encrypt a string...
//  The input string is 44 ANSI characters (i.e. 44 bytes), so
//  the output should be 48 bytes (a multiple of 8).
//  Because the output is a hex string, it should
//  be 96 characters long (2 chars per byte).
NSString *encStr;
encStr = [crypt EncryptStringENC: @"The quick brown fox jumps over the lazy dog."];
NSLog(@"%@",encStr);

//  Now decrypt:
NSString *decStr;
decStr = [crypt DecryptStringENC: encStr];
NSLog(@"%@",decStr);

以上除了最後的加解密example可以不用管,其它照著放進去再修改就行了。
需要更改的地方可能有幾個:
1. EncodingMode =@"hex";
這邊看個人喜好喜歡用什麼加解密的input/output格式,例如使用hex,則data進去後,出來就是一串hex。
2. ivHex
為16進位的加密字串,由於blowfish有8 bytes的block size且IV的長度與block size相同,所以這邊改成自己的加密字串,並且只需要16個字即可。至於為啥是blowfish 是8 bytes,請google XD
3. keyHex
這邊的長度就是一開始設定的keylength長度,由於是128/8=16bytes,所以要用32個16進位的字去填滿。

4.  crypt的方法SetEncodedKey: encoding:@"hex" 中的encoding:
這邊雖然範例中沒有提,但其實是可以改的,例如我在使用的時候就是把兩個encoding的@"hex"改為@"ascii"。我的情況是改成@"hex"會導致解碼錯誤。原因是什麼還不清楚,如果有人知道再告訴我,不然等改天我清楚了再來補發一篇囉。(發完立刻想到可能的原因..囧)
自解:我這邊 PHP API放置的server預設編碼方式是utf-8,因此用ascii字元集編碼,才不會導致傳過去的資料,在API那一邊看會有亂碼產生,這也是為什麼我改成hex的話,會導致解碼錯誤。


最後使用設定好的crypt的EncryptStringENC以及DecryptStringENC去加解密就可以了。
下一回是最終回,使用在與PHP API資料加解密的傳輸。

補上chilkat對於iOS的blowfish reference documentation
http://www.chilkatsoft.com/refdoc/objcCkoCrypt2Doc.html

chilkat BlowFish for iOS data transmission PART1

這部分真的是浪費了我不少時間,要不斷兩邊驗證收到的data正不正確,還要把收到的data轉回正確能用的格式,my god Orz 以下正式心得文開始。

這邊使用的是第三方寫的資料加密傳輸,chilkat software中的iOS encryption部分,主要是採用blowfish的CBC方式去加密。(這裡我屬於使用者,什麼是blowfish以及CBC,請找google大神)

引用前需注意事項:
這個是以盈利為目的的第三方API提供者,所以API只有30天試用期,想找永遠免費的可能就要自行再多找找了,我大概一個月後有時間才會再來弄這個資料加解密的部分 (茶)

引用方式:(其實官網有說明,但我還是花了不少時間 Orz)
1. http://www.chilkatsoft.com/downloads_ios.asp  在這邊download他的code,有分兩種版本,都能用,差別好像在compile時候用的lib?
2. 下載後需要解壓就解壓,資料夾放哪裡是都沒差,不過我還是習慣放在project的資料夾下
3. 在command模式下執行他提供的shellscript去輸出一個allversion的.a檔
4. 開啓Xcode如下圖,加入static library,選取剛剛產生出來的.a檔

5. 加入-lresolv到Build setting裡的other linker flag,以及設定user header search path為$(SRCROOT),並選擇recursive。(由於SRCROOT是指向這個project的資料夾位置,所以我把解壓出來的檔案就放在project的資料夾中)

6. 在project中產生一個cpp檔案,什麼都可以刪掉,能正常run就行,然後加入一行import "CkCrpyt2.h"

到這邊大致上設定完成,再來就是引用加解密的部分了,請看下回的chilkat blowfish for iOS data transmission PART 2。
如果還有什麼問題其實可以先看官網的安裝說明,大致上會遇到的問題應該都有說明。



2014年6月26日 星期四

care alertView when view is changed

記錄記錄....
//若alertview發生在換場景的時候,需注意delegate的角色會不會已經release了
UIAlertView alert=[[UIAlertView alloc] initWithTitle:@"登入成功"
                                          message:@""
                                         delegate:self
                                cancelButtonTitle:@"確定"
                                otherButtonTitles:nil];
[alert show];

[self.navigationController popToRootViewControllerAnimated:YES];
//這一段執行後會call dealloc method
在使用alertView時,遇到一個情況如上方code,當我在同一區塊使用poptorootview後,由於viewcontroller已經執行dealloc,所以當按下alertView 不管是cancel button或自定button都會發生delegate找無人的情況導致crash。

有兩個方式解決這個問題:
1.
delegate:nil
在delegate的參數部分直接改成nil,這樣任何事件都不會去找view controller了。呃,還是很有用的,假如真的只是要做一個警告視窗而已,沒有要觸發什麼事件的話。
2.
- (void)dealloc{
    [_alert setDelegate:nil];
需要在dealloc的方法中,加入一段[alert setDelegate:nil],讓delegate變成nil,這樣當alert有button被click時,alert不會再去找已經release掉的view controller,不過當然若原先有在按鈕寫什麼事件,也都不會觸發了。與方法1相比,差別在於除了view controller 被release時不能觸發任何事件,這個方法在其他時候還是可以delegate給view controller去執行事件。

P.S.:修改dealloc時,只要加入自己想要release或set nil的部分即可,官方文件已經有說明在ARC機制下,dealloc方法裡面在編譯時,compiler會自動加入[super dealloc]。


2014年6月25日 星期三

NSPredicate for NSDictionary and NSArray


NSPredicate 可以用來驗證Array, String等內容是否符合格式,以及還有各種判斷式可以驗證內容,回傳也分為Array、BOOL或?我也還沒非常熟悉這個類別,總之是很有用的一個類別,詳細格式就不多說,挺多文章的,就記錄一下我釐清後的記錄。
ex:
@interface ...:...
@property NSDictionary *dataDict;
end
@implement ...
//以下是要做到能使用MATCHES的表示式去判斷物件內容有無符合條件
//Pridicate的驗證format,這裡是用正規表示式當成驗證條件。

NSString *verifyStr=@"[A-Z0-9a-z]{1,18}";

//一維Array的驗證方式,另外宣告testArray那行的意思是,取出dataArray
符合verifyStr的正規表示式的結果。filteredArrayUsingPredicate會累積
比對後return YES的 NSarray 物件並回傳。

NSArray *dataArray=@[@"abc",@"1234"];

NSPredicate *predict=[NSPredicate predicateWithFormat:@"SELF MATCHES %@", verifyStr];

NSArray *testArray=[dataArray filteredArrayUsingPredicate:predict];


//單筆Dictionary的驗證方式,這邊使用的方法是只會驗證內容是否符合條件並回傳YES or NO,在 predicateWithFormat部分可以直接列出想要判斷的欄位以及條件。

NSPredicate *predict=[NSPredicate predicateWithFormat:@"(acc MATCHES %@) AND (pwd MATCHES %@)", verifyStr,verifyStr];

_dataDict=@{@"acc": @"abc",@"pwd":@"1234"};

BOOL result=[predict evaluateWithObject:_dataDict];


//多筆Dictionary的驗證方式,透過allValues取出所有value去進行驗證,並如同第一種狀況,會將累積符合驗證條件的結果後,以 NSArray 物件回傳值。

NSPredicate *predict=[NSPredicate predicateWithFormat:@"(first_name MATCHES [A-Z]) AND (last_name MATCHES [a-Z])"];

NSDictionary *multiDict=@{@"1":@{@"first_name":@"A",
                                 @"last_name":@"a"},
                          
                          @"2":@{@"first_name":@"B",
                                 @"last_name":@"b"},
                          
                          @"3":@{@"first_name":@"C",
                                 @"last_name":@"c"}
                          
                          };

NSArray *testArray=[[multiDict allValues]filteredArrayUsingPredicate:predict];

說明:
-(NSPredicate *)[predicateWithFormat:@"(acc MATCHES %@) AND (pwd MATCHES %@)", verifyStr,verifyStr]
NSPredicate物件。predicateWithFormat可視為與NSString的initWithFormat方法等相同,不同的是這邊NSString要輸入欲驗證的格式,例如這邊的acc MATCHES %@,意思即是說acc欄位的值要符合後方傳入的verifyStr內容,其中MATCHES的驗證內容可用正規表示式。
-(NSArray*) filteredArrayUsingPredicate:(NSPredicate *)
NSArray 方法,需傳入NSPredicate物件,透過已經設定好的格式,一一對Array內容進行判斷,累積比對後return YES的 NSarray 物件並回傳。
-(BOOL) evaluateWithObject:(id)
NSPredicate的instance方法,傳入值為id型態,對傳入的物件判斷後,回傳YES or NO的結果。

2014年6月21日 星期六

first ViewController of review


記錄一下過程,不過以後的記錄或心得可能會越寫越精簡(也就是少XDD),因為這樣寫法好花時間,現在公司急件啊!!Orz

1. 建立ViewController
開啟simple view,storyboard會初始建立一個ViewController,sub of UIViewController class,同時project裡頭會有ViewController.h/m,到這邊第一個就建好了。

2. 建立第二個ViewController,取為ScViewController
 使用storyboard拉View Controller,在Identity inspector中,將Custom class選為ScViewController,這動作是指示這個ViewController是由ScViewController負責

3. 建立Navigation Controller
選取希望使用者第一個看到的ViewController(不要選到view了,點擊下方黑色條列比較不會有問題),選取在功能列裡的editor->embed in->Navigation Controller即可。
Navigation Controller說明:
根據字面來簡單講,就是俱有scene導航的能力,展示使用者選取的scene。在有多個scene的情況下,會透過Navigation Controller來顯示目前的scene (embed in, 將畫面嵌入到Navigation Controller的scene),在官方解釋來說就是RootViewController。
P.S.: scene存放的方式是使用stack。
還是不懂Navigation Controller的話,請看CS193p的lecture 6,我覺得會比我在這邊畫虎爛半天還清楚。

4. 使用IB提供的物件庫拉button

5. button 前往ScViewController
 透過segue push 方式,也就是在button滑鼠右鍵拉到ScViewController去,就會在storyboard出現一條關係線,記得為這個segue 的identifier取個名。超方便啊這個,這個時代怎麼會這麼進步?
segue說明:
簡單來說,按照字面解釋就是滑順的動作,如滑順的推segue push,滑順的模態(XD?)segue modal, etc...,總之,沒啥意思,但要解釋是因為有些方法叫做...segue...,有點概念會比較好理解跟記這些方法。
另外說明button這個右鍵拖曳的一些功能:

  • 建立segue
  • 若在code裏面有宣告一些變數是要搭配storyboard版面上的物件,拖曳可建立relationship
  • 未在code裏面宣告變數,從storyboard的物件拖曳到code裡面會自動宣告變數

6. 方法
//button拉線的方式可以前往下個scene,但也可透過此方法前往scene
- (void)performSegueWithIdentifier:(NSString *)segueId sender:(id)sender;
// 在segue執行之前要做的動作
 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{}
//是否執行Segue的判斷
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender{}
//是否pop掉目前的scene,也就是回上一scene
- (void)popViewControllerAnimated:(BOOL)animated;

IBOutlet & IBAction of review


雖然懂,但每次看到要在腦中自我解釋都會忘掉意義...
簡單來說,這兩個只是為了告知IB說,這邊有outlet(msg)/action要跟UI溝通(connection),IB你踏馬的記得要看一下,因此,這兩個宣告對於變數什麼改變都沒有,只是賦予意義而已,從下方原始定義可以看出來。

#ifndef IBOutlet
#typedef IBOutlet
#endif

#ifndef IBOutlet
#typedef IBAction void
#endif

簡單的範例來看 -
@interface ...

@property IBOutlet UILabel *detailDescriptionLabel;
- (IBAction)buttonPressed:(id)sender; 
@end

其實等於
@interface ...

@property UILabel *detailDescriptionLabel;
- (void)buttonPressed:(id)sender; 
@end


P.S.:
1. IB= Interface Builder, 視覺化界面設計工具,就是storyboard開啟的畫面,透過xml保存界面設計,這邊不太懂幹嘛用xml就是,json的格式感覺好看許多,改天再研究 XD
2. IB開頭的宣告都是為了給Interface Builder看,讓IB知道這是需要它解析的東西

review of obj-C id

id形態應該被用在以下地方:
1. 在一個collection中有多種不同class的物件
2. 不能知道資料傳遞時對於結構, 資料或方法呼叫時,例如MVC中常可看見的delegate

為了讓以上的使用方式可以更加安全,因此有了introspection與protocols

  • introspection 

是一個方法集合的意義,主要說明這個方法集合是用來做自我判別。例如isMemberOfClass, isKindOfClass等,另外值得一提的是SEL資料形態的變數selector,存放的資料是可被這個變數看見的“方法”,在此方法集合裡也有可驗証方法是否有被實做的方法。完整範例:[obj respondsToSelector:@selector(方法:)]

  • protocols     
最常見的就是委派,委託方需要建立一個變數為id <protocolMethod> delegate,讓使用動態形態的物件都必須實作protocol的方法,避免物件引用了本身未定義的方法

另外一提存在於selector的方法,在Object都有方法可以直接引用,例如以下範例:

[obj performSelector:selector]
[obj performSelector:selector withObject:obj]
[array makeObjectsPerformSelector:selector
[array makeObjectsPerformSelector:selector withObject:target]
[button addTarget:self action:@selector(digitPressed:) ...]; 

review of class of foundation

物件形態的資料:
NSString            - NSMutableString
NSArray             - NSMutableArray
NSNumber         - NSMutableNumber
NSDictionary      - NSMutableDictionary
NSSet                 - NSMutableSet - NSIndexSet
NSUserDefaults  
NSDate
NSData

immutable & mutable
物件內容可變與不可變,例如NSString = @"This is a shit" 不可執行deletechar, insertstring等會改變內容之動作。
而包含多物件的結構則是不可改變結構內容,例如NSarray = @[@"1", @"2", @"3", ...] 初始化建立後,不可執行NSarray[1]=@"1"等改變
陣列結構內容的動作。

review of delegation

這部分算是自我解讀的心得,請參考就好


delegation(委派) - 這是一種思維邏輯下的產物,因為Obj-C不使用delegation的方式,一樣可以完成delegation要做的事。但為了更容易釐清程式的設計概念,所以有了delegation。

  • 目的
delegation是為了簡化[類別之間的資料傳遞過程]以及[程式設計的思維模式]所產生的設計方式。

舉例來說,一個遊戲場景在程式設計中可能會分為View與Controller兩個部份,View是顯示遊戲場景的畫面,Controller則是負責控制場景。在這種設計模式下,若需要收集遊戲畫面的資訊或顯示資訊(例如遊戲中顯示FPS數字),不使用delegation有兩個做法:
1. 在view的類別底下新增一個method去print資訊
2. controller新增一個收集view傳來的資訊並顯示資訊的method.
這些設計方式在範例的思維邏輯上就會有一些矛盾:
1. 範例的敘述中,View是顯示遊戲場景使用,卻又多了可以顯示資訊的method
2. controller是負責控制場景,卻又有不相關的method去收集資訊
所以,delegation就是為了解決這種思維上的矛盾,所發展出來的design pattern
  • 概念
一般來說,當類別相互有關連時才會需要資訊傳遞,舉個常見例子就是view與controller。view需要顯示場景,但不希望工作變複雜而想把資訊顯示交給controller去做,因此view就委託(delegation) controller去顯示資料,而controller也不需要自己定義一個收集資訊的方法,而是根據view希望的資料顯示方式(protocol)去完成顯示即可。
delegation實做的概念可分為幾個步驟去理解,以下將委託方稱A,被委託方稱B:

A部分:
1. A需要定義protocol,並且需具有引用protocol的動態變數(基本上為了能更好理解,Obj-C皆使用delegate),讓B可以接受delegation。
2. A本身需具備判斷B有無實做protocol的方法,避免錯誤引用未實做的method
3. A的資料透過delegate動態變數傳遞給B

B部分: 
1. B引用A定義的protocol,宣告接受A的delegation
2. B需要實做protocol中的required部分
3. B本身需被指定為被委託方(程式碼直觀來看就是A.delegate = B)
4. 收到A的資料,執行protocol的方法

執行順序: A.1, B.1, B.2 -> B.3 -> A.2 -> A.3 -> B.4
當B.3完成後,則A執行本身的工作時,將會執行委託的流程A.2與A.3,並且透過delegate動態變數呼叫在B中的protocol方法,執行B.4步驟

了解delegation的目的,更容易清楚delegation的概念。

review of protocal

protocol
簡單來講 - 沒有被實做的方法集合,具有限制性,限制引用protocol則必須該實做的內容。
引用        - protocol會被類別, 變數或類目宣告時引用,protocol被引用以後,引用者要conform (採用) protocol定義的方法才不會出錯。
限制性    - @required與@optional說明了方法需不需要實做,一般protocol的宣告是默認為required,required的方法沒實做會出錯。

protocol 宣告:
新建一protocol名稱的header檔
@protocol ProtocalName
-協定方法
+協定方法
@optional
-協定方法
+協定方法
@end

引用方式:
interface NSObject(Category) <ProtocolName, ..., ..., ...>  //類目引用
-協定方法
+協定方法
...
end 

interface NSObject <ProtocolName, ..., ..., ...>                  //類別引用
-協定方法
+協定方法
...
end 

id <ProtocolName, ..., ..., ...> 變數名稱                              //變數引用 (表示此變數有實做這些協定)

測試有無實做protocol的API:
id 變數名稱;
...
if ([變數名稱 conformsToProtocol: @protocol (ProtocolName)] == YES)
...

end 

review of category & class extension

  • category(類目) 
不修改原有的類別內容,新增此類別的方法
  • class extension(類別衍伸)

同類目,但不止可以新增方法到類別,還可新增變數到類別。類別衍伸時,介面與實做區段要在同一檔案,一般此做法可以讓方法具有private性質(因為方法不會出現在.h中,使用者看不到,但若使用者知道名字一樣可以用),給類別使用。

ex:在NSObject類別新增一類目

開新檔,取名原則為原類別名稱加上類目名稱 -> NSObject+NewCategoryMethod.m&.h,類目宣告方式→interface 類別(類目名稱)
使用時同樣import此新檔,則型態即具有此類目方法
interface NSObject(NewCategoryMethod)
-(...)
+(...)
end

@implementation NSObject(NewCategoryMethod)
-(...)
+(...)
end
ex:在NSObject類別新增一類別衍伸

在實做檔中(.m檔案裡),宣告一無名稱類目

@interface NSObject()
...
end

@implementation NSObject
...
end

2014年6月20日 星期五

review of enum & typedef

就有點忘了這樣...


enum用法:
1.
enum 宣告名稱 {內容1,內容2=數值,內容,...}
enum 宣告名稱 變數名稱;

2.
enum {內容1,內容2=數值,內容,...} 變數名稱

3.
enum 宣告名稱:宣告型態 {內容1,內容2=數值,內容,...}

typedef用法:
typedef 型態 新型態名稱

enum + typedef:
typedef  enum {內容1,內容2=數值,內容,...} 型態名稱
型態名稱 變數名稱;

#ifdef & #ifndef
1.
#ifdef
...
#else
...
#endif

2.
#ifndef
...
#else
...
#endif

comment of IAP

壓力踏馬的比山大啊... (這篇廢話有點多)

        老實說,身為公司第一個開發iOS App的工程師,尤其還是一位不太會開發iOS App的工程師XD,當遇到專案日期評估、App開發可行性或功能開發可行性等問題,這比天塌下來還可怕啊。
        今天還在想我改給andriod用的銀行金流php API,忽然想到Apple可沒在給你玩這套時,就馬上抖了一下,OK,這不是我的問題,嗯,不是我的。只是我要想辦法解決而已Orz
       這也沒什麼好解決的,Apple可沒那麼仁慈,總之就是上報一句「Apple拒絕非官方的付費機制」,然後提一些不是做法的做法,像是在App內放置一網頁用來向外轉到不是放在App內的付費網頁,審核時不可內含任何訊息是需要透過非IAP方式付款(茶)
        另外有翻到的黑心做法是不上架到App store,利用企業內部署App的資格,將App部署到自己的server上(ipa, plist),透過網頁提供給Users安裝。這是個解法啦,不過我當作沒這回事就是了XD
        總之,Apple接受的只有IAP這官方付費機制,其餘什麼外接內接管你什麼接,Apple一概回絕。

P.S.: 經過大大指點得知,IAP的管制是對於虛擬貨物,也就是沒有實體物品的情況下受限於Apple的條款,若是實體貨物,則不受限於IAP的管制,是可以轉向其他付款方式。

OK, let me start to Develop it


        呃,其實不會有什麼精深的東西,也就只是把我學習過程記錄一下,原因是看到有人說最好在學習過程中做些記錄,所以就這樣啦,會把這一個禮拜來私底下記錄的review心得轉過來,以後有心得就繼續更新。

        要說的是,總算開始做這件事了?