呃....又荒廢了 XD
總之,是有關UIAcitvityViewController的share。
UIActivityViewController就是iOS的share extension,似乎在iOS8才有的樣子,下面這篇文章有很好的範例,包含建立自己想要額外放入share extension的功能。
http://www.albertopasca.it/whiletrue/2012/10/objective-c-custom-uiactivityviewcontroller-icons-text/
呃...
其實不會有什麼精深的東西,也就只是把我學習過程記錄一下...
2015年6月3日 星期三
2015年2月16日 星期一
Coding for Bugs: iOS Application Directory Structure : Document, Cache and tmp
iOS sandbox下的directory tutorial,雖然沒有特別深入,但是簡單易懂且也有說明該使用的時機。
覺得對App 可以用的資料夾感到混亂的可以看看。
Coding for Bugs: iOS Application Directory Structure : Document, Cache and tmp
覺得對App 可以用的資料夾感到混亂的可以看看。
Coding for Bugs: iOS Application Directory Structure : Document, Cache and tmp
2015年2月5日 星期四
open file by default viewer in iOS(UIDocumentInteractionController, QuickLook Framework )
Apple Official Document:
https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010409-SW1
Apple 提供UIDocumentInteractionController 來work with Quick Look Framework或其它App來開啟文件 - ( UIDocumentInteractionController Class Reference)
以及僅可preview的default browser的SDK - Quick Look Framework (Quick Look Framework Reference for iOS.)
UIDocumentInteractionController為了要可以preview file,所以包含Quick Look framework的功能。(那所以不要使用Quick Look ?單純使用Quick Look有沒有優點?)
單獨使用Quick Look Framework
1. 主要Class - QLPreviewController
2. 可以使用NavigationController push view,或是使用modal方式去push view (
presentModalViewController:animated:)
4. Quick Look support的type: iWork, Office, RTF, PDF, Image, UTI, csv
5. 使用DataSource pattern 提供檔案來源,應類似tableview的方式
使用UIDocumentInteractionController的3 step:
2. 在UI上放一個file
3. 當tap這個file時,使用UIDocumentInteractionController去present它。
presentation的時候UIDocumentInteractionController提供三種UI:
call presentPreviewAnimated:,並且必須implement
documentInteractionControllerViewControllerForPreview: ,如果return值為nil或沒有其他view controller,則file不會被present2. preview file或其他App開啟的選項:
call presentOptionsMenuFromRect:inView:animated: or presentOptionsMenuFromBarButtonItem:animated:這邊還可以另外加入copy和print options (此兩種method與UIDocumentInteractionController的delegate有關)
3. 提示使用者要用其他App開啟:
presentOpenInMenuFromRect:inView:animated: or presentOpenInMenuFromBarButtonItem:animated:UIDocumentInteractionController也具有file sharing的功能,詳情見(see UI State Preservation in iOS Technology Overview and the DocInteraction sample code project)
UIDocumentInteractionController包含filename, type, url, icon等properties可供使用。
UIDocumentInteractionController另外有annotation property可提供客製化information給其他App。
UIDocumentInteractionController會自動handle view的dismiss,但也有另外提供兩種方式來進行手動關閉view。
dismissMenuAnimated: or dismissPreviewAnimated:Registering the File Types Your App Supports
CFBundleDocumentTypes是dictionary型態,有四個key:
1. CFBundleTypeName - 文件型態的名稱
2. CFBundleTypeIconFiles - 是array型態,用來放文件icon的image
3. LSItemContentTypes - contains an array of strings with the UTI types that represent the supported file types in this group.
4. LSHandlerRank - 說明App是文件的owner或是只能打開檔案而已
Apple官方文件中的XML例子如下:
<dict> |
<key>CFBundleTypeName</key> |
<string>My File Format</string> |
<key>CFBundleTypeIconFiles</key> |
<array> |
<string>MySmallIcon.png</string> |
<string>MyLargeIcon.png</string> |
</array> |
<key>LSItemContentTypes</key> |
<array> |
<string>com.example.myformat</string> |
</array> |
<key>LSHandlerRank</key> |
<string>Owner</string> |
</dict> |
當其他App 使用UIDocumentInteractionController call自己的App時,其他App會丟information到
application:willFinishLaunchingWithOptions: or application:didFinishLaunchingWithOptions:,若有自行定義的document type,則需override method去處理收到的information並初始化自己的App。
丟來的資訊存放在上述方法中dictionary型態的options,有幾個key:
1.
UIApplicationLaunchOptionsURLKey - 檔案的URL
3.UIApplicationLaunchOptionsSourceApplicationKey - 想開檔案的其他App的bundle identifier
#import "ViewController.h"
#import <QuickLook/QuickLook.h>
@interface ViewController ()<QLPreviewControllerDataSource,QLPreviewControllerDataSource>{
NSURL *url;
}
@property (nonatomic, strong) QLPreviewController *qlController;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *strURL=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
strURL=[strURL stringByAppendingPathComponent:@"簡介Doxygen.doc"];
url=[NSURL fileURLWithPath:strURL];
// Do any additional setup after loading the view, typically from a nib.
self.qlController=[[QLPreviewController alloc]init];
self.qlController.dataSource=self;
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[[self.qlController navigationItem] setRightBarButtonItem:nil];
[self presentViewController:self.qlController animated:YES completion:nil];
}
-(NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller{
return 1;
}
-(id<qlpreviewitem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index{
return url;
}
@end
再來是UIDocumentInteractionController 的範例
#import "ViewController.h"
@interface ViewController ()<UIDocumentInteractionControllerDelegate>{
NSURL *url;
}
@property(nonatomic,strong) UIDocumentInteractionController *docController;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString *strURL=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
strURL=[strURL stringByAppendingPathComponent:@"簡介Doxygen.doc"];
url=[NSURL fileURLWithPath:strURL];
self.docController=[UIDocumentInteractionController interactionControllerWithURL:url];
self.docController.delegate=self;
// Do any additional setup after loading the view, typically from a nib.
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
[self.docController presentPreviewAnimated:YES];
}
-(UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller{
return self.navigationController;
}
-(void)documentInteractionControllerWillBeginPreview:(UIDocumentInteractionController *)controller{
}
@end
以上兩個範例都很簡單,官方文件也有其他範例可以看。 比較要注意的兩點:
1. 使用QLViewController時,若有使用NavigationController,可以用navigation的push
2. UIDocumentInteractionController 在delegation method的return要return navigationController,若是不用navigation則直接return self就可以。
最後重申一次,QLViewController只能preview,而UIDocumentInteractionController 則是可以support其他App或做比較細節一點的設定,像是可以設定action sheet讓 user選擇要preview、使用其他App開啟或是view dismiss要進行什麼動作之類的。
若只是要preview,QLViewController就可以滿足,其他狀況 UIDocumentInteractionController 還是比較方便。
2015年2月4日 星期三
Suggested App at lockscreen
在FB上的討論串看到的,記錄一下。
http://stackoverflow.com/questions/25897219/can-i-get-my-ios-app-to-appear-on-the-lower-left-corner-of-the-lock-screen
http://stackoverflow.com/questions/26082414/make-app-appear-as-ios-8-suggested-app-at-lockscreen
第一篇是說明目前在lock screen上有兩種情況可以收到message:
1. 裝有App的情況下,由beacon去broadcast message。
2. 未裝有App的情況下,由Apple去broadcast message。
針對上述第二點則有人回答在第二篇,如何可以透過Apple去做這件事:
要透過Apple的report bug頁面去申請,但必須要符合一些限制,App必須直接與環境/地理資訊有相關聯才行。
以下節錄自第二個連結內文,是其他developer去問然後Apple回應的原文:
========
http://stackoverflow.com/questions/25897219/can-i-get-my-ios-app-to-appear-on-the-lower-left-corner-of-the-lock-screen
http://stackoverflow.com/questions/26082414/make-app-appear-as-ios-8-suggested-app-at-lockscreen
第一篇是說明目前在lock screen上有兩種情況可以收到message:
1. 裝有App的情況下,由beacon去broadcast message。
2. 未裝有App的情況下,由Apple去broadcast message。
針對上述第二點則有人回答在第二篇,如何可以透過Apple去做這件事:
要透過Apple的report bug頁面去申請,但必須要符合一些限制,App必須直接與環境/地理資訊有相關聯才行。
以下節錄自第二個連結內文,是其他developer去問然後Apple回應的原文:
========
Here is the answer from Apple Tech Support - read it and weep!
Location relevant Apps are recommended on the lock screen and in the App Store based on a number of factors, including their popularity at the location, and there is no mechanism or process by which an App developer can add their App to the list of recommended Apps. However, if your iOS App is directly related to the location or venue (such as a mall guide iOS App which is published by the mall owner or operator), and you believe your iOS App’s relevance warrants it being included the list of recommended Apps, then you are encouraged to submit an enhancement request via http://bugreport.apple.com/, and request that Apple consider whether your iOS App should be included in the list of recommended Apps for that location. You should provide as much detail in the ’enhancement request' about the App and venue/location as possible, such as the App ID, App Name, URL to the App on the App Store, venue name, venue location (address & lat/lon), the relevance (if any) of your iOS App to the venue/location, and relationship (if any) between you as the developer and the owner/operator of the venue/location. Submission of an enhancement request does not guarantee that a particular iOS App will be added to the list of recommended Apps for a venue or location, and the sole feedback from Apple on the request will come through the http://bugreport.apple.com/bug report system.
2015年1月25日 星期日
Objectvie-C review (features, Delegation, protocol, category, KVC)
也是很久前的draft 囧 都是一些老生常談講到爛到不能再爛的東西,但是每次都會忘掉,就單純做個紀錄,因此此篇非常雜亂!
===================================
Obj-C introduction
dynamic language - dynamic type (id) and binding, a little more effort than C++, but has more flexible
http://rintarou.dyndns.org/2010/12/09/objective-c-淺談/
GC - suspend on iOS & OS X 10.8 (variety of algorithm)
property - access method(auto synthesize), encpulation, dot syntax, attribute configuration, KVO
hint:internal access - directly get and using setter to set instance variables
cocoa vs. cocoa touch
http://www.cnblogs.com/kkun/archive/2012/04/25/2470166.html
protocol
即類似java interface,主要是由於OC本身沒有多重繼承機制,所以protocol
可讓Class之間互相溝通與使用對方的method,protocol最頻繁被使用於
delegate 與 data source DP
Delegation
如我的blog所說,是一種DP讓Class之間可以互動並可委託其他Class執行
自己不希望執行的功能。其class互動與溝通有其他很多方法可以替代,但
是此方法可以充分發揮MVC精神,例如View不應該處理的MC,可透過此
DP完成這種概念。
由於protocol具@optional與@require(default)兩種method的設定,因
此在委託方中implement方法的使用時,要記得當使用@optional的方法時
,要多利用introspection機制確定方法有沒有被conform。
在使用introspection機制時也要再另外注意一件事,就是當method被頻繁
的call or callback時,應該想辦法將introspection機制與頻繁被執行的部分
分隔開來,避免浪費多餘的效能。(performance optimal)
優化機制作法:
override delegate setter,在當中先進行introspection機制並將結果
cache,未來直接使用cache的結果來判斷是否可以執行method即可。
category
在其他language中會發生繼承下來的方法不夠用或是沒找到自己想用的,這時
多數作法是在subclass增加方法,或是被經常用到的方法就新增到superclass裏
,這種情況下若是不複雜的且是自己implement的superclass可能不會造成太大
困擾,但若是接手他人的code或是superclass已經發展到很複雜並且太多subclass
在使用,若不想動到原本的code並且不會讓每個subclass都要繼承新增的method
,category所實現的額外加入method就非常的好用。
若沒有取名的category稱為類別延伸,通常用於隱藏不想public的instance variable
。需注意累目的方法名稱要加上prefix,避免override原始method
其存在主要是實現clean code 想法,透過category可對method分門別類,而不會
導致某個class既肥大又雜散
Observer Desgin Pattern:
KVC - KVO
http://rintarou.dyndns.org/2011/07/22/objective-c-programming-筆記-2/
KVC - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/Overview.html#//apple_ref/doc/uid/20001838-SW1
透過String格式的identifier間接access object properties/instance variable,KVC與@property一樣,會自動使用accessor。
若是instance variable,則會自動建立accessor去存取variable,但因為KVC的判斷方法是 找外內部的accessor ->找變數 ->找不到
,因此一般都會為instance variable套上property,降低效率成本。
符合KVC格式 -
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/Compliant.html#//apple_ref/doc/uid/20002172-BAJEAIEE
Attribut, to-one and Many format
無論Attribute或to-one,找不到key會引用valueForUndefinedKey:回傳一個exception,可自行override這個函數。
attribute :
Simple value,譬如String, bool, int, float, NSNumber等,key path可直接指定variable name,當attribute非object時(scalar type or struct),需implement setNilValueForKey:。
若是scalar type時,setValue需使用NSNumber wrap,可使用literal syntax,另外要注意的是當傳入數字字串時是可以使用的,會自動call NSString的method幫忙轉成NSNumber,但須注意應避免此種狀況,減少效率成本。
若是struct則一定需要implement setter和getter,且setValue時需使用NSValue wrap C struct再傳入,傳入的值會自動unwrap,且在obsevser被call時的change parameter一樣要使用NSValue的getValue去unwrap。
(scalar type or struct) - https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/DataTypes.html#//apple_ref/doc/uid/20002171-BAJEAIEE
to-one :
Object。使用方法 ex: [Object setValue:@“” forKeyPath:@“firstName”];to-many : (NSArray, NSSet, NSDictionary)
1. collection不能使用nil當值,所以value不可直接傳nil,但是可以使用NSNull,會建立一個nil的instance放入。
2. 回傳的非單一值,是同identifier的allvalue
3. 分為indexed (Array )and unorder(set)
KVC implement detail:
https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/SearchImplementation.html#//apple_ref/doc/uid/20000955-CJBBBFFA
原則:
1 .先找是否有@property auto-synthesize的 method(可以被override)或是否有自己根據rule而implement method
2. 若設定可以直接取值,則直接找是否有定義值並取值
3. 都沒有,auto invokes 找不到key的method
Encrypt & Decrypt context in iOS by CommonCryptor and communicate to PHP mcrypt (blowfish, AES, DES, 3DES...)
這是一篇好幾個月前的draft,久到我只記得怎麼做,卻不知道為什麼會這樣做的文章 XD
==============
繼上次使用3rd-party的blowfish加密library,這次換使用iOS public source 中的CommonCryptor library。用好好的幹嘛換?原因是chilkat的試用期限到了 囧,這裡想必會有一個疑問:如果有試用期,明知有試用期,為什麼還使用?因為被誤入歧途,說什麼那個限制是假的......Orz。總之,也是多了解一種3rd-party的library,多學到一些東西囉。
==============
繼上次使用3rd-party的blowfish加密library,這次換使用iOS public source 中的CommonCryptor library。用好好的幹嘛換?原因是chilkat的試用期限到了 囧,這裡想必會有一個疑問:如果有試用期,明知有試用期,為什麼還使用?因為被誤入歧途,說什麼那個限制是假的......Orz。總之,也是多了解一種3rd-party的library,多學到一些東西囉。
在學習CommonCryptor的過程中,其實還有不少內容並不是非常了解,不過至少可以work了 XD
==============
(以下是好幾個月後補的,所以Blowfish的algorithm細節已經記不得了,看到寫死的部份若有疑惑,請查Blowfish的algorithm XD)
這個method是加密的前置作業,在這當中可以看到我對傳入的String轉成Data並加大Data的長度,這是有關於encrypt的input長度,由於PHP以及iOS兩邊實作的Blowfish algorithm本身雖然一樣,但在input以及output可能多少有些不同,詳情要自行到wiki去查查blowfish的algorithm.. XD 但總之長度必須要符合兩邊Blowfish的要求,才不會導致encrypt或是未來decrypt出問題。
另外我對實際做encrypt或decrypt的部分另外寫成一個method,稍後會提到,總之若沒意外,計算完data length後丟入encrypt會return data出來,最後將data convert成String丟回去即可。噢,最後一樣可以看到我對加密後的data長度減8,這也是因為Blowfish的加密algorithm的制式output,詳情一樣請wiki blowfish XD
-(id) encode:(NSString *)str{
NSMutableData *dataStr=[[NSMutableData alloc] initWithData:[str dataUsingEncoding:NSUTF8StringEncoding]];
if (([dataStr length]%8)!=0) {
[dataStr increaseLengthBy:(8-[dataStr length]%8)];
}
NSData *encryptData=[self crypt:kCCEncrypt cinpherText:dataStr];
NSString *returnStr=[BitHelper bytesToHex:(unsigned char*)[encryptData bytes] length:(int)[encryptData length]-8];
return returnStr;
}
這個method則是decrypt的前置作業,當這個method被呼叫的時候,會傳入一串16進位的字串,但此字串資料實際上是byte,所以需convert回去byte型態。同樣的由於PHP以及iOS兩邊Blowfish的input與output不同,所以output的長度我也必須確認,但是相比iOS這邊encrypt後丟給PHP需顧慮PHP看不看得懂,PHP進行encrypt後的output反而只需要確認是否有額外增加長度而填入dirty data即可。因此除了0或1的情況,其餘只要確認收到資料格式最後是否有dirty data並捨棄即可。
-(id) decode:(NSString *)str{
NSMutableString *decodeStr=[[NSMutableString alloc]initWithData:[self crypt:kCCDecrypt cinpherText:[BitHelper hexToBytes:str]] encoding:NSUTF8StringEncoding];
//dirty padding in data, for example:[{"m_id":"44"}]@@@, after "]" character exist some bytes and print can't see that, so need to clear they.
if ([decodeStr length]!=8) {
NSRange range=[decodeStr rangeOfString:@"]" options:NSBackwardsSearch];
NSUInteger datalength=range.location+range.length;
NSMutableData *returnData=[[NSMutableData alloc]initWithData:[self crypt:kCCDecrypt cinpherText:[BitHelper hexToBytes:str]]];
[returnData setLength:datalength];
return returnData;
}
return [self crypt:kCCDecrypt cinpherText:[BitHelper hexToBytes:str]];
}
重頭戲來了,在這method中可以看到使用了CCCryptorStatus的variable以及CCCrypt的C function,這是由iOS的CommonCryptor library所提供的,CCCryptorStatus是用來判斷加解密的status是成功或失敗,最重要的是在CCCrypt,當把所有參數丟入CCCrypt並成功加解密後就會取得Bytes型態的資料,回傳後再交給NSData處理即可,這樣就完成了iOS的加解密功能了!P.S.:
1.
由於是因為和PHP串接,所以會需要自己確認data length以及有沒有dirty data,若是encrypt以及decrypt的input與output都是來自iOS的CommonCryptor的話,就不需要這些步驟了,因為iOS的CommonCryptor會看得懂自己做的input與output。
2.
CCCrypt必須放入很多個參數,我有的已經有點忘了,我就其中記得的說明一下:
operation - 在encode或decode裏可看到,也就是告知CCCrypt我現在要做decrypt或encrypt
kCCAlgorithmBlowfish - trace這個常數就可以知道,這是告知CCCrypt要用什麼algorithm去做,即使是要使用別的加解密演算法,像是AES, DES或3DES這些加密演算法,其實這個function都已經做好,是一個非常方便的library!
kCCOptionPKCS7Padding - 就是data的padding
[KeyAscii bytes] - Blowfish用來加解密的key,由於是C function,所以必須丟入bytes型態。
[ivAscii bytes] - Blowfish另一把key,印象中是在上一把key與data XOR後,再XOR這把key做二度加密 (不一定正確,細節忘了 XD)
[data bytes] - 愈加解密的資料
[datalength]- 資料的長度
buffer - 資料加解密後會被放在這個buffer中,回傳後記得free掉自行malloc的buffer。
bufferSize - 告知buffer有多大
&numBytesCrypted - 實際收到的buffer的長度
-(NSData *)crypt:(uint32_t) operation cinpherText:(NSData *) data{
NSData *keyAscii = [@"5399602753996027" dataUsingEncoding:NSUTF8StringEncoding];
NSData *ivAscii = [@"53996027" dataUsingEncoding:NSUTF8StringEncoding];
size_t bufferSize = 2048;
size_t datalength=[data length]+8;
if (operation==kCCEncrypt)
datalength=[data length];
void *buffer = malloc(bufferSize);
size_t numBytesCrypted = 0;
CCCryptorStatus destatus = CCCrypt(operation, kCCAlgorithmBlowfish,
kCCOptionPKCS7Padding,
[keyAscii bytes], [keyAscii length],
[ivAscii bytes],
[data bytes], datalength, /* input */
buffer, bufferSize, /* output */
&numBytesCrypted);
// NSLog(@"get %lu %lu %p %d", bufferSize, numBytesDecrypted, data, destatus);
if (destatus == kCCSuccess && operation==kCCDecrypt) {
//the returned NSData takes ownership of buffer and will free it on dealloc
return [NSMutableData dataWithBytesNoCopy:buffer length:numBytesCrypted];
}else if(destatus == kCCSuccess && operation==kCCEncrypt)
return [NSMutableData dataWithBytesNoCopy:buffer length:numBytesCrypted];
free(buffer); //free the buffer;
return nil;
}
================
老實說這篇其實有點慚愧,現在寫出來只是為了消化一些draft,我原本想說可以完整的解釋每個細節以及blowfish algorithm再寫出來,但最後還是沒有完成,可能是後來的工作在加解密這塊沒什麼需求,所以我就懶了吧.. XD 希望自己未來有一天可以補上這邊的knowledge Orz
2015年1月23日 星期五
Design Pattern in iOS (Singleton, notification, delegation, KVC-KVO, class cluster)
嗚哇~好幾個月沒發表啦 囧 其實是一直寫在draft而且整理不完,哭哭 Orz
先分享最近工作上的presentation slide好了,不過是簡單屬於Developer都知道
的東西就是 XD
http://www.slideshare.net/YiShouChen/design-patterns-in-ios
就加減看一下啦 XD
先分享最近工作上的presentation slide好了,不過是簡單屬於Developer都知道
的東西就是 XD
http://www.slideshare.net/YiShouChen/design-patterns-in-ios
就加減看一下啦 XD
2014年9月8日 星期一
[問題] APNS通知 (My answer for question in MacDev)
這個問題不長就不簡述了,最後倒是有不小心稍稍念了這位發問者 XD 我是覺得念得有理,畢竟APN不是什麼冷門問題,網路上一堆中文資源,還有很貼心的文章會解釋APNs原理,沒這麼難姑狗吧!?
作者 flamelad (flamelad) 看板 MacDev
標題 Re: [問題] APNS通知
時間 Mon Aug 25 00:45:04 2014
───────────────────────────────────────
※ 引述《haves560 (新鮮人)》之銘言:
: 我是用UILocalNotification接收到APNS訊息後
: 顯示在app上面,可是遇到個問題,我把程式關閉後沒辦法push
: 請教一下 各位在做APNS push都是用什麼方式讓程式關閉後還能接收的到?
問題描述有點不清楚,我先假設你的情況有兩種:1. 希望程式退到背景後,還可以收到APN 後讓App執行某些動作。 2. 程式完全關閉,不在foreground or background 執行,希望Device能收到APN後,讓App執行某些動作。
假設1:
若如1 的假設,則你必須了解UIApplication State。確切來說,你應該要知道什麼是背景處理,當然你若希望在App的其他階段執行你的動作,UIApplication State will help you more.
另外下面這連結的文章,很清楚的說明iOS7在背景處理的狀況。
http://onevcat.com/2013/08/ios7-background-multitask/
假設2:
若如2的假設,則情況與1不同,簡單來說,當App在not running狀態下時,Device收到APN後,iOS不會去替使用者執行App以及讓App執行某些動作,你可能需要多了解...呃,下段說明。
可以看得出你在這部分所遇到的問題是你不太熟悉相關議題,因此建議你需要好好了解一下APNs、App lifecycle、前/背景處理差異、UIApplication State以及各種Notification的使用時機與用途,相信會對你在這邊遇到的問題有很大的幫助。
最後算是我雞婆murmur,還請忍耐一下,有任何讓你感到不舒服的地方請多見諒:)
這部分算是挺熱門的議題,相比其他問題,網路上姑狗一下關鍵字有很多相關的繁體資源以及衍伸議題,未來希望可以先稍微姑狗一下,我始終相信除了來自他人幫助以外,慢慢培養獨立解決問題的能力以及享受解決問題後所帶來的成就感,這種良好的自我循環,才是成就一個好的開發者的最重要因素。我也剛踏在這路上,共勉之 :)
[問題] UINavigationController and Camera (My answer for question in MacDev)
發問者沒有很清楚描述問題,所以假設問題是想詢問使用UIImagePickerController時,NavigationBar消失了以及回不到rootView。
作者 flamelad (flamelad) 看板 MacDev
標題 Re: [問題] UINavigationController and Camera
時間 Sun Aug 24 00:39:08 2014
───────────────────────────────────────
※ 引述《stevenlin08 (stevens)》之銘言:
: hi all,
: 請問,若第一個頁面是TableViewController,而我將會導航*1到
: 另一個viewController(B),並開啓照相。
: 此時,會使原本的NavigationBar 消失。
: 導致我沒法退出到rootView .
: *1:
: 用pushViewController: view(B)推入控制器。
: 目前,我認為有一列方式,但還是沒法成功。
: 1.要如何讓NavigationBar 出現?
: 2.使用popViewControllerAnimated:並無法使畫面回覆
這部分同樣並非很熟悉,就直接回應於板上給其他版友指正:) 你的文章中缺少一些細
節,另外我也並不太懂你的*1的意思,因此我先假設幾件事情:
a. 是一般tableView中的cell點了會導向另一個ViewController。
b. 在另一個ViewController中的somewhere invoke UIImagePickerController。
c. 照著一般UIIPC最簡單的範例去實作Camera功能的呼叫。
問題1:
若是因為要解決問題2才有問題1,那這應該沒問題了。若不是,可以使用
isNavigationBarHidden確認是否NavigationBar在invoke Camera時被設定為hidden。
問題2:
請在imagePickerControllerDidCancel中,先dismiss掉正在使用的UIIPC,再
pop回rootView即可。
[self dismissViewControllerAnimated:YES completion:^{}];
[self.navigationController popToRootViewControllerAnimated:YES];
[問題] 請教AVAudioPlayer小問題 (My answer for question in MacDev)
原問題是詢問AudioToolBox,不過我沒使用過AVFundation相關類別,所以在這個問題的往來回信中,我是使用AVAudioPlayer進行測試。
問題簡述:有關AVFundation中的AVAudioPlayer在連續播放音效時,似乎在音效之間會有些許間隔的存在問題。
作者 flamelad (flamelad)
標題 Re: F大您好 請教AudioToolBox小問題
時間 Sat Aug 16 21:32:26 2014
───────────────────────────────────────
: 不好意思又打擾了
: 程式其實寫得差不多了
: 只是有些小問題不知道怎麼處理
: 想跟您請叫關於AudioToolBox的音效播放 不知您是否熟悉
: 由於我本來按鈕播放音效是用AVAudioPlayer
: 但聲音跑出來都會延遲個零點幾秒 很短的延遲 但是還是有感
: 對音樂軟體來說有些不太流暢
: 現在是考慮用AudioToolBox來播放
: 因為音效聲音跟我手觸碰幾乎同步反應 沒感覺到延遲
: 雖然無法調整音量 跟其他控制 但就是反應很快
: https://www.youtube.com/watch?v=bq7ldV9Wsnc
: 想請問一下F大
: 我用AudioToolBox播放 發現音跟音之間都會重疊
: 譬如第一個音還沒結束的時候 我再按第二個音, 第一個音不會消失 變成重疊存在
: 有辦法讓就只有最後一個點擊的有聲音 而之前的都被停止嗎?
: 就是只有單一個按鍵的聲音存在而已
: Thank you so much!
問題簡述:有關AVFundation中的AVAudioPlayer在連續播放音效時,似乎在音效之間會有些許間隔的存在問題。
作者 flamelad (flamelad)
標題 Re: F大您好 請教AudioToolBox小問題
時間 Sat Aug 16 21:32:26 2014
───────────────────────────────────────
Hello, 我先把上一封信打太快造成些謬誤的地方修正一下:p
在上一封信中我闡述了alloc放在Button中所造成的問題,這邊我並不是想說延遲,而是重新又被assign一次,所以才會有第二次點擊就會中斷第一次的播放,並非延遲,因此你將alloc放在其他地方使用,就會發現第一次點擊後的音效並不會被中斷。
回到你的問題,我重新思考一次,想要seamless播放音效,又不希望會重疊,我想一想,也許只是一個很簡單的問題。這邊真的挺不好意思,中午真的太趕沒好好仔細review寄給你的信,因為盲點在於AVAudioPlayer會有延遲感並非是program運作的問題,而是沒有對症下藥。你可以試試使用AVAudioPlayer,但是button 的 Sent Event改為TouchDown,而不是TouchUpInside,我想應該就能解決問題了。
試試看吧,有問題再來信討論吧 :)
: 不好意思又打擾了
: 程式其實寫得差不多了
: 只是有些小問題不知道怎麼處理
: 想跟您請叫關於AudioToolBox的音效播放 不知您是否熟悉
: 由於我本來按鈕播放音效是用AVAudioPlayer
: 但聲音跑出來都會延遲個零點幾秒 很短的延遲 但是還是有感
: 對音樂軟體來說有些不太流暢
: 現在是考慮用AudioToolBox來播放
: 因為音效聲音跟我手觸碰幾乎同步反應 沒感覺到延遲
: 雖然無法調整音量 跟其他控制 但就是反應很快
: https://www.youtube.com/watch?v=bq7ldV9Wsnc
: 想請問一下F大
: 我用AudioToolBox播放 發現音跟音之間都會重疊
: 譬如第一個音還沒結束的時候 我再按第二個音, 第一個音不會消失 變成重疊存在
: 有辦法讓就只有最後一個點擊的有聲音 而之前的都被停止嗎?
: 就是只有單一個按鍵的聲音存在而已
: Thank you so much!
[問題] 請教如何改變UIButton的highlighted狀態? (My answer for question in MacDev)
引用:http://www.ptt.cc/bbs/MacDev/M.1407647206.A.BD3.html
原文章問題簡述:如何手指不離開螢幕觸發多個Object在ptt上回應了一篇個人認為算是有通盤回應到答案的文章,如下。(回覆部分黑底反白)
作者 flamelad (flamelad) 看板 MacDev
標題 Re: [問題] 請教如何改變UIButton的highlighted狀態?
時間 Sun Aug 10 13:06:43 2014
───────────────────────────────────────
關於你的問題昨天原本想回信,但因為太晚又考慮到我並不是非常熟悉,所以就沒回
應了。由於你來信詢問,那我會盡我綿薄之力提供建議,不對之處還請多見諒。另外這篇
我就直接回應到版上占用一些版面,讓版友可以指出我不對之處或提供更佳解 :)
※ 引述《pistols (我不想上報 別寄信啦)》之銘言:
: 請問一下版友
: 我想設置多個UIButton
: 譬如我從xcode右下角拉了九個UIButton放到ViewControl
: 排列就像電話的按鈕 1 2 3...9這樣九宮格的排列
: 我想設計每個按鈕的state狀態為highlighted時 會產生個別的反應或音效
: 可是忽然發現UIButton的highlighted的特性跟我想的不太一樣
: 譬如當我按住button1時候 就會有highlighted
: 但是我手指拖移離開button1 移到button2的範圍內時
: button1的highlighted仍然未消失 button2也沒有出現highlighted
就如上次你詢問時的解答,假如你只是想要click button 後可以得到被點擊後或點住
不放的狀態,那isHighLighted 就可以得到你想要的結果,否則應該使用其他的-(method)
或判斷。(請務必參考isHighLighted 的description)
另外就我所了解的是,當你手指未離開屏幕而移動,整體來說只會是某個 Object 的
a series of events,包括Inside, Outside, DragExit等,而不是手指從button1 拖曳到
button2 就會trigger button2 的event。
: 想請問版友
: 我如果想讓每一個button只要是手指有接觸到該按鈕的範圍內就會有highlighted反應
: 而一離開或是拖移超出範圍馬上就不會有highlighted
: 我該如何設置呢?
這並不難,請參考UIButton繼承的UIControl中的一些method,主要是需要改變按下
button的default UIControlEvent。
: 譬如像上面說的例子
: 當我手指離開button1範圍 移到button2範圍的時候
: 如何讓button1的highlighted馬上消失 而變成button2的highlighted跑出來
這例子若是手指並不離開屏幕,則與上一段你所希望的並不相同,請見第一段的解釋
。若你想有手指不離開屏幕而觸發多個 Objects,應該使用Gesture Recognizer或是版友
所提到的UITouch中的-(method)。
: 是要拉每個按鈕的IBOutlet到interface底下 增加什麼判定的屬性嗎?
: 我是有試過拉IBAction 然後用touch drag outside或是drag inside等等
: 但都不會跑出我所說的那樣
: 而且 我的功能是用按鈕的state去做反應的
: 希望版友可幫忙解答一下
: 非常感謝!
請參考UIControl。另外若有拉IBAction,每當你觸發了版面上的某個Object event時
,則IBAction中常見的sender就是被觸發Object的instance,你可以借由這個sender去改
變行為。
以上,大致上是我的理解,希望有幫助:)
Edit:
最後一段有些謬誤的地方,不好意思,趕吃飯:p
謬誤:
1. 在button中的sender並不該是改變event,而是增減一些event才對。
2. 若是要修改該button的event,一般也不會在該button中實現,而是如你
所說,另外declare一個IBOutlet,然後去增加該button的event
[問題] 如何讓兩個按鈕一起按會有獨立事件? (My answer for question in MacDev)
有點久沒更新,罪惡啊~不過這也不能怪我,原本預計要寫iOS如何與php傳送加解密的資料,但原理部分實在有點難寫,這一兩個禮拜再來完成它。接下來一系列是將我在其他地方替其他人解答的文章或往來信件,轉錄過來做個記錄,哪天也需用得到。
原問題及回覆:(回覆部分黑底反白)
作者 flamelad (flamelad)
標題 Re: [問題] 如何讓兩個按鈕一起按會有獨立事件?
時間 Sat Jul 26 01:59:14 2014
───────────────────────────────────────
: 想請教板友們
: 關於iOS開發的按鈕問題
: 譬如設計個音樂遊戲
: 按了A按鈕會有個IBAction方法 是發出Sound A的聲音
: 並另外再設計B跟C按鈕 但是按下去不具任何聲音
: 想請問一下
: 如果我想讓它有另外一個功能:
: "當B按鈕按住 再按A按鈕 才會產生Sound B的聲音"
: "當C按鈕按住 再按A按鈕 才會產生Sound C的聲音"
: 我應該要在A按鈕的IBAction方法怎麼寫才會有
: "按A = Sound A聲" "B按住又按A = Sound B聲" "C按住又按A = Sound C聲"
: 就是把A鈕當作發聲的主事者 B跟C只是疊加A用來改變聲音
: 請問這樣的功能大概是要如何寫?
: 希望板友可幫忙解答一下! 感謝!
: p.s. 另外 聲音的部分由於是短短的音效 我使用AudioToolbox去寫
: 實機測試才發現 音量無法從機身的音量按鍵調整大小聲....
: 如果使用短音音效比較推薦用哪種框架的呢?
我是資淺開發者,就獻醜說說有關button的想法,覺得不好或根本是個誤會,
還請多諒解:)
1.
寫一個-method裡頭含有button的istracking判斷,用來判斷buttonB以及buttonC的
UIControlEvents狀態,再透過tag或title判斷哪個button被按下。declare一個變數值,
並根據-method中的判斷是來指定數值,可以是1,2,3......,總之,就是用來當buttonA
按下時,判斷該使用什麼音效。
大致上是這樣:
UIButton *buttonB & *buttonC -> init button並各指定Down與cancel給B與C,並含有
一個@selector(-method)-> -method寫判斷式去判斷button以及利用istracking判斷
button狀態->修改一個@property的變數值為0,1,2其中一個 -> ButtonA按下時根據變數
選擇音效發出。
2.
用notificationcenter去監聽buttonB&C狀態,其餘判斷與構想差不多跟1一樣
以上是一點淺見,不好用或根本誤解了還請多見諒:)
作者 flamelad (flamelad)
標題 Re: [問題] 如何讓兩個按鈕一起按會有獨立事件?
時間 Sat Jul 26 12:14:35 2014
───────────────────────────────────────
另外看到有版友說能使用highlighted這個State,在這邊補述一下,button的event有
各種不同狀況,那假定是最常見Down、Cancel與UpInside,highlighted可能不足夠滿足你
的條件。當button TouchDown的時候,isTracking與isHighLighted都會等於YES,但是當
button觸發的event是UpInside時,isTracking會等於NO,但isHighLighted會等於YES,這
在Description中也有提到。
簡而言之,不管是Cancel或UpInside,istracking都會改變狀態,但isHighLighted只
有在Cancel時,才會改變狀態。另外,是我昏了頭,確實不需要額外寫-method,一時忘記
直接使用isTracking在buttonA中判斷buttonB&C的狀態即可,不好意思:P
原問題及回覆:(回覆部分黑底反白)
作者 flamelad (flamelad)
標題 Re: [問題] 如何讓兩個按鈕一起按會有獨立事件?
時間 Sat Jul 26 01:59:14 2014
───────────────────────────────────────
: 想請教板友們
: 關於iOS開發的按鈕問題
: 譬如設計個音樂遊戲
: 按了A按鈕會有個IBAction方法 是發出Sound A的聲音
: 並另外再設計B跟C按鈕 但是按下去不具任何聲音
: 想請問一下
: 如果我想讓它有另外一個功能:
: "當B按鈕按住 再按A按鈕 才會產生Sound B的聲音"
: "當C按鈕按住 再按A按鈕 才會產生Sound C的聲音"
: 我應該要在A按鈕的IBAction方法怎麼寫才會有
: "按A = Sound A聲" "B按住又按A = Sound B聲" "C按住又按A = Sound C聲"
: 就是把A鈕當作發聲的主事者 B跟C只是疊加A用來改變聲音
: 請問這樣的功能大概是要如何寫?
: 希望板友可幫忙解答一下! 感謝!
: p.s. 另外 聲音的部分由於是短短的音效 我使用AudioToolbox去寫
: 實機測試才發現 音量無法從機身的音量按鍵調整大小聲....
: 如果使用短音音效比較推薦用哪種框架的呢?
我是資淺開發者,就獻醜說說有關button的想法,覺得不好或根本是個誤會,
還請多諒解:)
1.
寫一個-method裡頭含有button的istracking判斷,用來判斷buttonB以及buttonC的
UIControlEvents狀態,再透過tag或title判斷哪個button被按下。declare一個變數值,
並根據-method中的判斷是來指定數值,可以是1,2,3......,總之,就是用來當buttonA
按下時,判斷該使用什麼音效。
大致上是這樣:
UIButton *buttonB & *buttonC -> init button並各指定Down與cancel給B與C,並含有
一個@selector(-method)-> -method寫判斷式去判斷button以及利用istracking判斷
button狀態->修改一個@property的變數值為0,1,2其中一個 -> ButtonA按下時根據變數
選擇音效發出。
2.
用notificationcenter去監聽buttonB&C狀態,其餘判斷與構想差不多跟1一樣
以上是一點淺見,不好用或根本誤解了還請多見諒:)
作者 flamelad (flamelad)
標題 Re: [問題] 如何讓兩個按鈕一起按會有獨立事件?
時間 Sat Jul 26 12:14:35 2014
───────────────────────────────────────
另外看到有版友說能使用highlighted這個State,在這邊補述一下,button的event有
各種不同狀況,那假定是最常見Down、Cancel與UpInside,highlighted可能不足夠滿足你
的條件。當button TouchDown的時候,isTracking與isHighLighted都會等於YES,但是當
button觸發的event是UpInside時,isTracking會等於NO,但isHighLighted會等於YES,這
在Description中也有提到。
簡而言之,不管是Cancel或UpInside,istracking都會改變狀態,但isHighLighted只
有在Cancel時,才會改變狀態。另外,是我昏了頭,確實不需要額外寫-method,一時忘記
直接使用isTracking在buttonA中判斷buttonB&C的狀態即可,不好意思:P
2014年8月17日 星期日
NSNotificationCenter
同樣是很久前就解決的問題...積了不少文章 囧
這個類別在我剛接觸時其實有稍微困擾過,後來再姑狗上看到了同是Stanford的教學卻有附註解釋,真是容易懂太多了,不常用到時會經常忘記,就發這篇記錄一下囉。
透過defaultCenter這個+(method)來alloc與init一個NSNotificationCenter instance,在調用下方的-(method)即可實現監視物件活動的方法。
NSNotificationCenter *center=[NSNotificationCenter defaultCenter];
addObserver - 誰來收通知(通常是self)
selector - 當收到通知時被調用的方法
name - 決定監視該發出通知的情況類型,通常是已經預先define好的字串
object - 被監視的對象
NSNotificationCenter
- (void)addObserver:(id)observer // you (the object to get notified)
selector:(SEL)methodToInvokeIfSomethingHappens
name:(NSString *)name // name of station (a constant somewhere)
object:(id)sender; // whose changes you’re interested in (nil is anyone’s) You will then be notified when there are broadcasts
You will then be notified when there are broadcasts
- (void)methodToInvokeIfSomethingHappens:(NSNotification *)notification
{notification.name // the name passed above
notification.object // the object sending you the notification notification.userInfo // notification-specific information about what happened
}
How to implement serial execution of GCD queue?(group, barrier, serial)
廢話time:
原本打算是從上一篇文章開始都用英文撰寫來練習英文寫作,但是打完上一篇文章後卻覺得,繁體中文資源已經不多,很多技術文件或討論文件在中文搜尋上根本是零零落落或乾脆搜尋不到相關資料,因此還是改變決定,繼續以中文撰寫,算是勉強盡一份心力於中文資源。
積存已久的問題,雖然早已解決,但是GCD的部分還是沒有很熟,還需要了解NSOperationQueue與NSThread的差別,現在主要在熟悉CS193p的文件,等未來有空再發一篇文章補齊三者的使用時機。
在main thread 使用NSURLConnection,建立一個thread等待資料庫讀完,再回到main thread執行一些code,在program裡面看起來如下:
//part.1
[NSURLConnection *myDB=[...];
//概要來說是使用POST Method, 送NSURLrequest以及設定delegate為self,
//在NSURLconnection的protocol - connection didRecievedata實現一個loadprogress
//part.2
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue,^{
while (myDB.loadprogress!=1){
//這裡只是等待progress=1, 就是讓data收完
}
dispath_async(dispatch_get_main_queue, ^{
//data收完,回到main thread去做事,例如轉換格式,取資料,填資料到tableview等
});
});
//part.3
//這邊繼續做main thread的事
現在問題在於,假使我希望part3在某個片段可以等待part2完成(收data)再繼續做事,比較好的寫法是什麼?
Solution:
GCD有group、serial或barrier的建立方式,都可以實現等待上個thread完成後再執行的效果。以下是一些簡單的implement:
barrier - 如同barrier的意思,會擋住下游的thread執行直到上游的thread執行完畢以及本身thread執行完畢,方讓下游的thread繼續執行。
dispatch_queue_t queue=dispatch_queue_create("flamelad", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
for (int i=0; i<3; i++) {
NSLog(@"concurrent:%d\n",i);
}
});
dispatch_barrier_async(queue, ^{
for (int i=0; i<3; i++) {
NSLog(@"barrier:%d\n",i);
}
});
dispatch_async(queue, ^{
for (int i=0; i<3; i++) {
NSLog(@"concurrent1:%d\n",i);
}
});
// 輸出結果:
// 2014-08-17 01:58:42.464 Sherlock[2836:1303] concurrent:0
// 2014-08-17 01:58:42.465 Sherlock[2836:1303] concurrent:1
// 2014-08-17 01:58:42.466 Sherlock[2836:1303] concurrent:2
// 2014-08-17 01:58:42.467 Sherlock[2836:1303] barrier:0
// 2014-08-17 01:58:42.468 Sherlock[2836:1303] barrier:1
// 2014-08-17 01:58:42.469 Sherlock[2836:1303] barrier:2
// 2014-08-17 01:58:42.470 Sherlock[2836:1303] concurrent1:0
// 2014-08-17 01:58:42.470 Sherlock[2836:1303] concurrent1:1
// 2014-08-17 01:58:42.471 Sherlock[2836:1303] concurrent1:2
serial- 與concurrent不同(很明顯吧XD),queue中的每一個thread會循序處理,FIFO
dispatch_queue_t serial=dispatch_queue_create("flamelad", NULL);
dispatch_async(serial, ^{
for (int i=0; i<3; i++) {
NSLog(@"serial:%d\n",i);
}
});
dispatch_async(serial, ^{
for (int i=0; i<3; i++) {
NSLog(@"serial2:%d\n",i);
}
});
dispatch_async(serial, ^{
for (int i=0; i<3; i++) {
NSLog(@"serial3:%d\n",i);
}
});
// 輸出結果
// 2014-08-17 02:19:43.616 Sherlock[2898:1303] serial:0
// 2014-08-17 02:19:43.626 Sherlock[2898:1303] serial:1
// 2014-08-17 02:19:43.643 Sherlock[2898:1303] serial:2
// 2014-08-17 02:19:43.644 Sherlock[2898:1303] serial2:0
// 2014-08-17 02:19:43.646 Sherlock[2898:1303] serial2:1
// 2014-08-17 02:19:43.648 Sherlock[2898:1303] serial2:2
// 2014-08-17 02:19:43.649 Sherlock[2898:1303] serial3:0
// 2014-08-17 02:19:43.650 Sherlock[2898:1303] serial3:1
// 2014-08-17 02:19:43.651 Sherlock[2898:1303] serial3:2
group - group有notify和wait方式可以實現類似barrier的效果,不同處在於可以做一些細節上的設定。從輸出結果即可知wait會等待上游thread完成,notify則會等到group中所有thread完成。
dispatch_queue_t queue=dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group=dispatch_group_create();
dispatch_group_async(group,queue,^{
for (int i=0; i<3; i++) {
NSLog(@"group:%d\n",i);
}
});
dispatch_group_async(group,queue,^{
for (int i=0; i<3; i++) {
NSLog(@"group2:%d\n",i);
}
});
// 可設定等待下游的thread等待上游thread多久時間後開始執行,FOREVER則是等到上游執行完成後。
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_group_async(group,queue,^{
for (int i=0; i<3; i++) {
NSLog(@"group3:%d\n",i);
}
});
dispatch_group_notify(group,queue,^{
for (int i=0; i<3; i++) {
NSLog(@"group4:%d\n",i);
}
});
dispatch_group_async(group,queue,^{
for (int i=0; i<3; i++) {
NSLog(@"group5:%d\n",i);
}
});
// 輸出結果
// 2014-08-17 02:32:54.587 Sherlock[3001:130b] group:0
// 2014-08-17 02:32:54.587 Sherlock[3001:3c07] group2:0
// 2014-08-17 02:32:54.588 Sherlock[3001:130b] group:1
// 2014-08-17 02:32:54.588 Sherlock[3001:3c07] group2:1
// 2014-08-17 02:32:54.590 Sherlock[3001:130b] group:2
// 2014-08-17 02:32:54.591 Sherlock[3001:3c07] group2:2
// 2014-08-17 02:32:54.591 Sherlock[3001:130b] group3:0
// 2014-08-17 02:32:54.592 Sherlock[3001:3c07] group5:0
// 2014-08-17 02:32:54.593 Sherlock[3001:130b] group3:1
// 2014-08-17 02:32:54.593 Sherlock[3001:3c07] group5:1
// 2014-08-17 02:32:54.594 Sherlock[3001:130b] group3:2
// 2014-08-17 02:32:54.595 Sherlock[3001:3c07] group5:2
// 2014-08-17 02:32:54.596 Sherlock[3001:3c07] group4:0
// 2014-08-17 02:32:54.597 Sherlock[3001:3c07] group4:1
// 2014-08-17 02:32:54.598 Sherlock[3001:3c07] group4:2
這篇只介紹了三種最常用到的GCD thread執行方式來解決我的問題,但其實尚有些如dispatch_once、dispatch_semaphore_t等的執行方式,有興趣者再自行姑狗,都是在實現multi-thread石,可能會用到的方法。
2014年7月27日 星期日
Some problems with my development Part.1 (tabBar, navigationItem, Segue)
since the article, I will use English to write my blog. If there are any problems in my blog, please tell me, thanks.
[self.navigationController.navigationBar.topitem setTitle:NSString];(This is wrong!!)
There are three button types in navigationBar:
a. leftBarButtonItem, you can define a custom leftBarButtonItem of navigationBar in the view controller where the button is.
b. backBarButtonItem, you can define custom backBarButtonItem of navigationBar in the superview controller where the button is.
c. default Button, if you don't define anything(left and back all nil), navigationController will auto-generate a back button.
setBackBarButtonItem method: Important! Assuming now have two view controllers which called A&B, and you want to change B's back Button. So setBackBarButtonItem must be wrote in A.
P.S.: Left/back button instance variable is nil at begin in the navigationController, if want to change anything for left/back button, you must to create an UIButton object and assign to navigationController.
a. When you establish push relationship between view controllers, don't make it on button. Building it at any non-trigger component.
b. Using the method which show as below to jump to next view after complete all what you want to execute.
[self performSegueWithIdentifier:NSString sender:(id)]
1. How to edit tabBar items in tabBarController?
[[self.tabBarController.tabBar.Items objectAtIndex:(Integer)] setTitle:(NSString)]
2. how to edit/define back/leftBarButton's title in navigationController?
There are three button types in navigationBar:
a. leftBarButtonItem, you can define a custom leftBarButtonItem of navigationBar in the view controller where the button is.
b. backBarButtonItem, you can define custom backBarButtonItem of navigationBar in the superview controller where the button is.
c. default Button, if you don't define anything(left and back all nil), navigationController will auto-generate a back button.
setBackBarButtonItem method: Important! Assuming now have two view controllers which called A&B, and you want to change B's back Button. So setBackBarButtonItem must be wrote in A.
// backBarButtonItem doesn't need to put target and action, because it will work as function of back button.
[[UIBarButtonItem alloc] initWithTitle:@"Customize backButton"
style:UIBarButtonItemStyleBordered
target:nil
action:nil];
[[self navigationItem] setBackBarButtonItem:newBackButton];
setLeftBarButtonItem method:
Important! Writing these codes to customize button in view controller which you want to customize it.
// Don't forget to put target and action, or it doesn't work as button.
[[UIBarButtonItem alloc] initWithTitle:@"Customize leftButton"
style:UIBarButtonItemStyleBordered
target:self
action:@selector(-method)];
[[self navigationItem] setLeftBarButtonItem:newBackButton];
P.S.: Left/back button instance variable is nil at begin in the navigationController, if want to change anything for left/back button, you must to create an UIButton object and assign to navigationController.
3. Performing segue after executing something what you want to do.
There are two steps:a. When you establish push relationship between view controllers, don't make it on button. Building it at any non-trigger component.
b. Using the method which show as below to jump to next view after complete all what you want to execute.
[self performSegueWithIdentifier:NSString sender:(id)]
2014年7月5日 星期六
chilkat blowfish for iOS data transmission PART3
這兩三個禮拜工作下來,發現其實沒什麼時間可以更新這邊的文章,上班拼命找solution,下班死命看knowledge,未來到勉強上手前,可能真的只會有筆記式的文章留在這了。
然後新人想去公司培養能力真的要慎選公司,公司沒有好的規劃也沒有專業領域前輩的話,進去只會非常非常非常的吃力,而且會浪費許多時間走彎路。
以上這意見僅供給想安穩過生活的人參考,在沒有不合理對待的前提下(像是薪資22k、責任制、要求幾天內要有成果),我認為做一件事最重要的是有沒有『興趣』,雖然我累得要命,但卻也累的快樂。『愛你所選』我認為是這麼解釋的:做你有興趣或有目的的事,並一直持續保持熱情地去做,而不是什麼把工作當成興趣,那只是無法朝向自己目標前進的人以及資方壓榨勞方的理由。人生短短幾十年,有必要把1/3或更多的時間花在自己其實並不感興趣的工作上嗎?三個傻瓜的道理,『追求卓越,成功自然隨之而來』,加油!
不廢話了,下面說明最後我實做的部分。
先建立Blowfish的header file,並在前面繼上回的chilkat blowfish for iOS data transmission PART1, chilkat blowfish for iOS data transmission PART2已經設定好的CkoCrypt2的header file import進來(或@class),並建立encode與decode兩個實體方法(或要建類別方法也行)以及一個CkoCrypt2的物件供其它函數的使用。
以上,就是非常簡單但我浪費很多時間的chilkat的blowfish加密方式Orz
然後新人想去公司培養能力真的要慎選公司,公司沒有好的規劃也沒有專業領域前輩的話,進去只會非常非常非常的吃力,而且會浪費許多時間走彎路。
以上這意見僅供給想安穩過生活的人參考,在沒有不合理對待的前提下(像是薪資22k、責任制、要求幾天內要有成果),我認為做一件事最重要的是有沒有『興趣』,雖然我累得要命,但卻也累的快樂。『愛你所選』我認為是這麼解釋的:做你有興趣或有目的的事,並一直持續保持熱情地去做,而不是什麼把工作當成興趣,那只是無法朝向自己目標前進的人以及資方壓榨勞方的理由。人生短短幾十年,有必要把1/3或更多的時間花在自己其實並不感興趣的工作上嗎?三個傻瓜的道理,『追求卓越,成功自然隨之而來』,加油!
不廢話了,下面說明最後我實做的部分。
#import#import "CkoCrypt2.h" @interface BlowFish : NSObject -(NSString *) encode:(NSString *)str; -(id) decode:(NSString *)str; @end
先建立Blowfish的header file,並在前面繼上回的chilkat blowfish for iOS data transmission PART1, chilkat blowfish for iOS data transmission PART2已經設定好的CkoCrypt2的header file import進來(或@class),並建立encode與decode兩個實體方法(或要建類別方法也行)以及一個CkoCrypt2的物件供其它函數的使用。
#import "BlowFish.h"
@interface BlowFish()
@property CkoCrypt2 *crypt;
@end
@implementation BlowFish
-(instancetype)init{
self = [super init];
_crypt = [[CkoCrypt2 alloc] init];
NSString *keyAscii = @"1234567812345678";
NSString *ivAscii = @"12345678";
if([_crypt UnlockComponent: @"Anything for 30-day trial"]){
_crypt.CryptAlgorithm=@"blowfish2";
_crypt.CipherMode = @"cbc";
_crypt.EncodingMode = @"hex";
_crypt.KeyLength = [NSNumber numberWithInt:256];
_crypt.PaddingScheme = [NSNumber numberWithInt:3];
[_crypt SetEncodedIV: ivAscii encoding: @"ascii"];
[_crypt SetEncodedKey: keyAscii encoding: @"ascii"];
}
else
NSLog(@"trail day is exceeded");
return self;
}
-(NSString *) encode:(NSString *)str{
return [_crypt EncryptStringENC:str];
}
-(id) decode:(NSString *)str{
return [_crypt DecryptStringENC:str];
}
@end
implement裡面其實就沒什麼好說的,就是在init裡面把前面part1與part2說明過的一一設定完成即可,最後encode與decode方法return一個NSString的物件,那內容當然是encode或decode後的東西囉。
... BlowFish *blowfh=[[BlowFish alloc] init]; //別忘了要init,在BlowFish中的所有設定都是放在init裡。 NSString *encodeStr=[blowfh encode:@"123"]; //123字串加密 NSLog(@"encodeStr:%@",encodeStr); //可以看到16進位的一串數字 NSString *decodeStr=[blowfh decode:encodestr]; //123字串解密 NSLog(@"encodeStr:%@",decodeStr); //可以看到123字串呃,就像上面的註解囉。
以上,就是非常簡單但我浪費很多時間的chilkat的blowfish加密方式Orz
2014年6月27日 星期五
chilkat blowfish for iOS data transmission PART2
繼上回的chilkat blowfish for iOS data transmission PART1安裝完成後,再來就是正式的引用啦。
以下這裡是官網給的範例,其實照著走就可以了..那我到底為啥花了這麼多時間 Orz
以上除了最後的加解密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
以下這裡是官網給的範例,其實照著走就可以了..那我到底為啥花了這麼多時間 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。
如果還有什麼問題其實可以先看官網的安裝說明,大致上會遇到的問題應該都有說明。
這邊使用的是第三方寫的資料加密傳輸,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檔
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的instance方法,傳入值為id型態,對傳入的物件判斷後,回傳YES or NO的結果。說明:-(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)
訂閱:
文章 (Atom)
