IOS開發基礎知識--片段21,ios基礎知識--片段
1:[UIScreen mainScreen].scale知識點
當螢幕分別為640x940時[[UIScreen mainScreen] scale]=2.0當螢幕分別為320x480時[[UIScreen mainScreen] scale]=1.0
2:如何正確的繪製1像素的線
#define SINGLE_LINE_WIDTH (1 / [UIScreen mainScreen].scale)#define SINGLE_LINE_ADJUST_OFFSET ((1 / [UIScreen mainScreen].scale) / 2)代碼如下:UIView *view = [[UIView alloc] initWithFrame:CGrect(x - SINGLE_LINE_ADJUST_OFFSET, 0, SINGLE_LINE_WIDTH, 100)];注意:如果線寬為偶數Point的話,則不要去設定位移,否則線條也會失真
3:socket編程 - Asyncsocket
Iphone的標準推薦是CFNetwork 庫編程,其封裝好的開源庫是 cocoa AsyncSocket庫,用它來簡化CFNetwork的調用,它提供了非同步作業 主要特性有: 隊列的非阻塞的讀和寫,而且可選逾時。你可以調用它讀取和寫入,它會當完成後告知你自動的socket接收。如果你調用它接收串連,它將為每個串連啟動新的執行個體,當然,也可以立即關閉這些串連委託(delegate)支援。錯誤、串連、接收、完整的讀取、完整的寫入、進度以及中斷連線,都可以通過委託模式調用基於run loop的,而不是線程的。雖然可以在主線程或者背景工作執行緒中使用它,但你不需要這樣做。它非同步調用委託方法,使用NSRunLoop。委託方法包括socket的參數,可讓你在多個執行個體中區分自包含在一個類中。你無需操作流或者socket,這個類幫你做了全部支援基於IPV4和IPV6的TCP流 加入:AsynSocket.h .m與AsynUdpSocket.h .m四個檔案 及CFNetwork.framework TCP用戶端 #import "AsyncSocket.h" @interface HelloiPhoneViewController : UIViewController { UITextField * textField; AsyncSocket * asyncSocket; } @property (retain, nonatomic) IBOutlet UITextField *textField; - (IBAction) buttonPressed: (id)sender; - (IBAction) textFieldDoneEditing: (id)sender; @end 在需要聯結地方使用connectToHost聯結伺服器 其中initWithDelegate的參數中self是必須。這個對象指標中的各個Socket響應的函數將被ASyncSocket所調用.initWithDelegate把將當前對象傳遞進去,這樣只要在當前對象方法實現相應方法 asyncSocket = [[AsyncSocket alloc] initWithDelegate:self]; NSError *err = nil; if(![asyncSocket connectToHost:host on:port error:&err]) { NSLog(@"Error: %@", err); } 關於NSData對象 無論SOCKET收發都採用NSData對象.它的定義是 http://developer.apple.com/library/mac /#documentation/Cocoa/Reference/Foundation/Classes/NSData_Class/Reference/Reference.html NSData主要是帶一個(id)data指向的資料空間和長度 length. NSString 轉換成NSData 對象 NSData* xmlData = [@"testdata" dataUsingEncoding:NSUTF8StringEncoding]; NSData 轉換成NSString對象 NSData * data; NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 發送資料 AsyncSocket writeData 方法來發送資料,它有如下定義 - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; 以下是一個執行個體語句. NSData* aData= [@"test data" dataUsingEncoding: NSUTF8StringEncoding]; [sock writeData:aData withTimeout:-1 tag:1]; 在onSocket重載函數,有如定義採用是專門用來處理SOCKET的發送資料的: -(void)onSocket(AsyncSocket *)sock didWriteDataWithTag:(long)tag { NSLog(@"thread(%),onSocket:%p didWriteDataWithTag:%d",[[NSThread currentThread] name], sock,tag); } 接收Socket資料. 在onSocket重載函數,有如定義採用是專門用來處理SOCKET的接收資料的. -(void) onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 在中間將其轉換成NSString進行顯示. NSString* aStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"===%@",aStr); [aStr release]; 6、TCP串連讀取制定長度的資料 socket串連,可能會讀取固定長度的位元組 [socket readDataToLength: withTimeout :tag]各方法的解析 -(void)onSocket:(AsyncSocket *)sock willDisconnectWithError:(NSError *)err; 發生錯誤,socket關閉,可以在call-back程序呼叫"unreadData"去取得socket的最後的資料位元組,當串連的時候,該委託方法在 onSocket:didAcceptNewSocket: 或者 onSocket:didConnectToHost: 之前調用 -(void)onSocketDidDisconnect:(ASyncSocket *)sock; 當socket由於或沒有錯誤而中斷連線,如果你想要在中斷連線後release socket,在此方法工作,而在onSocket:willDisconnectWithError 釋放則不安全 -(void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket; 當產生一個socket去處理串連時調用,此方法會返回 線程上的run-loop 的新的socket和其應處理的委託,如果省略,則使用[NSRunLoop cunrrentRunLoop] -(BOOL)onSocketWillConnect:(AsyncSocket *)sock; -(void)onSocket:(AsyncSocket *)sock didConnectToHost :(NSString *)host port:(UINt16)port; 當socket串連正準備讀和寫的時候調用,host屬性是一個IP地址,而不是一個DNS 名稱 -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long) tag; 當socket已完成所要求的資料讀入記憶體時調用,如果有錯誤則不調用 -(void)onSocket:(Asyncsocket *)sock didReadPartialDataOfLength:(NSUInteger)partiaLength tag:(long)tag; 當一個socket讀取資料,但尚未完成讀操作的時候調用,如果使用 readToData: or readToLength: 方法 會發生,可以被用來更新進度條等東西 -(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag; 當一個socket已完成請求資料的寫入時候調用 -(void)onSocket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag; 當一個socket寫入一些資料,但還沒有完成整個寫入時調用,它可以用來更新進度條等東西 -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutReadWithTag:(long)tag elapsed:(NSTimeInterval)exapsed bytesDone:(NSUInteger)length 使用讀操作已逾時但還沒完成時調用,此方法允許隨意延遲逾時,如果返回一個正的時間間隔,讀取的逾時將有一定量的擴充,如果不實現這個方法,或會像往常一樣返回一個負的時間間隔,elapsed參數是 原逾時的總和,加上先前通過這種方法添加的任何補充, length參數是 讀操作到目前為止已讀取的位元組數, 注意,如果返回正數的話,這個方法可能被一個單獨的讀取多次調用 -(NSTimeInterval)onSocket:(AsyncSocket *)sock shouldTimeoutWriteWithTag:(long)tag elapsed:(NSTimeInterval)elapsed bytesDone:(NSUInteger)length; 如果一個寫操作已達到其逾時但還沒完成時調用,同上 -(void)onSocketDidSecure:(AsyncSocket *)sock; 在socket成功完成ssl/tls協商時調用,此方法除非你使用提供startTLS方法時候才調用, 如果ssl/tls是無效的認證,socket將會立即關閉,onSocket:willDisconnectWithError:代理方法竟會與特定的ssl錯誤碼一起調用 -(BOOL)canSafelySetDelegate 用來查看在改變它之前,是否帶有與當前的委託有懸而未決的業務(讀/寫)。當然,應在安全連線或接受委託之前改變委託 一旦接收或串連方法之一被調用,AsyncSocket執行個體會被鎖定,其他接收/串連方法在沒有先斷開socket不會被調用 如果嘗試失敗或逾時,這些方法要麼返回NO 要麼調用 onSocket:willDisconnectWithError: 或 onSockedDidDisconnect 當傳入的串連被接受,AsyncSocket調用多個委託方法。這些方法按照時間順序排列: 1.onSocket:didAcceptNewSocket: 2.onSocket:wantsRunLoopForNewSocket: 3. onSocketWillConnect: 你的伺服器的代碼將需要保留公認的socket(如果要接受它),最好的地方是要做到這一點可能在onSocket:didAcceptNewSocket:方法 在讀和寫流已經為新接受的socket設定,onSocket:didConnectToHost:port 方法將在適當的運行迴圈調用 多線程注意,如果要想通過實施onSocket:wantsRunLoopForNewSocket:,移動另一個新接收的socket去到另一個迴圈的socket。然後,應該在調用讀和寫或者startTLS方法前,等待直到onSocket:didConnectToHost:port:方法。否則讀和寫時間原定於不正確的runloop,會發生混亂 -(BOOL)acceptOnPort:(UInit16)port error:(NSError **)errPtr; 告訴socket開始聽取和接受指定連接埠上的串連,當一個串連到來的時候,AsyncSocket執行個體將調用各種委託方法,socket將聽取所有可用的介面(wifi,乙太網路等) -(BOOL)connectToHost:(NSString *)hostname onPort:(UInt16)port error :(NSError **)errPtr; 串連給定的主機和連接埠,主機hostname可以是網域名稱或者是Ip地址 -(BOOL)connectToAddress:(NSData *)remoteAddr error:(NSError *)errPtr; 串連到一個給定的地址,指定一個sockaddr結構包裹住一個NSData對象,例如,NSData對象從NSNetService的地址方法返回,如果有一個現有的sockaddr結構,可以將它轉換到一個NSData對象,像這樣: struct sockaddr sa -> NSData *dsa = [NSData dataWithBytes:&remoteAddr length:remoteAddr.sa_len]; struct sockaddr *sa -> NSData *dsa = [NSData dataWithBytes:remoteAddr length:remoteAddr->sa_len]; -(void)disconnect; 立即斷開,任何未處理的讀或寫都將被丟棄 如果socket還沒有斷開,在這個方法返回之前,onSocketDidDisconnect 委託方法將會被立即調用 注意推薦釋放AsyncSocket執行個體的方式: [asyncSocket setDelegate:nil]; [asyncSocket disconnect]; [asyncSocket release]; -(void)disconnectAfterReading; 在已經完成了所有懸而未決的讀取時 斷開,在調用之後,讀取和寫入方法將無用,socket將斷開 即使仍有寫入的東西 - (NSString *)connectedHost; - (UInt16)connectedPort; - (NSString *)localHost; - (UInt16)localPort; 返回本地和遠程主機和連接埠給串連的socket,如果沒有串連會返回nil或0,主機將會是一個IP地址 -(NSData *)connectedAddress -(NSData *)localAddresss 返回本地和遠端地址給串連的socket,指定一個socketaddr結構包裹在一個NSData對象 readData和writeData方法不會是block(它們是非同步) 當讀完成 onSocket:didReadData:withTag: 委託方法時調用 當寫完成 onSocket:didWriteDataWithTag: 委託方法時調用 可以選擇任何讀/寫操作的逾時設定(為了不逾時,使用負時間間隔。) 如果讀/寫操作逾時,相應的 onSocket:shouldTimeout...委託方法被調用去選擇性地允許我們去延長逾時 逾時後,onSocket:willDisconnectWithError: 方法被調用,緊接著是 onSocketDidDisconnect tag是為了方便,可以使用它作為數組的索引、步數、state id 、指標等 -(void)readDataWithTimeout:(NSTimeInterval)tiemout tag:(long)tag; 讀取socket上第一次成為可用的位元組,如果timeout值是負數的,讀操作將不使用timeout - (void)readDataWithTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInterger)offset tag:(long)tag; 讀取socket上第一次成為可用的位元組 位元組將被追加到給定的位元組緩衝區,從給定的位移量開始 如果需要,給定的緩衝區大小將會自動增加 如果timeout值是負數的,讀操作將不使用timeout 如果緩衝區為空白,socket會為我們建立一個緩衝區 如果bufferOffset是大於給定的緩衝區的長度,該方法將無用,委託將不會被調用 如果你傳遞一個緩衝區,當AsyncSocket在使用它的時候你不能以任何方式改變它 完成之後,onSocket:didReadData:withTag 返回的資料將是一個給定的緩衝區的子集 也就是說,它將會被引用到被追加的給定的緩衝區的位元組 -(void)readDataToLength:(NSUInterger)length withTimeout:(NSTimeInterval)timeout tag:(long)tag; 讀取給定的位元組數,如果length為0,方法將無用,委託將不會被調用 -(void)readDataToLength:(NSUInteger)length withTimeout:(NSTimeInterval)tiemout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag; 讀取給定的位元組數,在給定的位移開始,位元組將被追加到給定的位元組緩衝區 -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; 讀取位元組直到(包括)傳入的作為分隔的"data"參數 如果傳遞0或者0長度的資料,"data"參數,該方法將無用,委託將不會被調用 從socket讀取一行,使用"data"參數作為行的分隔字元 (如HTTP的CRLF) 注意,此方法不是字元集,因此,如果一個分隔字元出現,它自然可以作為進行編碼的一部分,讀取將提前結束 -(void)readDataToData:(NSData *)data withTimeout:(NSTimeInterval)timeout buffer:(NSMutableData *)buffer bufferOffset:(NSUInteger) offset tag:(long)tag; 讀取位元組直到(包括)傳入的作為分隔的“data”參數,在給定的位移量開始,位元組將被追加到給定的位元組緩衝區。 從socket讀取一行,使用"data"參數作為行的分隔字元(如HTTP的CRLF) -(void)writeData:(NSData *)data withTimeout:(NSTimeInterval) timeout tag:(long)tag; 將data寫入socket,當完成的時候委託被調用 - (float)progressOfReadReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total; - (float)progressOfWriteReturningTag:(long *)tag bytesDone:(NSUInteger *)done total:(NSUInteger *)total; 返回當前讀或寫的進度,從0.0 到 1.0 或者 如果沒有讀/寫的時候返回Nan(使用isNan來檢查) tag、done、total如果不為空白的話,它們將會被填補 - (void)startTLS:(NSDictionary *)tlsSettings; 確保使用ssl/tls串連 這方法可被隨時調用,tls握手將會發生在所有懸而未決的讀/寫完成之後。這緊跟著一個發送依賴 StartTLS訊息的協議選項,在排隊升級到TLS的同一時間,而不必等待寫入完成。在這個方法被調用後,任何讀寫計劃 將會發生在安全連結 對於可能的keys和TLS設定的值是有據可查的 一些可能的keys是: * - kCFStreamSSLLevel * - kCFStreamSSLAllowsExpiredCertificates * - kCFStreamSSLAllowsExpiredRoots * - kCFStreamSSLAllowsAnyRoot * - kCFStreamSSLValidatesCertificateChain * - kCFStreamSSLPeerName * - kCFStreamSSLCertificates * - kCFStreamSSLIsServer 如果你傳遞空或者空字典,將使用預設的字典 預設設定將檢查以確保由簽署可信的第三方認證機構和沒有到期的遠端連線的認證 然而,它不會驗證認證上的名字,除非你給它一個名字,通過kCFStreamSSLPeerName鍵去驗證 這對安全的影響是重要的理解 想象一下你正試圖建立一個到MySecureServer.com的安全連線,但因為一個被攻擊的DNS伺服器,所以你的socket被定向到MaliciousServer.com 如果你只是使用預設設定,MaliciousServer.com 有一個有效認證 預設設定將無法監測到任何問題,因為認證是有效 在這個特殊的情況下,要妥善保護你的串連,應設定kCFStreamSSLPeerName性質為MySecureServer.com. 如果事前你不知道對等的名字的遠程主機(例如,你不確認它是domain.com" or "www.domain.com"),那麼你可以使用預設設定來驗證認證,然後在獲得驗證的發行後使用X509Certificate類來驗證,X509Certificate類的CocoaAsyncSocket開源項目的一部分 -(void)enablePrebuffering 對於處理readDataToData請求,資料是必須從socket以小增量的方式讀取出來的 效能通過允許AsyncSocket去一次性讀大塊的資料和儲存任何一個小的內部緩衝區溢位的東西來大大提高 這被稱為預緩衝,就好像一些資料在你要求它之前就可能被讀取出來 如果你經常使用readDataToData,使用預緩衝會有更好的效能,尤其是在iphone上 預設的預緩衝狀態是由DEFAULT_PREBUFFERING 定義控制的,強烈建議設定其為yes 這方法存在一些預緩衝需要一些不可預見的原因被預設禁用的情況,這時,這種方法存在允許當就緒時,可輕鬆啟用預緩衝 -(BOOL)moveToRunLoop:(NSRunLoop *)runLoop; 當你建立一個AsyncSocket,它被添加到當前線程runloop 對於手動建立的socket,線上程上你打算使用它,它是最容易簡單的建立的線程上的socket 當一個新的socket被接受,委託方法 onSocket:wantsRunLoopForNewSocket 會被調用 允許你在一個單獨的線程上放置socket,這個工作最好結合在同一個線程池設計 如果,但是,在一個單獨的線程上,在之後的時間,你需要移動一個socket,這個方法可以用來完成任務 此方法必須從 當前啟動並執行 線程/runloop 的socket 調用 注意:此方法調用後,所有進一步的方法應該從給定的runloop上調用這個對象 此外,所有委託調用將會發送到給定的runloop - (BOOL)setRunLoopModes:(NSArray *)runLoopModes; - (BOOL)addRunLoopMode:(NSString *)runLoopMode; - (BOOL)removeRunLoopMode:(NSString *)runLoopMode; 允許你配置 socket 使用的 運行迴圈模式 運行迴圈模式設定預設是NSRunLoopCommonModes 如果你想你的socket 在其他模式下繼續操作,你可能需要添加模式 NSModalPanelRunLoopMode 或者 NSEventTrackingRunLoopMode ,或者你可能只想使用 NSRunLoopCommonModes 可接受的socket將自動 繼承相同的運行迴圈模式就像偵聽socket 注意:NSRunLoopCommonModes 定義在10.5,對於之前的版本可使用 kCFRunLoopCommonModes -(NSArray *)runLoopModes 返回當前正在啟動並執行迴圈模式的AsyncSocket執行個體, run loop modes的預設設定是NSDefaultRunLoopMode -(NSData *)unreadData; 一個錯誤的事件,在 onSocket:willDisconnectWithError: 將會被調用 去讀取留在socket上的任何資料 + (NSData *)CRLFData; // 0x0D0A + (NSData *)CRData; // 0x0D + (NSData *)LFData; // 0x0A + (NSData *)ZeroData; // 0x00 一些常見的分隔字元,為了去使用 readDataToData:.. 方法