多線程、特別是NSOperation 和 GCD 的內(nèi)部原理。
運(yùn)行時(shí)機(jī)制的原理和運(yùn)用場(chǎng)景。
SDWebImage的原理。實(shí)現(xiàn)機(jī)制。如何解決TableView卡的問(wèn)題。
block和代理的,通知的區(qū)別。block的用法需要注意些什么。
strong,weak,retain,assign,copy nomatic 等的區(qū)別。
設(shè)計(jì)模式,mvc,單利,工廠,代理等的應(yīng)用場(chǎng)景。
單利的寫法。在單利中創(chuàng)建數(shù)組應(yīng)該注意些什么。
NSString 的時(shí)候用copy和strong的區(qū)別。
響應(yīng)值鏈。
NSTimer 在子線程中應(yīng)該手動(dòng)創(chuàng)建NSRunLoop ,否則不能循環(huán)執(zhí)行。
UIScrollView和NSTimer組合做循環(huán)廣告圖輪播的時(shí)候有一個(gè)屬性可以控制當(dāng)上下滾動(dòng)tableview的時(shí)候廣告輪播圖依然正常滾動(dòng)。
Xcode最新的自動(dòng)布局。。。這個(gè)很多公司都用。盡量自學(xué)下。
Git ,和svn的用法。。。git的幾個(gè)命令簡(jiǎn)單的記下。。。
友盟報(bào)錯(cuò)可以查到具體某一行的錯(cuò)誤,原理是什么。
Instrument 可以檢測(cè) 電池的耗電量、和內(nèi)存的消耗。的用法。
動(dòng)畫CABaseAnimation CAKeyAni…. CATrans….. CAGoup…. 等熟悉。。
ARC的原理。
自己寫過(guò)什么自定義控件就最好了。。
———————————————回答好上面的足夠了-------------------------------------
__block和__weak修飾符的區(qū)別其實(shí)是挺明顯的:
1.__block不管是ARC還是MRC模式下都可以使用,可以修飾對(duì)象,還可以修飾基本數(shù)據(jù)類型。 2.__weak只能在ARC模式下使用,也只能修飾對(duì)象(NSString),不能修飾基本數(shù)據(jù)類型(int)。 3.__block對(duì)象可以在block中被重新賦值,__weak不可以。
tableView 滑動(dòng)卡的問(wèn)題主要是因?yàn)椋簭木彺嬷谢蛘呤菑谋镜刈x取圖片給UIImage的時(shí)候耗費(fèi)的時(shí)間。需要把下面的兩句話放到子線程里面:
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:app.icon]]; //得到圖像數(shù)據(jù) UIImage *image = [UIImage imageWithData:imgData];
把UIImage賦值給圖片的時(shí)候在主線程。
子線程不能更新UI 所有的UI跟新都是主線程執(zhí)行了。手指滑動(dòng)屏幕了。或者屏幕的某個(gè)方法執(zhí)行了。
子線程里面加入NSTimer 的時(shí)候需要 手動(dòng)添加NSRunloop 否則不能循環(huán)。
單利里面添加 NSMutableArray 的時(shí)候,防止多個(gè)地方對(duì)它同時(shí)便利和修改的話,需要加原子屬性。并且用strong,,,并且寫一個(gè)遍歷和修改的方法。加上鎖。 Lock UnLock
__weak ViewController* weakSelf = self;
GCD里面用 __weak 防止內(nèi)存釋放不了,循環(huán)引用。
二、SDWebImage內(nèi)部實(shí)現(xiàn)過(guò)程
入口 setImageWithURL:placeholderImage:options: 會(huì)先把 placeholderImage 顯示,然后 SDWebImageManager 根據(jù) URL 開始處理圖片。
進(jìn)入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給 SDImageCache 從緩存查找圖片是否已經(jīng)下載 queryDiskCacheForKey:delegate:userInfo:.
先從內(nèi)存圖片緩存查找是否有圖片,如果內(nèi)存中已經(jīng)有圖片緩存,SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
SDWebImageManagerDelegate 回調(diào) webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示圖片。
如果內(nèi)存緩存中沒(méi)有,生成 NSInvocationOperation 添加到隊(duì)列開始從硬盤查找圖片是否已經(jīng)緩存。
根據(jù) URLKey 在硬盤緩存目錄下嘗試讀取圖片文件。這一步是在 NSOperation 進(jìn)行的操作,所以回主線程進(jìn)行結(jié)果回調(diào) notifyDelegate:。
如果上一操作從硬盤讀取到了圖片,將圖片添加到內(nèi)存緩存中(如果空閑內(nèi)存過(guò)小,會(huì)先清空內(nèi)存緩存)。SDImageCacheDelegate 回調(diào) imageCache:didFindImage:forKey:userInfo:。進(jìn)而回調(diào)展示圖片。
如果從硬盤緩存目錄讀取不到圖片,說(shuō)明所有緩存都不存在該圖片,需要下載圖片,回調(diào) imageCache:didNotFindImageForKey:userInfo:。
共享或重新生成一個(gè)下載器 SDWebImageDownloader 開始下載圖片。
圖片下載由 NSURLConnection 來(lái)做,實(shí)現(xiàn)相關(guān) delegate 來(lái)判斷圖片下載中、下載完成和下載失敗。
connection:didReceiveData: 中利用 ImageIO 做了按圖片下載進(jìn)度加載效果。
connectionDidFinishLoading: 數(shù)據(jù)下載完成后交給 SDWebImageDecoder 做圖片解碼處理。
圖片解碼處理在一個(gè) NSOperationQueue 完成,不會(huì)拖慢主線程 UI。如果有需要對(duì)下載的圖片進(jìn)行二次處理,最好也在這里完成,效率會(huì)好很多。
在主線程 notifyDelegateOnMainThreadWithInfo: 宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo: 回調(diào)給 SDWebImageDownloader。
imageDownloader:didFinishWithImage: 回調(diào)給 SDWebImageManager 告知圖片下載完成。
通知所有的 downloadDelegates 下載完成,回調(diào)給需要的地方展示圖片。
將圖片保存到 SDImageCache 中,內(nèi)存緩存和硬盤緩存同時(shí)保存。寫文件到硬盤也在以單獨(dú) NSInvocationOperation 完成,避免拖慢主線程。
SDImageCache 在初始化的時(shí)候會(huì)注冊(cè)一些消息通知,在內(nèi)存警告或退到后臺(tái)的時(shí)候清理內(nèi)存圖片緩存,應(yīng)用結(jié)束的時(shí)候清理過(guò)期圖片。
SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。
SDWebImagePRefetcher 可以預(yù)先下載圖片,方便后續(xù)使用。
從上面流程可以看出,當(dāng)你調(diào)用setImageWithURL:方法的時(shí)候,他會(huì)自動(dòng)去給你干這么多事,當(dāng)你需要在某一具體時(shí)刻做事情的時(shí)候,你可以覆蓋這些方法。比如在下載某個(gè)圖片的過(guò)程中要響應(yīng)一個(gè)事件,就覆蓋這個(gè)方法:
| 1234567891011 | //覆蓋方法,指哪打哪,這個(gè)方法是下載imagePath2的時(shí)候響應(yīng) SDWebImageManager *manager = [SDWebImageManager sharedManager]; [manager downloadImageWithURL:imagePath2 options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) { NSLog(@"顯示當(dāng)前進(jìn)度"); } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { NSLog(@"下載完成"); }]; |
對(duì)于初級(jí)來(lái)說(shuō),用sd_setImageWithURL:的若干個(gè)方法就可以實(shí)現(xiàn)很好的圖片緩存。
UIButton 的父類是UIControl UIControl的父類是UIView UIView的父類是 UIResponder
http狀態(tài)嗎 :302 是請(qǐng)求重定向。500以上是服務(wù)器錯(cuò)誤。400以上是請(qǐng)求鏈接錯(cuò)誤或者找不到服務(wù)器。200以上是正確。100以上是請(qǐng)求接受成功。
HTTP Keep-Alive詳解[轉(zhuǎn)]HTTP是一個(gè)請(qǐng)求<->響應(yīng)模式的典型范例,即客戶端向服務(wù)器發(fā)送一個(gè)請(qǐng)求信息,服務(wù)器來(lái)響應(yīng)這個(gè)信息。在老的HTTP版本中,每個(gè)請(qǐng)求都將被創(chuàng)建一個(gè)新的客戶端->服務(wù)器的連接,在這個(gè)連接上發(fā)送請(qǐng)求,然后接收請(qǐng)求。這樣的模式有一個(gè)很大的優(yōu)點(diǎn)就是,它很簡(jiǎn)單,很容易理解和編程實(shí)現(xiàn);它也有一個(gè)很大的缺點(diǎn)就是,它效率很低,因此Keep-Alive被提出用來(lái)解決效率低的問(wèn)題。Keep-Alive功能使客戶端到服務(wù)器端的連接持續(xù)有效,當(dāng)出現(xiàn)對(duì)服務(wù)器的后繼請(qǐng)求時(shí),Keep-Alive功能避免了建立或者重新建立連接。市場(chǎng)上 的大部分Web服務(wù)器,包括iplanet、IIS和Apache,都支持HTTP Keep-Alive。對(duì)于提供靜態(tài)內(nèi)容的網(wǎng)站來(lái)說(shuō),這個(gè)功能通常很有用。但是,對(duì)于負(fù)擔(dān)較重的網(wǎng)站來(lái)說(shuō),這里存在另外一個(gè)問(wèn)題:雖然為客戶保留打開的連 接有一定的好處,但它同樣影響了性能,因?yàn)樵谔幚頃和F陂g,本來(lái)可以釋放的資源仍舊被占用。當(dāng)Web服務(wù)器和應(yīng)用服務(wù)器在同一臺(tái)機(jī)器上運(yùn)行時(shí),Keep- Alive功能對(duì)資源利用的影響尤其突出。 此功能為HTTP 1.1預(yù)設(shè)的功能,HTTP 1.0加上Keep-Aliveheader也可以提供HTTP的持續(xù)作用功能。Keep-Alive: timeout=5, max=100timeout:過(guò)期時(shí)間5秒(對(duì)應(yīng)httpd.conf里的參數(shù)是:KeepAliveTimeout),max是最多一百次請(qǐng)求,強(qiáng)制斷掉連接就是在timeout時(shí)間內(nèi)又有新的連接過(guò)來(lái),同時(shí)max會(huì)自動(dòng)減1,直到為0,強(qiáng)制斷掉。見(jiàn)下面的四個(gè)圖,注意看Date的值(前后時(shí)間差都是在5秒之內(nèi))!HTTP/1.0在HTTP/1.0版本中,并沒(méi)有官方的標(biāo)準(zhǔn)來(lái)規(guī)定Keep-Alive如何工作,因此實(shí)際上它是被附加到HTTP/1.0協(xié)議上,如果客戶端瀏覽器支持Keep-Alive,那么就在HTTP請(qǐng)求頭中添加一個(gè)字段 Connection: Keep-Alive,當(dāng)服務(wù)器收到附帶有Connection: Keep-Alive的請(qǐng)求時(shí),它也會(huì)在響應(yīng)頭中添加一個(gè)同樣的字段來(lái)使用Keep-Alive。這樣一來(lái),客戶端和服務(wù)器之間的HTTP連接就會(huì)被保持,不會(huì)斷開(超過(guò)Keep-Alive規(guī)定的時(shí)間,意外斷電等情況除外),當(dāng)客戶端發(fā)送另外一個(gè)請(qǐng)求時(shí),就使用這條已經(jīng)建立的連接HTTP/1.1在HTTP/1.1版本中,官方規(guī)定的Keep-Alive使用標(biāo)準(zhǔn)和在HTTP/1.0版本中有些不同,默認(rèn)情況下所在HTTP1.1中所有連接都被保持,除非在請(qǐng)求頭或響應(yīng)頭中指明要關(guān)閉:Connection: Close ,這也就是為什么Connection: Keep-Alive字段再?zèng)]有意義的原因。另外,還添加了一個(gè)新的字段Keep-Alive:,因?yàn)檫@個(gè)字段并沒(méi)有詳細(xì)描述用來(lái)做什么,可忽略它
Not reliable(不可靠)
HTTP是一個(gè)無(wú)狀態(tài)協(xié)議,這意味著每個(gè)請(qǐng)求都是獨(dú)立的,Keep-Alive沒(méi)能改變這個(gè)結(jié)果。另外,Keep-Alive也不能保證客戶端和服務(wù)器之間的連接一定是活躍的,在HTTP1.1版本中也如此。唯一能保證的就是當(dāng)連接被關(guān)閉時(shí)你能得到一個(gè)通知,所以不應(yīng)該讓程序依賴于Keep-Alive的保持連接特性,否則會(huì)有意想不到的后果
Keep-Alive和POST
在HTTP1.1細(xì)則中規(guī)定了在一個(gè)POST消息體后面不能有任何字符,還指出了對(duì)于某一個(gè)特定的瀏覽器可能并不遵循這個(gè)標(biāo)準(zhǔn)(比如在POST消息體的后面放置一個(gè)CRLF符)。而據(jù)我所知,大部分瀏覽器在POST消息體后都會(huì)自動(dòng)跟一個(gè)CRLF符再發(fā)送,如何解決這個(gè)問(wèn)題呢?根據(jù)上面的說(shuō)明在POST請(qǐng)求頭中禁止使用Keep-Alive,或者由服務(wù)器自動(dòng)忽略這個(gè)CRLF,大部分服務(wù)器都會(huì)自動(dòng)忽略,但是在未經(jīng)測(cè)試之前是不可能知道一個(gè)服務(wù)器是否會(huì)這樣做。
為了避免界面在處理耗時(shí)的操作時(shí)卡死,比如讀取網(wǎng)絡(luò)數(shù)據(jù),IO,數(shù)據(jù)庫(kù)讀寫等,我們會(huì)在另外一個(gè)線程中處理這些操作,然后通知主線程更新界面。
用GCD實(shí)現(xiàn)這個(gè)流程的操作比前面介紹的NSThread NSOperation的方法都要簡(jiǎn)單。代碼框架結(jié)構(gòu)如下:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 耗時(shí)的操作 dispatch_async(dispatch_get_main_queue(), ^{ // 更新界面 }); }); 如果這樣還不清晰的話,那我們還是用上兩篇博客中的下載圖片為例子,代碼如下:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"]; NSData * data = [[NSData alloc]initWithContentsOfURL:url]; UIImage *image = [[UIImage alloc]initWithData:data]; if (data != nil) { dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = image; }); } });
運(yùn)行顯示:

系統(tǒng)給每一個(gè)應(yīng)用程序提供了三個(gè)concurrent dispatch queues。這三個(gè)并發(fā)調(diào)度隊(duì)列是全局的,它們只有優(yōu)先級(jí)的不同。因?yàn)槭侨值?,我們不需要去?chuàng)建。我們只需要通過(guò)使用函數(shù)dispath_get_global_queue去得到隊(duì)列,如下:
dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
這里也用到了系統(tǒng)默認(rèn)就有一個(gè)串行隊(duì)列main_queue
dispatch_queue_t mainQ = dispatch_get_main_queue();
雖然dispatch queue是引用計(jì)數(shù)的對(duì)象,但是以上兩個(gè)都是全局的隊(duì)列,不用retain或release。
dispatch_group_async可以實(shí)現(xiàn)監(jiān)聽一組任務(wù)是否完成,完成后得到通知執(zhí)行其他的操作。這個(gè)方法很有用,比如你執(zhí)行三個(gè)下載任務(wù),當(dāng)三個(gè)任務(wù)都下載完成后你才通知界面說(shuō)完成的了。下面是一段例子代碼:
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, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"group1"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"group2"); }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:3]; NSLog(@"group3"); }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"updateUi"); }); dispatch_release(group); dispatch_group_async是異步的方法,運(yùn)行后可以看到打印結(jié)果:
2012-09-25 16:04:16.737 gcdTest[43328:11303] group12012-09-25 16:04:17.738 gcdTest[43328:12a1b] group22012-09-25 16:04:18.738 gcdTest[43328:13003] group32012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi
每個(gè)一秒打印一個(gè),當(dāng)?shù)谌齻€(gè)任務(wù)執(zhí)行后,upadteUi被打印。
dispatch_barrier_async是在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,而且它后面的任務(wù)等它執(zhí)行完成之后才會(huì)執(zhí)行
例子代碼如下:
dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"dispatch_async1"); }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:4]; NSLog(@"dispatch_async2"); }); dispatch_barrier_async(queue, ^{ NSLog(@"dispatch_barrier_async"); [NSThread sleepForTimeInterval:4]; }); dispatch_async(queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"dispatch_async3"); }); 打印結(jié)果:
2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async
2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3
請(qǐng)注意執(zhí)行的時(shí)間,可以看到執(zhí)行的順序如上所述。執(zhí)行某個(gè)代碼片段N次。dispatch_apply(5, globalQ, ^(size_t index) { // 執(zhí)行5次
});
copy與retain:1、copy其實(shí)是建立了一個(gè)相同的對(duì)象,而retain不是;2、copy是內(nèi)容拷貝,retain是指針拷貝; 3、copy是內(nèi)容的拷貝 ,對(duì)于像NSString,的確是這樣,但是如果copy的是一個(gè)NSArray呢?這時(shí)只是copy了指向array中相對(duì)應(yīng)元素的指針.這便是所謂的"淺復(fù)制".4、copy的情況:NSString *newPt = [pt copy];此時(shí)會(huì)在堆上重新開辟一段內(nèi)存存放@"abc" 比如0X1122 內(nèi)容為@"abc 同時(shí)會(huì)在棧上為newPt分配空間 比如地址:0Xaacc 內(nèi)容為0X1122 因此retainCount增加1供newPt來(lái)管理0X1122這段內(nèi)存;assign與retain:1、assign: 簡(jiǎn)單賦值,不更改索引計(jì)數(shù);2、assign的情況:NSString *newPt = [pt assing]; 此時(shí)newPt和pt完全相同 地址都是0Xaaaa 內(nèi)容為0X1111 即newPt只是pt的別名,對(duì)任何一個(gè)操作就等于對(duì)另一個(gè)操作, 因此retainCount不需要增加;3、assign就是直接賦值;4、retain使用了引用計(jì)數(shù),retain引起引用計(jì)數(shù)加1, release引起引用計(jì)數(shù)減1,當(dāng)引用計(jì)數(shù)為0時(shí),dealloc函數(shù)被調(diào)用,內(nèi)存被回收; 5、retain的情況:NSString *newPt = [pt retain]; 此時(shí)newPt的地址不再為0Xaaaa,可能為0Xaabb 但是內(nèi)容依然為0X1111。 因此newPt 和 pt 都可以管理"abc"所在的內(nèi)存,因此 retainCount需要增加1 ;readonly:1、屬性是只讀的,默認(rèn)的標(biāo)記是讀寫,如果你指定了只讀,在@implementation中只需要一個(gè)讀取器。或者如果你使用@synthesize關(guān)鍵字,也是有讀取器方法被解析 readwrite:1、說(shuō)明屬性會(huì)被當(dāng)成讀寫的,這也是默認(rèn)屬性。設(shè)置器和讀取器都需要在@implementation中實(shí)現(xiàn)。如果使用@synthesize關(guān)鍵字,讀取器和設(shè)置器都會(huì)被解析;nonatomic:1、非原子性訪問(wèn),對(duì)屬性賦值的時(shí)候不加鎖,多線程并發(fā)訪問(wèn)會(huì)提高性能。如果不加此屬性,則默認(rèn)是兩個(gè)訪問(wèn)方法都為原子型事務(wù)訪問(wèn);weak and strong property (強(qiáng)引用和弱引用的區(qū)別):1、 weak 和 strong 屬性只有在你打開ARC時(shí)才會(huì)被要求使用,這時(shí)你是不能使用retain release autorelease 操作的,因?yàn)锳RC會(huì)自動(dòng)為你做好這些操作,但是你需要在對(duì)象屬性上使用weak 和strong,其中strong就相當(dāng)于retain屬性,而weak相當(dāng)于assign。2、只有一種情況你需要使用weak(默認(rèn)是strong),就是為了避免retain cycles(就是父類中含有子類{父類retain了子類},子類中又調(diào)用了父類{子類又retain了父類},這樣都無(wú)法release) 3、聲明為weak的指針,指針指向的地址一旦被釋放,這些指針都將被賦值為nil。這樣的好處能有效的防止野指針。 ARC(Automatic Reference Counting):1、就是代碼中自動(dòng)加入了retain/release,原先需要手動(dòng)添加的用來(lái)處理內(nèi)存管理的引用計(jì)數(shù)的代碼可以自動(dòng)地由編譯器完成了。該機(jī)能在 iOS 5/ Mac OS X 10.7 開始導(dǎo)入,利用 Xcode4.2 以后可以使用該特性。strong,weak,copy 具體用法:
1.具體一點(diǎn):IBOutlet可以為weak,NSString為copy,Delegate一般為weak,其他的看情況。一般來(lái)說(shuō),類“內(nèi)部”的屬性設(shè)置為strong,類“外部”的屬性設(shè)置為weak。說(shuō)到底就是一個(gè)歸屬權(quán)的問(wèn)題。小心出現(xiàn)循環(huán)引用導(dǎo)致內(nèi)存無(wú)法釋放。2.不用ARC的話就會(huì)看到很多retian。3.如果你寫了@synthesize abc = _abc;的話,系統(tǒng)自動(dòng)幫你聲明了一個(gè)_abc的實(shí)例變量。 使用assign: 對(duì)基礎(chǔ)數(shù)據(jù)類型 (NSInteger)和C數(shù)據(jù)類型(int, float, double, char,等) 使用copy: 對(duì)NSString
使用retain: 對(duì)其他NSObject和其子類
1.寫一個(gè)NSString類的實(shí)現(xiàn)
+ (id)initWithCString:(c*****t char *)nullTerminatedCString encoding:(NSStringEncoding)encoding;
+ (id) stringWithCString: (c*****t char*)nullTerminatedCString
encoding: (NSStringEncoding)encoding
{
NSString *obj;
obj = [self allocWithZone: NSDefaultMallocZone()];
obj = [obj initWithCString: nullTerminatedCString encoding: encoding];
return AUTORELEASE(obj);
}
2static 關(guān)鍵字的作用:
(1)函數(shù)體內(nèi) static 變量的作用范圍為該函數(shù)體,不同于 auto 變量,該變量的內(nèi)存只被分配一次,
因此其值在下次調(diào)用時(shí)仍維持上次的值;
(2)在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所用函數(shù)訪問(wèn),但不能被模塊外其它函數(shù)訪問(wèn);
(3)在模塊內(nèi)的 static 函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用,這個(gè)函數(shù)的使用范圍被限制在聲明
它的模塊內(nèi);
(4)在類中的 static 成員變量屬于整個(gè)類所擁有,對(duì)類的所有對(duì)象只有一份拷貝;
(5)在類中的 static 成員函數(shù)屬于整個(gè)類所擁有,這個(gè)函數(shù)不接收 this 指針,因而只能訪問(wèn)類的static 成員變量。
3線程與進(jìn)程的區(qū)別和聯(lián)系?
進(jìn)程和線程都是由操作系統(tǒng)所體會(huì)的程序運(yùn)行的基本單元,系統(tǒng)利用該基本單元實(shí)現(xiàn)系統(tǒng)對(duì)應(yīng)用的并發(fā)性。
程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其它進(jìn)程產(chǎn)生影響,而線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時(shí),耗費(fèi)資源較大,效率要差一些。但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。
4堆和棧的區(qū)別
管理方式:對(duì)于棧來(lái)講,是由編譯器自動(dòng)管理,無(wú)需我們手工控制;對(duì)于堆來(lái)說(shuō),釋放工作由程序員控制,容易產(chǎn)生memory leak。
申請(qǐng)大?。?nbsp;
棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在 WINDOWS下,棧的大小是2M(也有的說(shuō)是1M,總之是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請(qǐng)的空間超過(guò)棧的剩余空間時(shí),將提示overflow。因此,能從棧獲得的空間較小。
堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來(lái)存儲(chǔ)的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見(jiàn),堆獲得的空間比較靈活,也比較大。
碎片問(wèn)題:對(duì)于堆來(lái)講,頻繁的new/delete勢(shì)必會(huì)造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對(duì)于棧來(lái)講,則不會(huì)存在這個(gè)問(wèn)題,因?yàn)闂J窍冗M(jìn)后出的隊(duì)列,他們是如此的一一對(duì)應(yīng),以至于永遠(yuǎn)都不可能有一個(gè)內(nèi)存塊從棧中間彈出
分配方式:堆都是動(dòng)態(tài)分配的,沒(méi)有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動(dòng)態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動(dòng)態(tài)分配和堆是不同的,他的動(dòng)態(tài)分配是由編譯器進(jìn)行釋放,無(wú)需我們手工實(shí)現(xiàn)。
分配效率:棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會(huì)在底層對(duì)棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是C/C++函數(shù)庫(kù)提供的,它的機(jī)制是很復(fù)雜的。
5什么是鍵-值,鍵路徑是什么
模型的性質(zhì)是通過(guò)一個(gè)簡(jiǎn)單的鍵(通常是個(gè)字符串)來(lái)指定的。視圖和控制器通過(guò)鍵來(lái)查找相應(yīng)的屬性值。在一個(gè)給定的實(shí)體中,同一個(gè)屬性的所有值具有相同的數(shù)據(jù)類型。鍵-值編碼技術(shù)用于進(jìn)行這樣的查找—它是一種間接訪問(wèn)對(duì)象屬性的機(jī)制。
鍵路徑是一個(gè)由用點(diǎn)作分隔符的鍵組成的字符串,用于指定一個(gè)連接在一起的對(duì)象性質(zhì)序列。第一個(gè)鍵的
性質(zhì)是由先前的性質(zhì)決定的,接下來(lái)每個(gè)鍵的值也是相對(duì)于其前面的性質(zhì)。鍵路徑使您可以以獨(dú)立于模型
實(shí)現(xiàn)的方式指定相關(guān)對(duì)象的性質(zhì)。通過(guò)鍵路徑,您可以指定對(duì)象圖中的一個(gè)任意深度的路徑,使其指向相
關(guān)對(duì)象的特定屬性。
6目標(biāo)-動(dòng)作機(jī)制
目標(biāo)是動(dòng)作消息的接收者。一個(gè)控件,或者更為常見(jiàn)的是它的單元,以插座變量(參見(jiàn)"插座變量"部分)
的形式保有其動(dòng)作消息的目標(biāo)。
動(dòng)作是控件發(fā)送給目標(biāo)的消息,或者從目標(biāo)的角度看,它是目標(biāo)為了響應(yīng)動(dòng)作而實(shí)現(xiàn)的方法。
程序需要某些機(jī)制來(lái)進(jìn)行事件和指令的翻譯。這個(gè)機(jī)制就是目標(biāo)-動(dòng)作機(jī)制。
7objc的內(nèi)存管理
?? 如果您通過(guò)分配和初始化(比如[[MyClass alloc] init])的方式來(lái)創(chuàng)建對(duì)象,您就擁
有這個(gè)對(duì)象,需要負(fù)責(zé)該對(duì)象的釋放。這個(gè)規(guī)則在使用NSObject的便利方法new 時(shí)也同樣適用。
?? 如果您拷貝一個(gè)對(duì)象,您也擁有拷貝得到的對(duì)象,需要負(fù)責(zé)該對(duì)象的釋放。
?? 如果您保持一個(gè)對(duì)象,您就部分擁有這個(gè)對(duì)象,需要在不再使用時(shí)釋放該對(duì)象。
反過(guò)來(lái),
?? 如果您從其它對(duì)象那里接收到一個(gè)對(duì)象,則您不擁有該對(duì)象,也不應(yīng)該釋放它(這個(gè)規(guī)則有少數(shù)
的例外,在參考文檔中有顯式的說(shuō)明)。
8 自動(dòng)釋放池是什么,如何工作
當(dāng)您向一個(gè)對(duì)象發(fā)送一個(gè)autorelease消息時(shí),Cocoa就會(huì)將該對(duì)象的一個(gè)引用放入到最新的自動(dòng)釋放池。它仍然是個(gè)正當(dāng)?shù)膶?duì)象,因此自動(dòng)釋放池定義的作用域內(nèi)的其它對(duì)象可以向它發(fā)送消息。當(dāng)程序執(zhí)行到作用域結(jié)束的位置時(shí),自動(dòng)釋放池就會(huì)被釋放,池中的所有對(duì)象也就被釋放。
1. ojc-c 是通過(guò)一種"referring counting"(引用計(jì)數(shù))的方式來(lái)管理內(nèi)存的, 對(duì)象在開始分配內(nèi)存(alloc)的時(shí)候引用計(jì)數(shù)為一,以后每當(dāng)碰到有copy,retain的時(shí)候引用計(jì)數(shù)都會(huì)加一, 每當(dāng)碰到release和autorelease的時(shí)候引用計(jì)數(shù)就會(huì)減一,如果此對(duì)象的計(jì)數(shù)變?yōu)榱?, 就會(huì)被系統(tǒng)銷毀.
2. NSAutoreleasePool 就是用來(lái)做引用計(jì)數(shù)的管理工作的,這個(gè)東西一般不用你管的.
3. autorelease和release沒(méi)什么區(qū)別,只是引用計(jì)數(shù)減一的時(shí)機(jī)不同而已,autorelease會(huì)在對(duì)象的使用真正結(jié)束的時(shí)候才做引用計(jì)數(shù)減一.
9類工廠方法是什么
類工廠方法的實(shí)現(xiàn)是為了向客戶提供方便,它們將分配和初始化合在一個(gè)步驟中,返回被創(chuàng)建的對(duì)象,并
進(jìn)行自動(dòng)釋放處理。這些方法的形式是+ (type)className...(其中 className不包括任何前綴)。
工廠方法可能不僅僅為了方便使用。它們不但可以將分配和初始化合在一起,還可以為初始化過(guò)程提供對(duì)
象的分配信息。
類工廠方法的另一個(gè)目的是使類(比如NSWorkspace)提供單件實(shí)例。雖然init...方法可以確認(rèn)一
個(gè)類在每次程序運(yùn)行過(guò)程只存在一個(gè)實(shí)例,但它需要首先分配一個(gè)“生的”實(shí)例,然后還必須釋放該實(shí)例。
工廠方法則可以避免為可能沒(méi)有用的對(duì)象盲目分配內(nèi)存。
10單件實(shí)例是什么
Foundation 和 application Kit 框架中的一些類只允許創(chuàng)建單件對(duì)象,即這些類在當(dāng)前進(jìn)程中的唯一實(shí)例。舉例來(lái)說(shuō),NSFileManager 和NSWorkspace 類在使用時(shí)都是基于進(jìn)程進(jìn)行單件對(duì)象的實(shí)例化。當(dāng)向這些類請(qǐng)求實(shí)例的時(shí)候,它們會(huì)向您傳遞單一實(shí)例的一個(gè)引用,如果該實(shí)例還不存在,則首先進(jìn)行實(shí)例的分配和初始化。單件對(duì)象充當(dāng)控制中心的角色,負(fù)責(zé)指引或協(xié)調(diào)類的各種服務(wù)。如果類在概念上只有一個(gè)實(shí)例(比如
NSWorkspace),就應(yīng)該產(chǎn)生一個(gè)單件實(shí)例,而不是多個(gè)實(shí)例;如果將來(lái)某一天可能有多個(gè)實(shí)例,您可
以使用單件實(shí)例機(jī)制,而不是工廠方法或函數(shù)。
11動(dòng)態(tài)綁定
—在運(yùn)行時(shí)確定要調(diào)用的方法
動(dòng)態(tài)綁定將調(diào)用方法的確定也推遲到運(yùn)行時(shí)。在編譯時(shí),方法的調(diào)用并不和代碼綁定在一起,只有在消實(shí)發(fā)送出來(lái)之后,才確定被調(diào)用的代碼。通過(guò)動(dòng)態(tài)類型和動(dòng)態(tài)綁定技術(shù),您的代碼每次執(zhí)行都可以得到不同的結(jié)果。運(yùn)行時(shí)因子負(fù)責(zé)確定消息的接收者和被調(diào)用的方法。運(yùn)行時(shí)的消息分發(fā)機(jī)制為動(dòng)態(tài)綁定提供支持。當(dāng)您向一個(gè)動(dòng)態(tài)類型確定了的對(duì)象發(fā)送消息時(shí),運(yùn)行環(huán)境系統(tǒng)會(huì)通過(guò)接收者的isa指針定位對(duì)象的類,并以此為起點(diǎn)確定被調(diào)用的方法,方法和消息是動(dòng)態(tài)綁定的。而且,您不必在Objective-C 代碼中做任何工作,就可以自動(dòng)獲取動(dòng)態(tài)綁定的好處。您在每次發(fā)送消息時(shí),
特別是當(dāng)消息的接收者是動(dòng)態(tài)類型已經(jīng)確定的對(duì)象時(shí),動(dòng)態(tài)綁定就會(huì)例行而透明地發(fā)生。
12obj-c的優(yōu)缺點(diǎn)
objc優(yōu)點(diǎn):
1) Cateogies
2) Posing
3) 動(dòng)態(tài)識(shí)別
4) 指標(biāo)計(jì)算
5)彈性訊息傳遞
6) 不是一個(gè)過(guò)度復(fù)雜的 C 衍生語(yǔ)言
7) Objective-C 與 C++ 可混合編程
缺點(diǎn):
1) 不支援命名空間
2) 不支持運(yùn)算符重載
3)不支持多重繼承
4)使用動(dòng)態(tài)運(yùn)行時(shí)類型,所有的方法都是函數(shù)調(diào)用,所以很多編譯時(shí)優(yōu)化方法都用不到。(如內(nèi)聯(lián)函數(shù)等),性能低劣。
13sprintf,strcpy,memcpy使用上有什么要注意的地方
strcpy是一個(gè)字符串拷貝的函數(shù),它的函數(shù)原型為strcpy(char *dst, c*****t char *src);
將 src開始的一段字符串拷貝到dst開始的內(nèi)存中去,結(jié)束的標(biāo)志符號(hào)為'/0',由于拷貝的長(zhǎng)度不是由我們自己控制的,所以這個(gè)字符串拷貝很容易出錯(cuò)。具備字符串拷貝功能的函數(shù)有memcpy,這是一個(gè)內(nèi)存拷貝函數(shù),它的函數(shù)原型為memcpy(char *dst, c*****t char* src, unsigned int len);
將長(zhǎng)度為len的一段內(nèi)存,從src拷貝到dst中去,這個(gè)函數(shù)的長(zhǎng)度可控。但是會(huì)有內(nèi)存疊加的問(wèn)題。
sprintf是格式化函數(shù)。將一段數(shù)據(jù)通過(guò)特定的格式,格式化到一個(gè)字符串緩沖區(qū)中去。sprintf格式化的函數(shù)的長(zhǎng)度不可控,有可能格式化后的字符串會(huì)超出緩沖區(qū)的大小,造成溢出。
14答案是:
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functi***** that take an integer argument and return an integer
15.readwrite,readonly,assign,retain,copy,nonatomic屬性的作用
@property是一個(gè)屬性訪問(wèn)聲明,擴(kuò)號(hào)內(nèi)支持以下幾個(gè)屬性:
1,getter=getterName,setter=setterName,設(shè)置setter與getter的方法名
2,readwrite,readonly,設(shè)置可供訪問(wèn)級(jí)別
2,assign,setter方法直接賦值,不進(jìn)行任何retain操作,為了解決原類型與環(huán)循引用問(wèn)題
3,retain,setter方法對(duì)參數(shù)進(jìn)行release舊值再retain新值,所有實(shí)現(xiàn)都是這個(gè)順序(CC上有相關(guān)資料)
4,copy,setter方法進(jìn)行Copy操作,與retain處理流程一樣,先舊值release,再Copy出新的對(duì)象,retainCount為1。這是為了減少對(duì)上下文的依賴而引入的機(jī)制。
copy是在你不希望a和b共享一塊內(nèi)存時(shí)會(huì)使用到。a和b各自有自己的內(nèi)存。
5,nonatomic,非原子性訪問(wèn),不加同步,多線程并發(fā)訪問(wèn)會(huì)提高性能。注意,如果不加此屬性,則默認(rèn)是兩個(gè)訪問(wèn)方法都為原子型事務(wù)訪問(wèn)。鎖被加到所屬對(duì)象實(shí)例級(jí)(我是這么理解的...)。
atomic和nonatomic用來(lái)決定編譯器生成的getter和setter是否為原子操作。在多線程環(huán)境下,原子操作是必要的,否則有可能引起錯(cuò) 誤的結(jié)果。加了atomic,setter函數(shù)會(huì)變成下面這樣:
16什么時(shí)候用delegate,什么時(shí)候用Notification?答:delegate針對(duì)one-to-one關(guān)系,并且reciever可以返回值 給sender,notification 可以針對(duì)one-to-one/many/none,reciever無(wú)法返回值給sender.所以,delegate用于sender希望接受到 reciever的某個(gè)功能反饋值,notification用于通知多個(gè)object某個(gè)事件。
17什么是KVC和KVO?答:KVC(Key-Value-Coding)內(nèi)部的實(shí)現(xiàn):一個(gè)對(duì)象在調(diào)用setValue的時(shí)候,(1)首先根據(jù)方法名找到運(yùn)行方法的時(shí)候所需要的環(huán)境參數(shù)。(2)他會(huì)從自己isa指針結(jié)合環(huán)境參數(shù),找到具體的方法實(shí)現(xiàn)的接口。(3)再直接查找得來(lái)的具體的方法實(shí)現(xiàn)。KVO(Key-Value- Observing):當(dāng)觀察者為一個(gè)對(duì)象的屬性進(jìn)行了注冊(cè),被觀察對(duì)象的isa指針被修改的時(shí)候,isa指針就會(huì)指向一個(gè)中間類,而不是真實(shí)的類。所以 isa指針其實(shí)不需要指向?qū)嵗龑?duì)象真實(shí)的類。所以我們的程序最好不要依賴于isa指針。在調(diào)用類的方法的時(shí)候,最好要明確對(duì)象實(shí)例的類名
18ViewController 的 loadView, viewDidLoad, viewDidUnload 分別是在什么時(shí)候調(diào)用的?在自定義ViewController的時(shí)候這幾個(gè)函數(shù)里面應(yīng)該做什么工作?答:viewDidLoad在view 從nib文件初始化時(shí)調(diào)用,loadView在controller的view為nil時(shí)調(diào)用。此方法在編程實(shí)現(xiàn)view時(shí)調(diào)用,view 控制器默認(rèn)會(huì)注冊(cè)memory warning notification,當(dāng)view controller的任何view 沒(méi)有用的時(shí)候,viewDidUnload會(huì)被調(diào)用,在這里實(shí)現(xiàn)將retain 的view release,如果是retain的IBOutlet view 屬性則不要在這里release,IBOutlet會(huì)負(fù)責(zé)release 。
19
"NSMutableString *"這個(gè)數(shù)據(jù)類型則是代表"NSMutableString"對(duì)象本身,這兩者是有區(qū)別的。
而NSString只是對(duì)象的指針而已。
面向過(guò)程就是分析出解決問(wèn)題所需要的步驟,然后用函數(shù)把這些步驟一步一步實(shí)現(xiàn),使用的時(shí)候一個(gè)一個(gè)依次調(diào)用就可以了。
面向?qū)ο笫前褬?gòu)成問(wèn)題事務(wù)分解成各個(gè)對(duì)象,建立對(duì)象的目的不是為了完成一個(gè)步驟,而是為了描敘某個(gè)事物在整個(gè)解決問(wèn)題的步驟中的行為。;
20類別的作用
類別主要有3個(gè)作用:
(1)將類的實(shí)現(xiàn)分散到多個(gè)不同文件或多個(gè)不同框架中。
(2)創(chuàng)建對(duì)私有方法的前向引用。
(3)向?qū)ο筇砑臃钦絽f(xié)議。
類別的局限性
有兩方面局限性:
(1)無(wú)法向類中添加新的實(shí)例變量,類別沒(méi)有位置容納實(shí)例變量。
(2)名稱沖突,即當(dāng)類別中的方法與原始類方法名稱沖突時(shí),類別具有更高的優(yōu)先級(jí)。類別方法將完全取代初始方法從而無(wú)法再使用初始方法。
無(wú)法添加實(shí)例變量的局限可以使用字典對(duì)象解決
21關(guān)鍵字volatile有什么含意?并給出三個(gè)不同的例子:
一個(gè)定義為volatile的變量是說(shuō)這變量可能會(huì)被意想不到地改變,這樣,編譯器就不會(huì)去假設(shè)這個(gè)變量的值了。精確地說(shuō)就是,優(yōu)化器在用到
這個(gè)變量時(shí)必須每次都小心地重新讀取這個(gè)變量的值,而不是使用保存在寄存器里的備份。下面是volatile變量的幾個(gè)例子:
? 并行設(shè)備的硬件寄存器(如:狀態(tài)寄存器)
? 一個(gè)中斷服務(wù)子程序中會(huì)訪問(wèn)到的非自動(dòng)變量(Non-automatic variables)
? 多線程應(yīng)用中被幾個(gè)任務(wù)共享的變量
? 一個(gè)參數(shù)既可以是const還可以是volatile嗎?解釋為什么。
? 一個(gè)指針可以是volatile 嗎?解釋為什么。
下面是答案:
? 是的。一個(gè)例子是只讀的狀態(tài)寄存器。它是volatile因?yàn)樗赡鼙灰庀氩坏降馗淖?。它是const因?yàn)槌绦虿粦?yīng)該試圖去修改它。
? 是的。盡管這并不很常見(jiàn)。一個(gè)例子是當(dāng)一個(gè)中服務(wù)子程序修該一個(gè)指向一個(gè)buffer的指針時(shí)。
22@synthesize 是系統(tǒng)自動(dòng)生成getter和setter屬性聲明
@dynamic 是開發(fā)者自已提供相應(yīng)的屬性聲明
@dynamic 意思是由開發(fā)人員提供相應(yīng)的代碼:對(duì)于只讀屬性需要提供 setter,對(duì)于讀寫屬性需要提供 setter 和getter。@synthesize 意思是,除非開發(fā)人員已經(jīng)做了,否則由編譯器生成相應(yīng)的代碼,以滿足屬性聲明。
查閱了一些資料確定@dynamic的意思是告訴編譯器,屬性的獲取與賦值方法由用戶自己實(shí)現(xiàn), 不自動(dòng)生成。
23Difference between shallow copy and deep copy?淺復(fù)制和深復(fù)制的區(qū)別?答案:淺層復(fù)制:只復(fù)制指向?qū)ο蟮闹羔?,而不?fù)制引用對(duì)象本身。深層復(fù)制:復(fù)制引用對(duì)象本身。意思就是說(shuō)我有個(gè)A對(duì)象,復(fù)制一份后得到A_copy對(duì)象后,對(duì)于淺復(fù)制來(lái)說(shuō),A和A_copy指向的是同一個(gè)內(nèi)存資源,復(fù)制的只不過(guò)是是一個(gè)指針,對(duì)象本身資源還是只有一份,那如果我們對(duì)A_copy執(zhí)行了修改操作,那么發(fā)現(xiàn)A引用的對(duì)象同樣被修改,這其實(shí)違背了我們復(fù)制拷貝的一個(gè)思想。深復(fù)制就好理解了,內(nèi)存中存在了兩份獨(dú)立對(duì)象本身。用網(wǎng)上一哥們通俗的話將就是:淺復(fù)制好比你和你的影子,你完蛋,你的影子也完蛋深復(fù)制好比你和你的克隆人,你完蛋,你的克隆人還活著。
24What is advantage of categories? What is difference between implementing a category and inheritance?類別的作用?繼承和類別在實(shí)現(xiàn)中有何區(qū)別?答案:category 可以在不獲悉,不改變?cè)瓉?lái)代碼的情況下往里面添加新的方法,只能添加,不能刪除修改。并且如果類別和原來(lái)類中的方法產(chǎn)生名稱沖突,則類別將覆蓋原來(lái)的方法,因?yàn)轭悇e具有更高的優(yōu)先級(jí)。類別主要有3個(gè)作用:(1)將類的實(shí)現(xiàn)分散到多個(gè)不同文件或多個(gè)不同框架中。(2)創(chuàng)建對(duì)私有方法的前向引用。(3)向?qū)ο筇砑臃钦絽f(xié)議。 繼承可以增加,修改或者刪除方法,并且可以增加屬性。
25.Difference between categories and extensions?類別和類擴(kuò)展的區(qū)別。 答案:category和extensions的不同在于 后者可以添加屬性。另外后者添加的方法是必須要實(shí)現(xiàn)的。extensions可以認(rèn)為是一個(gè)私有的Category。
26.Difference between protocol in objective c and interfaces injava?oc中的協(xié)議和java中的接口概念有何不同?答案:OC中的代理有2層含義,官方定義為 formal和informal protocol。前者和Java接口一樣。informal protocol中的方法屬于設(shè)計(jì)模式考慮范疇,不是必須實(shí)現(xiàn)的,但是如果有實(shí)現(xiàn),就會(huì)改變類的屬性。其實(shí)關(guān)于正式協(xié)議,類別和非正式協(xié)議我很早前學(xué)習(xí)的時(shí)候大致看過(guò),也寫在了學(xué)習(xí)教程里“非正式協(xié)議概念其實(shí)就是類別的另一種表達(dá)方式“這里有一些你可能希望實(shí)現(xiàn)的方法,你可以使用他們更好的完成工作”。這個(gè)意思是,這些是可選的。比如我門要一個(gè)更好的方法,我們就會(huì)申明一個(gè)這樣的類別去實(shí)現(xiàn)。然后你在后期可以直接使用這些更好的方法。這么看,總覺(jué)得類別這玩意兒有點(diǎn)像協(xié)議的可選協(xié)議。"現(xiàn)在來(lái)看,其實(shí)protocal已經(jīng)開始對(duì)兩者都統(tǒng)一和規(guī)范起來(lái)操作,因?yàn)橘Y料中說(shuō)“非正式協(xié)議使用interface修飾“,現(xiàn)在我們看到協(xié)議中兩個(gè)修飾詞:“必須實(shí)現(xiàn)(@requied)”和“可選實(shí)現(xiàn)(@optional)”。
26What are KVO and KVC?答案:kvc:鍵 - 值編碼是一種間接訪問(wèn)對(duì)象的屬性使用字符串來(lái)標(biāo)識(shí)屬性,而不是通過(guò)調(diào)用存取方法,直接或通過(guò)實(shí)例變量訪問(wèn)的機(jī)制。很多情況下可以簡(jiǎn)化程序代碼。apple文檔其實(shí)給了一個(gè)很好的例子。kvo:鍵值觀察機(jī)制,他提供了觀察某一屬性變化的方法,極大的簡(jiǎn)化了代碼。具體用看到嗯哼用到過(guò)的一個(gè)地方是對(duì)于按鈕點(diǎn)擊變化狀態(tài)的的監(jiān)控。比如我自定義的一個(gè)button[cpp] [self addObserver:self forKeyPath:@"highlighted" options:0 context:nil]; #pragma mark KVO - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"highlighted"] ) { [self setNeedsDisplay]; } }
對(duì)于系統(tǒng)是根據(jù)keypath去取的到相應(yīng)的值發(fā)生改變,理論上來(lái)說(shuō)是和kvc機(jī)制的道理是一樣的。對(duì)于kvc機(jī)制如何通過(guò)key尋找到value:“當(dāng)通過(guò)KVC調(diào)用對(duì)象時(shí),比如:[self valueForKey:@”someKey”]時(shí),程序會(huì)自動(dòng)試圖通過(guò)幾種不同的方式解析這個(gè)調(diào)用。首先查找對(duì)象是否帶有 someKey 這個(gè)方法,如果沒(méi)找到,會(huì)繼續(xù)查找對(duì)象是否帶有someKey這個(gè)實(shí)例變量(iVar),如果還沒(méi)有找到,程序會(huì)繼續(xù)試圖調(diào)用 -(id) valueForUndefinedKey:這個(gè)方法。如果這個(gè)方法還是沒(méi)有被實(shí)現(xiàn)的話,程序會(huì)拋出一個(gè)NSUndefinedKeyException異常錯(cuò)誤。(cocoachina.com注:Key-Value Coding查找方法的時(shí)候,不僅僅會(huì)查找someKey這個(gè)方法,還會(huì)查找getsomeKey這個(gè)方法,前面加一個(gè)get,或者_(dá)someKey以及_getsomeKey這幾種形式。同時(shí),查找實(shí)例變量的時(shí)候也會(huì)不僅僅查找someKey這個(gè)變量,也會(huì)查找_someKey這個(gè)變量是否存在。)設(shè)計(jì)valueForUndefinedKey:方法的主要目的是當(dāng)你使用-(id)valueForKey方法從對(duì)象中請(qǐng)求值時(shí),對(duì)象能夠在錯(cuò)誤發(fā)生前,有最后的機(jī)會(huì)響應(yīng)這個(gè)請(qǐng)求。這樣做有很多好處,下面的兩個(gè)例子說(shuō)明了這樣做的好處?!皝?lái)至cocoa,這個(gè)說(shuō)法應(yīng)該挺有道理。因?yàn)槲覀冎纀utton卻是存在一個(gè)highlighted實(shí)例變量.因此為何上面我們只是add一個(gè)相關(guān)的keypath就行了,
27What is purpose of delegates?代理的作用?答案:代理的目的是改變或傳遞控制鏈。允許一個(gè)類在某些特定時(shí)刻通知到其他類,而不需要獲取到那些類的指針??梢詼p少框架復(fù)雜度。另外一點(diǎn),代理可以理解為java中的回調(diào)監(jiān)聽機(jī)制的一種類似。
28What are mutable and immutable types in Objective C?oc中可修改和不可以修改類型。答案:可修改不可修改的集合類。這個(gè)我個(gè)人簡(jiǎn)單理解就是可動(dòng)態(tài)添加修改和不可動(dòng)態(tài)添加修改一樣。比如NSArray和NSMutableArray。前者在初始化后的內(nèi)存控件就是固定不可變的,后者可以添加等,可以動(dòng)態(tài)申請(qǐng)新的內(nèi)存空間
29When we call objective c is runtime language what does it mean?我們說(shuō)的oc是動(dòng)態(tài)運(yùn)行時(shí)語(yǔ)言是什么意思?答案:多態(tài)。主要是將數(shù)據(jù)類型的確定由編譯時(shí),推遲到了運(yùn)行時(shí)。這個(gè)問(wèn)題其實(shí)淺涉及到兩個(gè)概念,運(yùn)行時(shí)和多態(tài)。簡(jiǎn)單來(lái)說(shuō),運(yùn)行時(shí)機(jī)制使我們直到運(yùn)行時(shí)才去決定一個(gè)對(duì)象的類別,以及調(diào)用該類別對(duì)象指定方法。多態(tài):不同對(duì)象以自己的方式響應(yīng)相同的消息的能力叫做多態(tài)。意思就是假設(shè)生物類(life)都用有一個(gè)相同的方法-eat;那人類屬于生物,豬也屬于生物,都繼承了life后,實(shí)現(xiàn)各自的eat,但是調(diào)用是我們只需調(diào)用各自的eat方法。也就是不同的對(duì)象以自己的方式響應(yīng)了相同的消息(響應(yīng)了eat這個(gè)選擇器)。因此也可以說(shuō),運(yùn)行時(shí)機(jī)制是多態(tài)的基礎(chǔ)?~~~
30what is difference between NSNotification and protocol?通知和協(xié)議的不同之處?答案:協(xié)議有控制鏈(has-a)的關(guān)系,通知沒(méi)有。首先我一開始也不太明白,什么叫控制鏈(專業(yè)術(shù)語(yǔ)了~)。但是簡(jiǎn)單分析下通知和代理的行為模式,我們大致可以有自己的理解簡(jiǎn)單來(lái)說(shuō),通知的話,它可以一對(duì)多,一條消息可以發(fā)送給多個(gè)消息接受者。代理按我們的理解,到不是直接說(shuō)不能一對(duì)多,比如我們知道的明星經(jīng)濟(jì)代理人,很多時(shí)候一個(gè)經(jīng)濟(jì)人負(fù)責(zé)好幾個(gè)明星的事務(wù)。只是對(duì)于不同明星間,代理的事物對(duì)象都是不一樣的,一一對(duì)應(yīng),不可能說(shuō)明天要處理A明星要一個(gè)發(fā)布會(huì),代理人發(fā)出處理發(fā)布會(huì)的消息后,別稱B的發(fā)布會(huì)了。但是通知就不一樣,他只關(guān)心發(fā)出通知,而不關(guān)心多少接收到感興趣要處理。因此控制鏈(has-a從英語(yǔ)單詞大致可以看出,單一擁有和可控制的對(duì)應(yīng)關(guān)系。
31What is push notification?什么是推送消息?答案:太簡(jiǎn)單,不作答~~~~~~~~~~這是cocoa上的答案。其實(shí)到不是說(shuō)太簡(jiǎn)單,只是太泛泛的一個(gè)概念的東西。就好比說(shuō),什么是人。推送通知更是一種技術(shù)。簡(jiǎn)單點(diǎn)就是客戶端獲取資源的一種手段。普通情況下,都是客戶端主動(dòng)的pull。推送則是服務(wù)器端主動(dòng)push。
32.Polymorphism?關(guān)于多態(tài)性答案:多態(tài),子類指針可以賦值給父類。這個(gè)題目其實(shí)可以出到一切面向?qū)ο笳Z(yǔ)言中,因此關(guān)于多態(tài),繼承和封裝基本最好都有個(gè)自我意識(shí)的理解,也并非一定要把書上資料上寫的能背出來(lái)。最重要的是轉(zhuǎn)化成自我理解。
33
What is responder chain?說(shuō)說(shuō)響應(yīng)鏈答案:事件響應(yīng)鏈。包括點(diǎn)擊事件,畫面刷新事件等。在視圖棧內(nèi)從上至下,或者從下之上傳播??梢哉f(shuō)點(diǎn)事件的分發(fā),傳遞以及處理。具體可以去看下touch事件這塊。因?yàn)閱?wèn)的太抽象化了嚴(yán)重懷疑題目出到越后面就越笼統(tǒng)。
34Difference between frame and bounds?frame和bounds有什么不同?答案:frame指的是:該view在父view坐標(biāo)系統(tǒng)中的位置和大小。(參照點(diǎn)是父親的坐標(biāo)系統(tǒng))bounds指的是:該view在本身坐標(biāo)系統(tǒng)中 的位置和大小。(參照點(diǎn)是本身坐標(biāo)系統(tǒng))
35
.Difference between method and selector?方法和選擇器有何不同?答案:selector是一個(gè)方法的名字,method是一個(gè)組合體,包含了名字和實(shí)現(xiàn).
36NSOperation queue?答案:存放NSOperation的集合類。操作和操作隊(duì)列,基本可以看成java中的線程和線程池的概念。用于處理ios多線程開發(fā)的問(wèn)題。網(wǎng)上部分資料提到一點(diǎn)是,雖然是queue,但是卻并不是帶有隊(duì)列的概念,放入的操作并非是按照嚴(yán)格的先進(jìn)現(xiàn)出。這邊又有個(gè)疑點(diǎn)是,對(duì)于隊(duì)列來(lái)說(shuō),先進(jìn)先出的概念是Afunc添加進(jìn)隊(duì)列,Bfunc緊跟著也進(jìn)入隊(duì)列,Afunc先執(zhí)行這個(gè)是必然的,但是Bfunc是等Afunc完全操作完以后,B才開始啟動(dòng)并且執(zhí)行,因此隊(duì)列的概念離亂上有點(diǎn)違背了多線程處理這個(gè)概念。但是轉(zhuǎn)念一想其實(shí)可以參考銀行的取票和叫號(hào)系統(tǒng)。因此對(duì)于A比B先排隊(duì)取票但是B率先執(zhí)行完操作,我們亦然可以感性認(rèn)為這還是一個(gè)隊(duì)列。但是后來(lái)看到一票關(guān)于這操作隊(duì)列話題的文章,其中有一句提到“因?yàn)閮蓚€(gè)操作提交的時(shí)間間隔很近,線程池中的線程,誰(shuí)先啟動(dòng)是不定的。”瞬間覺(jué)得這個(gè)queue名字有點(diǎn)忽悠人了,還不如pool~綜合一點(diǎn),我們知道他可以比較大的用處在于可以幫組多線程編程就好了。
37What is lazy loading?答案:懶漢模式,只在用到的時(shí)候才去初始化。也可以理解成延時(shí)加載。我覺(jué)得最好也最簡(jiǎn)單的一個(gè)列子就是tableView中圖片的加載顯示了。一個(gè)延時(shí)載,避免內(nèi)存過(guò)高,一個(gè)異步加載,避免線程堵塞。
38Can we use two tableview controllers on one viewcontroller?是否在一個(gè)視圖控制器中嵌入兩個(gè)tableview控制器?答案:一個(gè)視圖控制只提供了一個(gè)View視圖,理論上一個(gè)tableViewController也不能放吧,只能說(shuō)可以嵌入一個(gè)tableview視圖。當(dāng)然,題目本身也有歧義,如果不是我們定性思維認(rèn)為的UIViewController,而是宏觀的表示視圖控制者,那我們倒是可以把其看成一個(gè)視圖控制者,它可以控制多個(gè)視圖控制器,比如TabbarController那樣的感覺(jué)。
39Can we use one tableview with two different datasources? How you will achieve this?一個(gè)tableView是否可以關(guān)聯(lián)兩個(gè)不同的數(shù)據(jù)源?你會(huì)怎么處理?答案:首先我們從代碼來(lái)看,數(shù)據(jù)源如何關(guān)聯(lián)上的,其實(shí)是在數(shù)據(jù)源關(guān)聯(lián)的代理方法里實(shí)現(xiàn)的。因此我們并不關(guān)心如何去關(guān)聯(lián)他,他怎么關(guān)聯(lián)上,方法只是讓我返回根據(jù)自己的需要去設(shè)置如相關(guān)的數(shù)據(jù)源。因此,我覺(jué)得可以設(shè)置多個(gè)數(shù)據(jù)源啊,但是有個(gè)問(wèn)題是,你這是想干嘛呢?想讓列表如何顯示,不同的數(shù)據(jù)源分區(qū)塊顯示?
40id、nil代表什么?
id和void *并非完全一樣。在上面的代碼中,id是指向struct objc_object的一個(gè)指針,這個(gè)意思基本上是說(shuō),id是一個(gè)指向任何一個(gè)繼承了Object(或者NSObject)類的對(duì)象。需要注意的是id是一個(gè)指針,所以你在使用id的時(shí)候不需要加星號(hào)。比如id foo=nil定義了一個(gè)nil指針,這個(gè)指針指向NSObject的一個(gè)任意子類。而id *foo=nil則定義了一個(gè)指針,這個(gè)指針指向另一個(gè)指針,被指向的這個(gè)指針指向NSObject的一個(gè)子類。
nil和C語(yǔ)言的NULL相同,在objc/objc.h中定義。nil表示一個(gè)Objctive-C對(duì)象,這個(gè)對(duì)象的指針指向空(沒(méi)有東西就是空)。
首字母大寫的Nil和nil有一點(diǎn)不一樣,Nil定義一個(gè)指向空的類(是Class,而不是對(duì)象)。
SEL是“selector”的一個(gè)類型,表示一個(gè)方法的名字
Method(我們常說(shuō)的方法)表示一種類型,這種類型與selector和實(shí)現(xiàn)(implementation)相關(guān)
IMP定義為 id (*IMP) (id, SEL, …)。這樣說(shuō)來(lái), IMP是一個(gè)指向函數(shù)的指針,這個(gè)被指向的函數(shù)包括id(“self”指針),調(diào)用的SEL(方法名),再加上一些其他參數(shù).說(shuō)白了IMP就是實(shí)現(xiàn)方法。
41層和UIView的區(qū)別是什么?
答:兩者最大的區(qū)別是,圖層不會(huì)直接渲染到屏幕上,UIView是iOS系統(tǒng)中界面元素的基礎(chǔ),所有的界面元素都是繼承自它。它本身完全是由CoreAnimation來(lái)實(shí)現(xiàn)的。它真正的繪圖部分,是由一個(gè)CALayer類來(lái)管理。UIView本身更像是一個(gè)CALayer的管理器。一個(gè)UIView上可以有n個(gè)CALayer,每個(gè)layer顯示一種東西,增強(qiáng)UIView的展現(xiàn)能力。
42GCD為Grand Central Dispatch的縮寫?! rand Central Dispatch (GCD)是Apple開發(fā)的一個(gè)多核編程的較新的解決方法。在Mac OS X 10.6雪豹中首次推出,并在最近引入到了iOS4.0?! CD是一個(gè)替代諸如NSThread等技術(shù)的很高效和強(qiáng)大的技術(shù)。GCD完全可以處理諸如數(shù)據(jù)鎖定和資源泄漏等復(fù)雜的異步編程問(wèn)題?!?/p>
GCD可以完成很多事情,但是這里僅關(guān)注在iOS應(yīng)用中實(shí)現(xiàn)多線程所需的一些基礎(chǔ)知識(shí)?! ≡陂_始之前,需要理解是要提供給GCD隊(duì)列的是代碼塊,用于在系統(tǒng)或者用戶創(chuàng)建的的隊(duì)列上調(diào)度運(yùn)行?! ?strong>聲明一個(gè)隊(duì)列
如下會(huì)返回一個(gè)用戶創(chuàng)建的隊(duì)列:
dispatch_queue_t myQueue = dispatch_queue_create("com.iphonedevblog.post", NULL);其中,第一個(gè)參數(shù)是標(biāo)識(shí)隊(duì)列的,第二個(gè)參數(shù)是用來(lái)定義隊(duì)列的參數(shù)(目前不支持,因此傳入NULL)?!?/p>
執(zhí)行一個(gè)隊(duì)列
如下會(huì)異步執(zhí)行傳入的代碼:
dispatch_async(myQueue, ^{ [self doSomething]; });其中,首先傳入之前創(chuàng)建的隊(duì)列,然后提供由隊(duì)列運(yùn)行的代碼塊?! ?/p>
聲明并執(zhí)行一個(gè)隊(duì)列
如果不需要保留要運(yùn)行的隊(duì)列的引用,可以通過(guò)如下代碼實(shí)現(xiàn)之前的功能: dispatch_async(dispatch_queue_create ("com.iphonedevblog.post", NULL), ^{ [self doSomething]; }); 如果需要暫停一個(gè)隊(duì)列,可以調(diào)用如下代碼。暫停一個(gè)隊(duì)列會(huì)阻止和該隊(duì)列相關(guān)的所有代碼運(yùn)行。 dispatch_suspend(myQueue);暫停一個(gè)隊(duì)列
如果暫停一個(gè)隊(duì)列不要忘記恢復(fù)。暫停和恢復(fù)的操作和內(nèi)存管理中的retain和release類似。調(diào)用dispatch_suspend會(huì)增加暫停計(jì)數(shù),而dispatch_resume則會(huì)減少。隊(duì)列只有在暫停計(jì)數(shù)變成零的情況下才開始運(yùn)行。dispatch_resume(myQueue);恢復(fù)一個(gè)隊(duì)列 從隊(duì)列中在主線程運(yùn)行代碼 有些操作無(wú)法在異步隊(duì)列運(yùn)行,因此必須在主線程(每個(gè)應(yīng)用都有一個(gè))上運(yùn)行。UI繪圖以及任何對(duì)NSNotificationCenter的調(diào)用必須在主線程長(zhǎng)進(jìn)行。在另一個(gè)隊(duì)列中訪問(wèn)主線程并運(yùn)行代碼的示例如下: dispatch_sync(dispatch_get_main_queue(), ^{ [self dismissLoginWindow]; });注意,dispatch_suspend (以及dispatch_resume)在主線程上不起作用。
使用GCD,可以讓你的程序不會(huì)失去響應(yīng). 多線程不容易使用,用了GCD,會(huì)讓它變得簡(jiǎn)單。你無(wú)需專門進(jìn)行線程管理, 很棒!
dispatch_queue_t t1=dispatch_queue_create("1", NULL);
dispatch_queue_t t2=dispatch_queue_create("2", NULL);
dispatch_async(t1, ^{
[self print1];
});
dispatch_async(t2, ^{
[self print2];
});
43Provider是指某個(gè)iPhone軟件的Push服務(wù)器,這篇文章我將使用.net作為Provider。 APNS 是Apple Push Notification Service(Apple Push服務(wù)器)的縮寫,是蘋果的服務(wù)器。
上圖可以分為三個(gè)階段。
第一階段:.net應(yīng)用程序把要發(fā)送的消息、目的iPhone的標(biāo)識(shí)打包,發(fā)給APNS。 第二階段:APNS在自身的已注冊(cè)Push服務(wù)的iPhone列表中,查找有相應(yīng)標(biāo)識(shí)的iPhone,并把消息發(fā)到iPhone。 第三階段:iPhone把發(fā)來(lái)的消息傳遞給相應(yīng)的應(yīng)用程序,并且按照設(shè)定彈出Push通知。
http://blog.csdn.NET/zhuqilin0/article/details/6527113 //消息推送機(jī)制
看內(nèi)存泄露時(shí)候:在搜索中搜索run 找到Run Static Snalyzer .
44.可擴(kuò)展標(biāo)記語(yǔ)言extensible markup language;xml
2.用于標(biāo)記電子文件使其具有結(jié)構(gòu)性的標(biāo)記語(yǔ)言,可以用來(lái)標(biāo)記數(shù)據(jù)、定義數(shù)據(jù)類型,是一種允許用戶對(duì)自己的標(biāo)記語(yǔ)言進(jìn)行定義的源語(yǔ)言。
3,數(shù)據(jù)庫(kù)提供了更強(qiáng)有力的數(shù)據(jù)存儲(chǔ)和分析能力,例如:數(shù)據(jù)索引、排序、查找、相關(guān)一致性等,XML僅僅是存儲(chǔ)數(shù)據(jù)。
4.XML與HTML的設(shè)計(jì)區(qū)別是:XML的核心是數(shù)據(jù),其重點(diǎn)是數(shù)據(jù)的內(nèi)容。而HTML 被設(shè)計(jì)用來(lái)顯示數(shù)據(jù),其重點(diǎn)是數(shù)據(jù)的顯示。
5.XML和HTML語(yǔ)法區(qū)別:HTML的標(biāo)記不是所有的都需要成對(duì)出現(xiàn),XML則要求所有的標(biāo)記必須成對(duì)出現(xiàn);HTML標(biāo)記不區(qū)分大小寫,XML則大小敏感,即區(qū)分大小寫。
結(jié)合
XML的簡(jiǎn)單使其易于在任何應(yīng)用程序中讀寫數(shù)據(jù),這使XML很快成為數(shù)據(jù)交換的唯一公共語(yǔ)言,雖然不同的應(yīng)用軟件也支持其它的數(shù)據(jù)交換格式,但不久之后他們都將支持XML,那就意味著程序可以更容易的與Windows,Mac OS,linux以及其他平臺(tái)下產(chǎn)生的信息結(jié)合,然后可以很容易加載XML數(shù)據(jù)到程序中并分析他,并以XML格式輸出結(jié)果。
XML去掉了之前令許多開發(fā)人員頭疼的SGML(標(biāo)準(zhǔn)通用標(biāo)記語(yǔ)言)的隨意語(yǔ)法。在XML中,采用了如下的語(yǔ)法:
1 任何的起始標(biāo)簽都必須有一個(gè)結(jié)束標(biāo)簽。
2 可以采用另一種簡(jiǎn)化語(yǔ)法,可以在一個(gè)標(biāo)簽中同時(shí)表示起始和結(jié)束標(biāo)簽。這種語(yǔ)法是在大于符號(hào)之前緊跟一個(gè)斜線(/),例如<tag/ >。XML解析器會(huì)將其翻譯成<tag></tag>。
3 標(biāo)簽必須按合適的順序進(jìn)行嵌套,所以結(jié)束標(biāo)簽必須按鏡像順序匹配起始標(biāo)簽,例如this is asamplestring。這好比是將起始和結(jié)束標(biāo)簽看作是數(shù)學(xué)中的左右括號(hào):在沒(méi)有關(guān)閉所有的內(nèi)部括號(hào)之前,是不能關(guān)閉外面的括號(hào)的。
4 所有的特性都必須有值。
5 所有的特性都必須在值的周圍加上雙引號(hào)。
45union u
{ double a; int b; };
union u2 { char a[13]; int b; };
union u3 { char a[13]; char b; };
cout<<sizeof(u)<<endl; // 8 cout<<sizeof(u2)<<endl; // 16 cout<<sizeof(u3)<<endl; // 13 |
都知道union的大小取決于它所有的成員中,占用空間最大的一個(gè)成員的大小。所以對(duì)于u來(lái)說(shuō),大小就是最大的double類型成員a了,所以 sizeof(u)=sizeof(double)=8。但是對(duì)于u2和u3,最大的空間都是char[13]類型的數(shù)組,為什么u3的大小是13,而 u2是16呢?關(guān)鍵在于u2中的成員int b。由于int類型成員的存在,使u2的對(duì)齊方式變成4,也就是說(shuō),u2的大小必須在4的對(duì)界上,所以占用的空間變成了16(最接近13的對(duì)界)。 struct s1
{ char a; double b; int c; char d; };
struct s2 { char a; char b; int c; double d; };
cout<<sizeof(s1)<<endl; // 24 cout<<sizeof(s2)<<endl; // 16 |
同樣是兩個(gè)char類型,一個(gè)int類型,一個(gè)double類型,但是因?yàn)閷?duì)界問(wèn)題,導(dǎo)致他們的大小不同。計(jì)算結(jié)構(gòu)體大小可以采用元素?cái)[放法,我舉例子說(shuō)明一下:首先,CPU判斷結(jié)構(gòu)體的對(duì)界,根據(jù)上一節(jié)的結(jié)論,s1和s2的對(duì)界都取最大的元素類型,也就是double類型的對(duì)界8。然后開始擺放每個(gè)元素。
對(duì)于s1,首先把a(bǔ)放到8的對(duì)界,假定是0,此時(shí)下一個(gè)空閑的地址是1,但是下一個(gè)元素d是double類型,要放到8的對(duì)界上,離1最接近的地址是8了,所以d被放在了8,此時(shí)下一個(gè)空閑地址變成了16,下一個(gè)元素c的對(duì)界是4,16可以滿足,所以c放在了16,此時(shí)下一個(gè)空閑地址變成了20,下一個(gè)元素d需要對(duì)界1,也正好落在對(duì)界上,所以d放在了20,結(jié)構(gòu)體在地址21處結(jié)束。由于s1的大小需要是8的倍數(shù),所以21- 23的空間被保留,s1的大小變成了24。
對(duì)于s2,首先把a(bǔ)放到8的對(duì)界,假定是0,此時(shí)下一個(gè)空閑地址是1,下一個(gè)元素的對(duì)界也是1,所以b擺放在1,下一個(gè)空閑地址變成了2;下一個(gè)元素c的對(duì)界是4,所以取離2最近的地址4擺放c,下一個(gè)空閑地址變成了8,下一個(gè)元素d的對(duì)界是 8,所以d擺放在8,所有元素?cái)[放完畢,結(jié)構(gòu)體在15處結(jié)束,占用總空間為16,正好是8的倍數(shù)。
46ASIDownloadCache 設(shè)置下載緩存
它對(duì)Get請(qǐng)求的響應(yīng)數(shù)據(jù)進(jìn)行緩存(被緩存的數(shù)據(jù)必需是成功的200請(qǐng)求):
[ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]]; |
當(dāng)設(shè)置緩存策略后,所有的請(qǐng)求都被自動(dòng)的緩存起來(lái)。
另外,如果僅僅希望某次請(qǐng)求使用緩存操作,也可以這樣使用:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setDownloadCache:[ASIDownloadCache sharedCache]]; |
緩存存儲(chǔ)方式
你可以設(shè)置緩存的數(shù)據(jù)需要保存多長(zhǎng)時(shí)間,ASIHTTPRequest提供了兩種策略:
a,ASICacheForsessionDurationCacheStoragePolicy,默認(rèn)策略,基于session的緩存數(shù)據(jù)存儲(chǔ)。當(dāng)下次運(yùn)行或[ASIHTTPRequest clearSession]時(shí),緩存將失效。
b,ASICachePermanentlyCacheStoragePolicy,把緩存數(shù)據(jù)永久保存在本地,
如:
ASIHTTPRequest *request = [ ASIHTTPRequest requestWithURL:url ]; [ request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy ]; |
47HTTP協(xié)議詳解
HTTP是一個(gè)屬于應(yīng)用層的面向?qū)ο蟮膮f(xié)議,由于其簡(jiǎn)捷、快速的方式,適用于分布式超媒體信息系統(tǒng)。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的規(guī)范化工作正在進(jìn)行之中。
http(超文本傳輸協(xié)議)是一個(gè)基于請(qǐng)求與響應(yīng)模式的、無(wú)狀態(tài)的、應(yīng)用層的協(xié)議,?;赥CP的連接方式,HTTP1.1版本中給出一種持續(xù)連接的機(jī)制,絕大多數(shù)的Web開發(fā),都是構(gòu)建在HTTP協(xié)議之上的Web應(yīng)用。HTTP協(xié)議的主要特點(diǎn)可概括如下:1.支持客戶/服務(wù)器模式。2.簡(jiǎn)單快速:客戶向服務(wù)器請(qǐng)求服務(wù)時(shí),只需傳送請(qǐng)求方法和路徑。請(qǐng)求方法常用的有GET、HEAD、POST。每種方法規(guī)定了客戶與服務(wù)器聯(lián)系的類型不同。由于HTTP協(xié)議簡(jiǎn)單,使得HTTP服務(wù)器的程序規(guī)模小,因而通信速度很快。3.靈活:HTTP允許傳輸任意類型的數(shù)據(jù)對(duì)象。正在傳輸?shù)念愋陀蒀ontent-Type加以標(biāo)記。4.無(wú)連接:無(wú)連接的含義是限制每次連接只處理一個(gè)請(qǐng)求。服務(wù)器處理完客戶的請(qǐng)求,并收到客戶的應(yīng)答后,即斷開連接。采用這種方式可以節(jié)省傳輸時(shí)間。5.無(wú)狀態(tài):HTTP協(xié)議是無(wú)狀態(tài)協(xié)議。無(wú)狀態(tài)是指協(xié)議對(duì)于事務(wù)處理沒(méi)有記憶能力。缺少狀態(tài)意味著如果后續(xù)處理需要前面的信息,則它必須重傳,這樣可能導(dǎo)致每次連接傳送的數(shù)據(jù)量增大。另一方面,在服務(wù)器不需要先前信息時(shí)它的應(yīng)答就較快。
48URL
HTTP URL (URL是一種特殊類型的URI是他的子類,包含了用于查找某個(gè)資源的足夠的信息)的格式如下:http://host[":"port][abs_path]http表示要通過(guò)HTTP協(xié)議來(lái)定位網(wǎng)絡(luò)資源;host表示合法的Internet主機(jī)域名或者IP地址;port指定一個(gè)端口號(hào),為空則使用缺省端口80;abs_path指定請(qǐng)求資源的URI;如果URL中沒(méi)有給出abs_path,那么當(dāng)它作為請(qǐng)求URI時(shí),必須以“/”的形式給出,通常這個(gè)工作瀏覽器自動(dòng)幫我們完成。
49TCP/UDP區(qū)別聯(lián)系
TCP---傳輸控制協(xié)議,提供的是面向連接、可靠的字節(jié)流服務(wù)。當(dāng)客戶和服務(wù)器彼此交換數(shù)據(jù)前,必須先在雙方之間建立一個(gè)TCP連接,之后才能傳輸數(shù)據(jù)。TCP提供超時(shí)重發(fā),丟棄重復(fù)數(shù)據(jù),檢驗(yàn)數(shù)據(jù),流量控制等功能,保證數(shù)據(jù)能從一端傳到另一端。
UDP---用戶數(shù)據(jù)報(bào)協(xié)議,是一個(gè)簡(jiǎn)單的面向數(shù)據(jù)報(bào)的運(yùn)輸層協(xié)議。UDP不提供可靠性,它只是把應(yīng)用程序傳給IP層的數(shù)據(jù)報(bào)發(fā)送出去,但是并不能保證它們能到達(dá)目的地。由于UDP在傳輸數(shù)據(jù)報(bào)前不用在客戶和服務(wù)器之間建立一個(gè)連接,且沒(méi)有超時(shí)重發(fā)等機(jī)制,故而傳輸速度很快
TCP(Transmission Control Protocol,傳輸控制協(xié)議)是基于連接的協(xié)議,也就是說(shuō),在正式收發(fā)數(shù)據(jù)前,必須和對(duì)方建立可靠的連接。一個(gè)TCP連接必須要經(jīng)過(guò)三次“對(duì)話”才能建立起來(lái),我們來(lái)看看這三次對(duì)話的簡(jiǎn)單過(guò)程:1.主機(jī)A向主機(jī)B發(fā)出連接請(qǐng)求數(shù)據(jù)包;2.主機(jī)B向主機(jī)A發(fā)送同意連接和要求同步(同步就是兩臺(tái)主機(jī)一個(gè)在發(fā)送,一個(gè)在接收,協(xié)調(diào)工作)的數(shù)據(jù)包;3.主機(jī)A再發(fā)出一個(gè)數(shù)據(jù)包確認(rèn)主機(jī)B的要求同步:“我現(xiàn)在就發(fā),你接著吧!”,這是第三次對(duì)話。三次“對(duì)話”的目的是使數(shù)據(jù)包的發(fā)送和接收同步,經(jīng)過(guò)三次“對(duì)話”之后,主機(jī)A才向主機(jī)B正式發(fā)送數(shù)據(jù)。
UDP(User Data Protocol,用戶數(shù)據(jù)報(bào)協(xié)議)是與TCP相對(duì)應(yīng)的協(xié)議。它是面向非連接的協(xié)議,它不與對(duì)方建立連接,而是直接就把數(shù)據(jù)包發(fā)送過(guò)去! UDP適用于一次只傳送少量數(shù)據(jù)、對(duì)可靠性要求不高的應(yīng)用環(huán)境。
tcp協(xié)議和udp協(xié)議的差別
是否連接面向連接面向非連接
傳輸可靠性可靠不可靠
應(yīng)用場(chǎng)合傳輸大量數(shù)據(jù)少量數(shù)據(jù)
速度慢快
50socket連接和http連接的區(qū)別
簡(jiǎn)單說(shuō),你瀏覽的網(wǎng)頁(yè)(網(wǎng)址以http://開頭)都是http協(xié)議傳輸?shù)侥愕臑g覽器的, 而http是基于socket之上的。socket是一套完成tcp,udp協(xié)議的接口。
HTTP協(xié)議:簡(jiǎn)單對(duì)象訪問(wèn)協(xié)議,對(duì)應(yīng)于應(yīng)用層 ,HTTP協(xié)議是基于TCP連接的
tcp協(xié)議: 對(duì)應(yīng)于傳輸層
ip協(xié)議: 對(duì)應(yīng)于網(wǎng)絡(luò)層 TCP/IP是傳輸層協(xié)議,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸;而HTTP是應(yīng)用層協(xié)議,主要解決如何包裝數(shù)據(jù)。
Socket是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API),通過(guò)Socket,我們才能使用TCP/IP協(xié)議。
http連接:http連接就是所謂的短連接,即客戶端向服務(wù)器端發(fā)送一次請(qǐng)求,服務(wù)器端響應(yīng)后連接即會(huì)斷掉;
socket連接:socket連接就是所謂的長(zhǎng)連接,理論上客戶端和服務(wù)器端一旦建立起連接將不會(huì)主動(dòng)斷掉;但是由于各種環(huán)境因素可能會(huì)是連接斷開,比如說(shuō):服務(wù)器端或客戶端主機(jī)down了,網(wǎng)絡(luò)故障,或者兩者之間長(zhǎng)時(shí)間沒(méi)有數(shù)據(jù)傳輸,網(wǎng)絡(luò)防火墻可能會(huì)斷開該連接以釋放網(wǎng)絡(luò)資源。所以當(dāng)一個(gè)socket連接中沒(méi)有數(shù)據(jù)的傳輸,那么為了維持連接需要發(fā)送心跳消息~~具體心跳消息格式是開發(fā)者自己定義的
我們已經(jīng)知道網(wǎng)絡(luò)中的進(jìn)程是通過(guò)socket來(lái)通信的,那什么是socket呢?socket起源于Unix,而Unix/Linux基本哲學(xué)之一就是“一切皆文件”,都可以用“打開open –> 讀寫write/read –> 關(guān)閉close”模式來(lái)操作。我的理解就是Socket就是該模式的一個(gè)實(shí)現(xiàn),socket即是一種特殊的文件,一些socket函數(shù)就是對(duì)其進(jìn)行的操作(讀/寫IO、打開、關(guān)閉),這些函數(shù)我們?cè)诤竺孢M(jìn)行介紹。我們?cè)趥鬏敂?shù)據(jù)時(shí),可以只使用(傳輸層)TCP/IP協(xié)議,但是那樣的話,如果沒(méi)有應(yīng)用層,便無(wú)法識(shí)別數(shù)據(jù)內(nèi)容,如果想要使傳輸?shù)臄?shù)據(jù)有意義,則必須使用到應(yīng)用層協(xié)議,應(yīng)用層協(xié)議有很多,比如HTTP、FTP、TELNET等,也可以自己定義應(yīng)用層協(xié)議。WEB使用HTTP協(xié)議作應(yīng)用層協(xié)議,以封裝HTTP文本信息,然后使用TCP/IP做傳輸層協(xié)議將它發(fā)到網(wǎng)絡(luò)上。1)Socket是一個(gè)針對(duì)TCP和UDP編程的接口,你可以借助它建立TCP連接等等。而TCP和UDP協(xié)議屬于傳輸層 。 而http是個(gè)應(yīng)用層的協(xié)議,它實(shí)際上也建立在TCP協(xié)議之上。
(HTTP是轎車,提供了封裝或者顯示數(shù)據(jù)的具體形式;Socket是發(fā)動(dòng)機(jī),提供了網(wǎng)絡(luò)通信的能力。)
2)Socket是對(duì)TCP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個(gè)調(diào)用接口(API),通過(guò)Socket,我們才能使用TCP/IP協(xié)議。Socket的出現(xiàn)只是使得程序員更方便地使用TCP/IP協(xié)議棧而已,是對(duì)TCP/IP協(xié)議的抽象,從而形成了我們知道的一些最基本的函數(shù)接口。
51什么是TCP連接的三次握手
第一次握手:客戶端發(fā)送syn包(syn=j)到服務(wù)器,并進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器確認(rèn);第二次握手:服務(wù)器收到syn包,必須確認(rèn)客戶的SYN(ack=j+1),同時(shí)自己也發(fā)送一個(gè)SYN包(syn=k),即SYN+ACK包,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);第三次握手:客戶端收到服務(wù)器的SYN+ACK包,向服務(wù)器發(fā)送確認(rèn)包ACK(ack=k+1),此包發(fā)送完畢,客戶端和服務(wù)器進(jìn)入ESTABLISHED狀態(tài),完成三次握手。
握手過(guò)程中傳送的包里不包含數(shù)據(jù),三次握手完畢后,客戶端與服務(wù)器才正式開始傳送數(shù)據(jù)。理想狀態(tài)下,TCP連接一旦建立,在通信雙方中的任何一方主動(dòng)關(guān)閉連接之前,TCP 連接都將被一直保持下去。斷開連接時(shí)服務(wù)器和客戶端均可以主動(dòng)發(fā)起斷開TCP連接的請(qǐng)求,斷開過(guò)程需要經(jīng)過(guò)“四次握手”(過(guò)程就不細(xì)寫了,就是服務(wù)器和客戶端交互,最終確定斷開)
52利用Socket建立網(wǎng)絡(luò)連接的步驟
建立Socket連接至少需要一對(duì)套接字,其中一個(gè)運(yùn)行于客戶端,稱為ClientSocket ,另一個(gè)運(yùn)行于服務(wù)器端,稱為ServerSocket 。
套接字之間的連接過(guò)程分為三個(gè)步驟:服務(wù)器監(jiān)聽,客戶端請(qǐng)求,連接確認(rèn)。
1。服務(wù)器監(jiān)聽:服務(wù)器端套接字并不定位具體的客戶端套接字,而是處于等待連接的狀態(tài),實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài),等待客戶端的連接請(qǐng)求。
2??蛻舳苏?qǐng)求:指客戶端的套接字提出連接請(qǐng)求,要連接的目標(biāo)是服務(wù)器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務(wù)器的套接字,指出服務(wù)器端套接字的地址和端口號(hào),然后就向服務(wù)器端套接字提出連接請(qǐng)求。
3。連接確認(rèn):當(dāng)服務(wù)器端套接字監(jiān)聽到或者說(shuō)接收到客戶端套接字的連接請(qǐng)求時(shí),就響應(yīng)客戶端套接字的請(qǐng)求,建立一個(gè)新的線程,把服務(wù)器端套接字的描述發(fā)給客戶端,一旦客戶端確認(rèn)了此描述,雙方就正式建立連接。而服務(wù)器端套接字繼續(xù)處于監(jiān)聽狀態(tài),繼續(xù)接收其他客戶端套接字的連接請(qǐng)求。
53進(jìn)程與線程
進(jìn)程(process)是一塊包含了某些資源的內(nèi)存區(qū)域。操作系統(tǒng)利用進(jìn)程把它的工作劃分為一些功能單元。
進(jìn)程中所包含的一個(gè)或多個(gè)執(zhí)行單元稱為線程(thread)。進(jìn)程還擁有一個(gè)私有的虛擬地址空間,該空間僅能被它所包含的線程訪問(wèn)。
通常在一個(gè)進(jìn)程中可以包含若干個(gè)線程,它們可以利用進(jìn)程所擁有的資源。
在引入線程的操作系統(tǒng)中,通常都是把進(jìn)程作為分配資源的基本單位,而把線程作為獨(dú)立運(yùn)行和獨(dú)立調(diào)度的基本單位。
由于線程比進(jìn)程更小,基本上不擁有系統(tǒng)資源,故對(duì)它的調(diào)度所付出的開銷就會(huì)小得多,能更高效的提高系統(tǒng)內(nèi)多個(gè)程序間并發(fā)執(zhí)行的程度。
簡(jiǎn)而言之,一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程.一個(gè)程序就是一個(gè)進(jìn)程,而一個(gè)程序中的多個(gè)任務(wù)則被稱為線程。
線程只能歸屬于一個(gè)進(jìn)程并且它只能訪問(wèn)該進(jìn)程所擁有的資源。當(dāng)操作系統(tǒng)創(chuàng)建一個(gè)進(jìn)程后,該進(jìn)程會(huì)自動(dòng)申請(qǐng)一個(gè)名為主線程或首要線程的線程。應(yīng)用程序(application)是由一個(gè)或多個(gè)相互協(xié)作的進(jìn)程組成的。
另外,進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率。線程在執(zhí)行過(guò)程中與進(jìn)程還是有區(qū)別的。每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。從邏輯角度來(lái)看,多線程的意義在于一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒(méi)有將多個(gè)線程看做多個(gè)獨(dú)立的應(yīng)用,來(lái)實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配。這就是進(jìn)程和線程的重要區(qū)別。
進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位.線程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,它是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位.線程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),但是它可與同屬一個(gè)進(jìn)程的其他的線程共享進(jìn)程所擁有的全部資源.一個(gè)線程可以創(chuàng)建和撤銷另一個(gè)線程;同一個(gè)進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行.
54多線程
多線程編程是防止主線程堵塞,增加運(yùn)行效率等等的最佳方法。而原始的多線程方法存在很多的毛病,包括線程鎖死等。在Cocoa中,Apple提供了NSOperation這個(gè)類,提供了一個(gè)優(yōu)秀的多線程編程方法。
本次介紹NSOperation的子集,簡(jiǎn)易方法的NSInvocationOperation:
一個(gè)NSOperationQueue 操作隊(duì)列,就相當(dāng)于一個(gè)線程管理器,而非一個(gè)線程。因?yàn)槟憧梢栽O(shè)置這個(gè)線程管理器內(nèi)可以并行運(yùn)行的的線程數(shù)量等等
55oc語(yǔ)法里的@perpoerty不用寫@synzhesize了,自動(dòng)填充了。并且的_name;
寫方法時(shí)候不用提前聲明。llvm 全局方法便利。
枚舉類型。enum hello:Integer{ } 冒號(hào)后面直接可以跟類型,以前是:
enum hello{} 后面在指定為Integer .
橋接。ARC 自動(dòng)release retain 的時(shí)候 CFString CFArray . Core Fountion. 加上橋接_brige 才能區(qū)分CFString 和NSString 而現(xiàn)在自動(dòng)區(qū)分了,叫固定橋接。
下拉刷新封裝好了。
UICollectionViewController. 可以把表格分成多列。
Social Framework(社交集成)
UIActivityViewController來(lái)詢問(wèn)用戶的社交行為
緩存:就是存放在臨時(shí)文件里,比如新浪微博請(qǐng)求的數(shù)據(jù),和圖片,下次請(qǐng)求看這里有沒(méi)有值。
56Singleton(單例模式),也叫單子模式,是一種常用的軟件設(shè)計(jì)模式。在應(yīng)用這個(gè)模式時(shí),單例對(duì)象的類必須保證只有一個(gè)實(shí)例存在。
代碼如下:
static ClassA *classA = nil;//靜態(tài)的該類的實(shí)例
+ (ClassA *)sharedManager
{
@synchronized(self) {
if (!classA) {
classA = [[super allocWithZone:NULL]init];
}
return classA;
}
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedManager] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (NSUIntger)retainCount {
return NSUIntgerMax;
}
- (oneway void)release {
}
- (id)autorelease {
return self;
}
-(void)dealloc{
}
57請(qǐng)寫一個(gè)C函數(shù),若處理器是Big_endian的,則返回0;若是Little_endian的,則返回1 int checkCPU( ) {
{
union w
{
int a;
char b;
} c;
c.a = 1;
return (c.b ==1);
}
}
剖析:嵌入式系統(tǒng)開發(fā)者應(yīng)該對(duì)Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU對(duì)操作數(shù)的存放方式是從低字節(jié)到高字節(jié), Big-endian 模式的CPU對(duì)操作數(shù)的存放方式是從高字節(jié)到低字節(jié)。在弄清楚這個(gè)之前要弄清楚這個(gè)問(wèn)題:字節(jié)從右到坐為從高到低! 假設(shè)從地址0x4000開始存放: 0x12345678,是也個(gè)32位四個(gè)字節(jié)的數(shù)據(jù),最高字節(jié)是0x12,最低字節(jié)是0x78:在Little-endian模式CPU內(nèi)存中的存放方式為: (高字節(jié)在高地址,低字節(jié)在低地址)
內(nèi)存地址0x4000 0x4001 0x4002 0x4003
存放內(nèi)容 0x78 0x56 0x34 0x12
大端機(jī)則相反。
有的處理器系統(tǒng)采用了小端方式進(jìn)行數(shù)據(jù)存放,如Intel的奔騰。有的處理器系統(tǒng)采用了大端方式進(jìn)行數(shù)據(jù)存放,如IBM半導(dǎo)體和Freescale的PowerPC處理器。不僅對(duì)于處理器,一些外設(shè)的設(shè)計(jì)中也存在著使用大端或者小端進(jìn)行數(shù)據(jù)存放的選擇。因此在一個(gè)處理器系統(tǒng)中,有可能存在大端和小端模式同時(shí)存在的現(xiàn)象。這一現(xiàn)象為系統(tǒng)的軟硬件設(shè)計(jì)帶來(lái)了不小的麻煩,這要求系統(tǒng)設(shè)計(jì)工程師,必須深入理解大端和小端模式的差別。大端與小端模式的差別體現(xiàn)在一個(gè)處理器的寄存器,指令集,系統(tǒng)總線等各個(gè)層次中。 聯(lián)合體union的存放順序是所有成員都從低地址開始存放的。以上是網(wǎng)上的原文。讓我們看看在ARM處理器上union是如何存儲(chǔ)的呢? 地址A ---------------- |A |A+1 |A+2 |A+3 |int a; | | | | -------------------- |A |char b; | | --------- 如果是小端如何存儲(chǔ)c.a的呢?
地址A -----------
------------------- |A |A+1 |A+2 |A+3 | int a;
|0x01 |0x00 |0x00 |0x00 | ------------------------------------- |A |char b; | | ---------
如果是大端如何存儲(chǔ)c.a的呢?
地址A ---------------------
--------- |A |A+1 |A+2 |A+3 |int a; |0x00 |0x00 |0x00 |0x01 | ------------------------------------------ |A |char b; | | --------- 現(xiàn)在知道為什么c.b==0的話是大端,c.b==1的話就是小端了吧。
58
堆和棧上的指針
指針?biāo)赶虻倪@塊內(nèi)存是在哪里分配的,在堆上稱為堆上的指針,在棧上為棧上的指針.
在堆上的指針,可以保存在全局?jǐn)?shù)據(jù)結(jié)構(gòu)中,供不同函數(shù)使用訪問(wèn)同一塊內(nèi)存.
在棧上的指針,在函數(shù)退出后,該內(nèi)存即不可訪問(wèn).
59什么是指針的釋放?
具體來(lái)說(shuō)包括兩個(gè)概念.
1 釋放該指針指向的內(nèi)存,只有堆上的內(nèi)存才需要我們手工釋放,棧上不需要.
2 將該指針重定向?yàn)镹ULL.
60數(shù)據(jù)結(jié)構(gòu)中的指針?
其實(shí)就是指向一塊內(nèi)存的地址,通過(guò)指針傳遞,可實(shí)現(xiàn)復(fù)雜的內(nèi)存訪問(wèn).
7 函數(shù)指針?
指向一塊函數(shù)的入口地址.
8 指針作為函數(shù)的參數(shù)?
比如指向一個(gè)復(fù)雜數(shù)據(jù)結(jié)構(gòu)的指針作為函數(shù)變量
這種方法避免整個(gè)復(fù)雜數(shù)據(jù)類型內(nèi)存的壓棧出棧操作,提高效率.
注意:指針本身不可變,但指針指向的數(shù)據(jù)結(jié)構(gòu)可以改變.
9 指向指針的指針?
指針指向的變量是一個(gè)指針,即具體內(nèi)容為一個(gè)指針的值,是一個(gè)地址.
此時(shí)指針指向的變量長(zhǎng)度也是4位.
61指針與地址的區(qū)別?
區(qū)別:
1指針意味著已經(jīng)有一個(gè)指針變量存在,他的值是一個(gè)地址,指針變量本身也存放在一個(gè)長(zhǎng)度為四個(gè)字節(jié)的地址當(dāng)中,而地址概念本身并不代表有任何變量存在.
2 指針的值,如果沒(méi)有限制,通常是可以變化的,也可以指向另外一個(gè)地址.
地址表示內(nèi)存空間的一個(gè)位置點(diǎn),他是用來(lái)賦給指針的,地址本身是沒(méi)有大小概念,指針指向變量的大小,取決于地址后面存放的變量類型.
62指針與數(shù)組名的關(guān)系?
其值都是一個(gè)地址,但前者是可以移動(dòng)的,后者是不可變的.
12 怎樣防止指針的越界使用問(wèn)題?
必須讓指針指向一個(gè)有效的內(nèi)存地址,
1 防止數(shù)組越界
2 防止向一塊內(nèi)存中拷貝過(guò)多的內(nèi)容
3 防止使用空指針
4 防止改變const修改的指針
5 防止改變指向靜態(tài)存儲(chǔ)區(qū)的內(nèi)容
6 防止兩次釋放一個(gè)指針
7 防止使用野指針.
13 指針的類型轉(zhuǎn)換?
指針轉(zhuǎn)換通常是指針類型和void * 類型之前進(jìn)行強(qiáng)制轉(zhuǎn)換,從而與期望或返回void指針的函數(shù)進(jìn)行正確的交接.
63static有什么用途?(請(qǐng)至少說(shuō)明兩種) 1.限制變量的作用域 2.設(shè)置變量的存儲(chǔ)域 7. 引用與指針有什么區(qū)別? 1) 引用必須被初始化,指針不必。 2) 引用初始化以后不能被改變,指針可以改變所指的對(duì)象。 2) 不存在指向空值的引用,但是存在指向空值的指針。 8. 描述實(shí)時(shí)系統(tǒng)的基本特性 在特定時(shí)間內(nèi)完成特定的任務(wù),實(shí)時(shí)性與可靠性
64全局變量和局部變量在內(nèi)存中是否有區(qū)別?如果有,是什么區(qū)別? 全局變量?jī)?chǔ)存在靜態(tài)數(shù)據(jù)庫(kù),局部變量在堆棧 10. 什么是平衡二叉樹? 左右子樹都是平衡二叉樹且左右子樹的深度差值的絕對(duì)值不大于1
65堆棧溢出一般是由什么原因?qū)е碌模?nbsp; 沒(méi)有回收垃圾資源 12. 什么函數(shù)不能聲明為虛函數(shù)? constructor 13. 冒泡排序算法的時(shí)間復(fù)雜度是什么? O(n^2) 14. 寫出float x 與“零值”比較的if語(yǔ)句。 if(x>0.000001&&x<-0.000001) 16. Internet采用哪種網(wǎng)絡(luò)協(xié)議?該協(xié)議的主要層次結(jié)構(gòu)? tcp/ip 應(yīng)用層/傳輸層/網(wǎng)絡(luò)層/數(shù)據(jù)鏈路層/物理層 17. Internet物理地址和IP地址轉(zhuǎn)換采用什么協(xié)議? ARP (Address Resolution Protocol)(地址解析協(xié)議) 18.IP地址的編碼分為哪倆部分? IP地址由兩部分組成,網(wǎng)絡(luò)號(hào)和主機(jī)號(hào)。不過(guò)是要和“子網(wǎng)掩碼”按位與上之后才能區(qū) 分哪些是網(wǎng)絡(luò)位哪些是主機(jī)位。 2.用戶輸入M,N值,從1至N開始順序循環(huán)數(shù)數(shù),每數(shù)到M輸出該數(shù)值,直至全部輸出。寫 出C程序。 循環(huán)鏈表,用取余操作做 3.不能做switch()的參數(shù)類型是: switch的參數(shù)不能為實(shí)型。 華為 1、局部變量能否和全局變量重名? 答:能,局部會(huì)屏蔽全局。要用全局變量,需要使用"::" 局部變量可以與全局變量同名,在函數(shù)內(nèi)引用這個(gè)變量時(shí),會(huì)用到同名的局部變量,而 不會(huì)用到全局變量。對(duì)于有些編譯器而言,在同一個(gè)函數(shù)內(nèi)可以定義多個(gè)同名的局部變 量,比如在兩個(gè)循環(huán)體內(nèi)都定義一個(gè)同名的局部變量,而那個(gè)局部變量的作用域就在那 個(gè)循環(huán)體內(nèi) 2、如何引用一個(gè)已經(jīng)定義過(guò)的全局變量? 答:extern 可以用引用頭文件的方式,也可以用extern關(guān)鍵字,如果用引用頭文件方式來(lái)引用某個(gè) 在頭文件中聲明的全局變理,假定你將那個(gè)變寫錯(cuò)了,那么在編譯期間會(huì)報(bào)錯(cuò),如果你 用extern方式引用時(shí),假定你犯了同樣的錯(cuò)誤,那么在編譯期間不會(huì)報(bào)錯(cuò),而在連接期 間報(bào)錯(cuò) 3、全局變量可不可以定義在可被多個(gè).C文件包含的頭文件中?為什么? 答:可以,在不同的C文件中以static形式來(lái)聲明同名全局變量。 可以在不同的C文件中聲明同名的全局變量,前提是其中只能有一個(gè)C文件中對(duì)此變量賦 初值,此時(shí)連接不會(huì)出錯(cuò) 4、語(yǔ)句for( ;1 ;)有什么問(wèn)題?它是什么意思? 答:和while(1)相同。 5、do……while和while……do有什么區(qū)別? 答:前一個(gè)循環(huán)一遍再判斷,后一個(gè)判斷以后再循環(huán)
661.IP Phone的原理是什么? IPV6 2.TCP/IP通信建立的過(guò)程怎樣,端口有什么作用? 三次握手,確定是哪個(gè)應(yīng)用程序使用該協(xié)議 3.1號(hào)信令和7號(hào)信令有什么區(qū)別,我國(guó)某前廣泛使用的是那一種? 4.列舉5種以上的電話新業(yè)務(wù)? 微軟亞洲技術(shù)中心的面試題?。。?nbsp; 1.進(jìn)程和線程的差別。 線程是指進(jìn)程內(nèi)的一個(gè)執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實(shí)體. 與進(jìn)程的區(qū)別: (1)調(diào)度:線程作為調(diào)度和分配的基本單位,進(jìn)程作為擁有資源的基本單位 (2)并發(fā)性:不僅進(jìn)程之間可以并發(fā)執(zhí)行,同一個(gè)進(jìn)程的多個(gè)線程之間也可并發(fā)執(zhí)行 (3)擁有資源:進(jìn)程是擁有資源的一個(gè)獨(dú)立單位,線程不擁有系統(tǒng)資源,但可以訪問(wèn)隸屬 于進(jìn)程的資源. (4)系統(tǒng)開銷:在創(chuàng)建或撤消進(jìn)程時(shí),由于系統(tǒng)都要為之分配和回收資源,導(dǎo)致系統(tǒng)的開 銷明顯大于創(chuàng)建或撤消線程時(shí)的開銷。 2.測(cè)試方法 人工測(cè)試:個(gè)人復(fù)查、抽查和會(huì)審 機(jī)器測(cè)試:黑盒測(cè)試和白盒測(cè)試 2.Heap與stack的差別。 Heap是堆,stack是棧。 Stack的空間由操作系統(tǒng)自動(dòng)分配/釋放,Heap上的空間手動(dòng)分配/釋放。 Stack空間有限,Heap是很大的自由存儲(chǔ)區(qū) C中的malloc函數(shù)分配的內(nèi)存空間即在堆上,C++中對(duì)應(yīng)的是new操作符。 程序在編譯期對(duì)變量和函數(shù)分配內(nèi)存都在棧上進(jìn)行,且程序運(yùn)行過(guò)程中函數(shù)調(diào)用時(shí)參數(shù)的 傳遞也在棧上進(jìn)行 3.Windows下的內(nèi)存是如何管理的? 4.介紹.Net和.Net的安全性。 5.客戶端如何訪問(wèn).Net組件實(shí)現(xiàn)Web Service? 6.C/C++編譯器中虛表是如何完成的? 7.談?wù)凜OM的線程模型。然后討論進(jìn)程內(nèi)/外組件的差別。 8.談?wù)処A32下的分頁(yè)機(jī)制 小頁(yè)(4K)兩級(jí)分頁(yè)模式,大頁(yè)(4M)一級(jí) 9.給兩個(gè)變量,如何找出一個(gè)帶環(huán)單鏈表中是什么地方出現(xiàn)環(huán)的? 一個(gè)遞增一,一個(gè)遞增二,他們指向同一個(gè)接點(diǎn)時(shí)就是環(huán)出現(xiàn)的地方 10.在IA32中一共有多少種辦法從用戶態(tài)跳到內(nèi)核態(tài)? 通過(guò)調(diào)用門,從ring3到ring0,中斷從ring3到ring0,進(jìn)入vm86等等 11.如果只想讓程序有一個(gè)實(shí)例運(yùn)行,不能運(yùn)行兩個(gè)。像winamp一樣,只能開一個(gè)窗 口,怎樣實(shí)現(xiàn)? 用內(nèi)存映射或全局原子(互斥變量)、查找窗口句柄.. FindWindow,互斥,寫標(biāo)志到文件或注冊(cè)表,共享內(nèi)存。
67如何截取鍵盤的響應(yīng),讓所有的‘a(chǎn)’變成‘b’? 鍵盤鉤子SetWindowsHookEx 13.Apartment在COM中有什么用?為什么要引入? 14.存儲(chǔ)過(guò)程是什么?有什么用?有什么優(yōu)點(diǎn)? 我的理解就是一堆sql的集合,可以建立非常復(fù)雜的查詢,編譯運(yùn)行,所以運(yùn)行一次后, 以后再運(yùn)行速度比單獨(dú)執(zhí)行SQL快很多 15.Template有什么特點(diǎn)?什么時(shí)候用? 16.談?wù)刉indows DNA結(jié)構(gòu)的特點(diǎn)和優(yōu)點(diǎn)。 網(wǎng)絡(luò)編程中設(shè)計(jì)并發(fā)服務(wù)器,使用多進(jìn)程與多線程,請(qǐng)問(wèn)有什么區(qū)別? 1,進(jìn)程:子進(jìn)程是父進(jìn)程的復(fù)制品。子進(jìn)程獲得父進(jìn)程數(shù)據(jù)空間、堆和棧的復(fù)制品。 2,線程:相對(duì)與進(jìn)程而言,線程是一個(gè)更加接近與執(zhí)行體的概念,它可以與同進(jìn)程的其 他線程共享數(shù)據(jù),但擁有自己的棧空間,擁有獨(dú)立的執(zhí)行序列。 兩者都可以提高程序的并發(fā)度,提高程序運(yùn)行效率和響應(yīng)時(shí)間。 線程和進(jìn)程在使用上各有優(yōu)缺點(diǎn):線程執(zhí)行開銷小,但不利于資源管理和保護(hù);而進(jìn)程 正相反。同時(shí),線程適合于在SMP機(jī)器上運(yùn)行,而進(jìn)程則可以跨機(jī)器遷移。 思科
682.找錯(cuò)題 試題1:void test1(){ char string[10]; char* str1 = "0123456789"; strcpy( string, str1 );} 試題2:void test2(){ char string[10], str1[10]; int i; for(i=0; i<10; i++) { str1 = 'a'; } strcpy( string, str1 );} 試題3:void test3(char* str1){ char string[10]; if( strlen( str1 ) <= 10 ) { strcpy( string, str1 ); }} 解答: 試題1字符串str1需要11個(gè)字節(jié)才能存放下(包括末尾的’/0’),而string只有10個(gè)字節(jié)的空間,strcpy會(huì)導(dǎo)致數(shù)組越界; 對(duì)試題2,如果面試者指出字符數(shù)組str1不能在數(shù)組內(nèi)結(jié)束可以給3分;如果面試者指出strcpy(string, str1)調(diào)用使得從str1[url=]內(nèi)存[/url]起復(fù)制到string內(nèi)存起所復(fù)制的字節(jié)數(shù)具有不確定性可以給7分,在此基礎(chǔ)上指出庫(kù)函數(shù)strcpy工作方式的給10分; 對(duì)試題3,if(strlen(str1) <= 10)應(yīng)改為if(strlen(str1) < 10),因?yàn)閟trlen的結(jié)果未統(tǒng)計(jì)’/0’所占用的1個(gè)字節(jié)?! ∑饰觯骸 】疾閷?duì)基本功的掌握: (1)字符串以’/0’結(jié)尾; (2)對(duì)數(shù)組越界把握的敏感度; (3)庫(kù)函數(shù)strcpy的工作方式,如果編寫一個(gè)標(biāo)準(zhǔn)strcpy函數(shù)的總分值為10,下面給出幾個(gè)不同得分的答案: 2分void strcpy( char *strDest, char *strSrc ){ while( (*strDest++ = * strSrc++) != ‘/0’ );} 4分void strcpy( char *strDest, const char *strSrc ) //將源字符串加const,表明其為輸入?yún)?shù),加2分{ while( (*strDest++ = * strSrc++) != ‘/0’ );} 7分void strcpy(char *strDest, const char *strSrc) { //對(duì)源地址和目的地址加非0斷言,加3分 assert( (strDest != NULL) && (strSrc != NULL) ); while( (*strDest++ = * strSrc++) != ‘/0’ );} 10分//為了實(shí)現(xiàn)鏈?zhǔn)讲僮?,將目的地址返回,?分!char * strcpy( char *strDest, const char *strSrc ) { assert( (strDest != NULL) && (strSrc != NULL) ); char *address = strDest; while( (*strDest++ = * strSrc++) != ‘/0’ ); return address;} 從2分到10分的幾個(gè)答案我們可以清楚的看到,小小的strcpy竟然暗藏著這么多玄機(jī),真不是蓋的!需要多么扎實(shí)的基本功才能寫一個(gè)完美的strcpy啊! (4)對(duì)strlen的掌握,它沒(méi)有包括字符串末尾的'/0'。 讀者看了不同分值的strcpy版本,應(yīng)該也可以寫出一個(gè)10分的strlen函數(shù)了,完美的版本為: int strlen( const char *str ) //輸入?yún)?shù)const{ assert( strt != NULL ); //斷言字符串地址非0 int len; while( (*str++) != '/0' ) { len++; } return len;} 試題4:void GetMemory( char *p ){ p = (char *) malloc( 100 );}void Test( void ) { char *str = NULL; GetMemory( str ); strcpy( str, "hello world" ); printf( str );} 試題5:char *GetMemory( void ){ char p[] = "hello world"; return p; }void Test( void ){ char *str = NULL; str = GetMemory(); printf( str ); } 試題6:void GetMemory( char **p, int num ){ *p = (char *) malloc( num );}void Test( void ){ char *str = NULL; GetMemory( &str, 100 ); strcpy( str, "hello" ); printf( str ); } 試題7:void Test( void ){ char *str = (char *) malloc( 100 ); strcpy( str, "hello" ); free( str ); ... //省略的其它語(yǔ)句} 解答: 試題4傳入中GetMemory( char *p )函數(shù)的形參為字符串指針,在函數(shù)內(nèi)部修改形參并不能真正的改變傳入形參的值,執(zhí)行完char *str = NULL;GetMemory( str ); 后的str仍然為NULL; 試題5中char p[] = "hello world"; return p; 的p[]數(shù)組為函數(shù)內(nèi)的局部自動(dòng)變量,在函數(shù)返回后,內(nèi)存已經(jīng)被釋放。這是許多程序員常犯的錯(cuò)誤,其根源在于不理解變量的生存期。 試題6的GetMemory避免了試題4的問(wèn)題,傳入GetMemory的參數(shù)為字符串指針的指針,但是在GetMemory中執(zhí)行申請(qǐng)內(nèi)存及賦值語(yǔ)句*p = (char *) malloc( num ); 后未判斷內(nèi)存是否申請(qǐng)成功,應(yīng)加上:if ( *p == NULL ){ ...//進(jìn)行申請(qǐng)內(nèi)存失敗處理} 試題7存在與試題6同樣的問(wèn)題,在執(zhí)行char *str = (char *) malloc(100); 后未進(jìn)行內(nèi)存是否申請(qǐng)成功的判斷;另外,在free(str)后未置str為空,導(dǎo)致可能變成一個(gè)“野”指針,應(yīng)加上:str = NULL; 試題6的Test函數(shù)中也未對(duì)malloc的內(nèi)存進(jìn)行釋放?! ∑饰觯骸 ≡囶}4~7考查面試者對(duì)內(nèi)存操作的理解程度,基本功扎實(shí)的面試者一般都能正確的回答其中50~60的錯(cuò)誤。但是要完全解答正確,卻也絕非易事?! ?duì)內(nèi)存操作的考查主要集中在: ?。?)指針的理解; ?。?)變量的生存期及作用范圍; (3)良好的動(dòng)態(tài)內(nèi)存申請(qǐng)和釋放習(xí)慣?! ≡倏纯聪旅娴囊欢纬绦蛴惺裁村e(cuò)誤:swap( int* p1,int* p2 ){ int *p; *p = *p1; *p1 = *p2; *p2 = *p;} 在swap函數(shù)中,p是一個(gè)“野”指針,有可能指向系統(tǒng)區(qū),導(dǎo)致程序運(yùn)行的崩潰。在VC++中DEBUG運(yùn)行時(shí)提示錯(cuò)誤“access Violation”。該程序應(yīng)該改為:swap( int* p1,int* p2 ){ int p; p = *p1; *p1 = *p2; *p2 = p;}[img=12,12]file:///D:/魚魚軟件/魚魚多媒體日記本/temp/{56068A28-3D3B-4D8B-9F82-AC1C3E9B128C}_arc_d[1].gif[/img] 3.內(nèi)功題 試題1:分別給出BOOL,int,float,指針變量 與“零值”比較的 if 語(yǔ)句(假設(shè)變量名為var) 解答: BOOL型變量:if(!var) int型變量: if(var==0) float型變量: const float EPSINON = 0.00001; if ((x >= - EPSINON) && (x <= EPSINON) 指針變量: if(var==NULL) 剖析: 考查對(duì)0值判斷的“內(nèi)功”,BOOL型變量的0判斷完全可以寫成if(var==0),而int型變量也可以寫成if(!var),指針變量的判斷也可以寫成if(!var),上述寫法雖然程序都能正確運(yùn)行,但是未能清晰地表達(dá)程序的意思。 一般的,如果想讓if判斷一個(gè)變量的“真”、“假”,應(yīng)直接使用if(var)、if(!var),表明其為“邏輯”判斷;如果用if判斷一個(gè)數(shù)值型變量(short、int、long等),應(yīng)該用if(var==0),表明是與0進(jìn)行“數(shù)值”上的比較;而判斷指針則適宜用if(var==NULL),這是一種很好的編程習(xí)慣。 浮點(diǎn)型變量并不精確,所以不可將float變量用“==”或“!=”與數(shù)字比較,應(yīng)該設(shè)法轉(zhuǎn)化成“>=”或“<=”形式。如果寫成if (x == 0.0),則判為錯(cuò),得0分。 試題2:以下為Windows NT下的32位C++程序,請(qǐng)計(jì)算sizeof的值void Func ( char str[100] ){ sizeof( str ) = ?}void *p = malloc( 100 );sizeof ( p ) = ? 解答:sizeof( str ) = 4sizeof ( p ) = 4 剖析: Func ( char str[100] )函數(shù)中數(shù)組名作為函數(shù)形參時(shí),在函數(shù)體內(nèi),數(shù)組名失去了本身的內(nèi)涵,僅僅只是一個(gè)指針;在失去其內(nèi)涵的同時(shí),它還失去了其常量特性,可以作自增、自減等操作,可以被修改。 數(shù)組名的本質(zhì)如下: (1)數(shù)組名指代一種數(shù)據(jù)結(jié)構(gòu),這種數(shù)據(jù)結(jié)構(gòu)就是數(shù)組; 例如:char str[10];cout << sizeof(str) << endl; 輸出結(jié)果為10,str指代數(shù)據(jù)結(jié)構(gòu)char[10]?! 。?)數(shù)組名可以轉(zhuǎn)換為指向其指代實(shí)體的指針,而且是一個(gè)指針常量,不能作自增、自減等操作,不能被修改;char str[10]; str++; //編譯出錯(cuò),提示str不是左值 ?。?)數(shù)組名作為函數(shù)形參時(shí),淪為普通指針?! indows NT 32位平臺(tái)下,指針的長(zhǎng)度(占用內(nèi)存的大小)為4字節(jié),故sizeof( str ) 、sizeof ( p ) 都為4?! ≡囶}3:寫一個(gè)“標(biāo)準(zhǔn)”宏MIN,這個(gè)宏輸入兩個(gè)參數(shù)并返回較小的一個(gè)。另外,當(dāng)你寫下面的代碼時(shí)會(huì)發(fā)生什么事?least = MIN(*p++, b); 解答:#define MIN(A,B) ((A) <= (B) ? (A) : (B)) MIN(*p++, b)會(huì)產(chǎn)生宏的副作用 剖析: 這個(gè)面試題主要考查面試者對(duì)宏定義的使用,宏定義可以實(shí)現(xiàn)類似于函數(shù)的功能,但是它終歸不是函數(shù),而宏定義中括弧中的“參數(shù)”也不是真的參數(shù),在宏展開的時(shí)候?qū)Α皡?shù)”進(jìn)行的是一對(duì)一的替換?! 〕绦騿T對(duì)宏定義的使用要非常小心,特別要注意兩個(gè)問(wèn)題: (1)謹(jǐn)慎地將宏定義中的“參數(shù)”和整個(gè)宏用用括弧括起來(lái)。所以,嚴(yán)格地講,下述解答:#define MIN(A,B) (A) <= (B) ? (A) : (B)#define MIN(A,B) (A <= B ? A : B ) 都應(yīng)判0分; ?。?)防止宏的副作用?! 『甓x#define MIN(A,B) ((A) <= (B) ? (A) : (B))對(duì)MIN(*p++, b)的作用結(jié)果是:((*p++) <= (b) ? (*p++) : (*p++)) 這個(gè)表達(dá)式會(huì)產(chǎn)生副作用,指針p會(huì)作三次++自增操作。 除此之外,另一個(gè)應(yīng)該判0分的解答是:#define MIN(A,B) ((A) <= (B) ? (A) : (B)); 這個(gè)解答在宏定義的后面加“;”,顯示編寫者對(duì)宏的概念模糊不清,只能被無(wú)情地判0分并被面試官淘汰?! ≡囶}4:為什么標(biāo)準(zhǔn)頭文件都有類似以下的結(jié)構(gòu)? #ifndef __INCvxWorksh#define __INCvxWorksh #ifdef __cplusplusextern "C" {#endif /*...*/ #ifdef __cplusplus}#endif #endif /* __INCvxWorksh */ 解答: 頭文件中的編譯宏#ifndef __INCvxWorksh#define __INCvxWorksh#endif 的作用是防止被重復(fù)引用?! ∽鳛橐环N面向?qū)ο蟮恼Z(yǔ)言,C++支持函數(shù)重載,而過(guò)程式語(yǔ)言C則不支持。函數(shù)被C++編譯后在symbol庫(kù)中的名字與C語(yǔ)言的不同。例如,假設(shè)某個(gè)函數(shù)的原型為: void foo(int x, int y); 該函數(shù)被C編譯器編譯后在symbol庫(kù)中的名字為_foo,而C++編譯器則會(huì)產(chǎn)生像_foo_int_int之類的名字。_foo_int_int這樣的名字包含了函數(shù)名和函數(shù)參數(shù)數(shù)量及類型信息,C++就是考這種機(jī)制來(lái)實(shí)現(xiàn)函數(shù)重載的?! 榱藢?shí)現(xiàn)C和C++的混合編程,C++提供了C連接交換指定符號(hào)extern "C"來(lái)解決名字匹配問(wèn)題,函數(shù)聲明前加上extern "C"后,則編譯器就會(huì)按照C語(yǔ)言的方式將該函數(shù)編譯為_foo,這樣C語(yǔ)言中就可以調(diào)用C++的函數(shù)了。[img=12,12]file:///D:/魚魚軟件/魚魚多媒體日記本/temp/{C74A38C4-432E-4799-B54D-73E2CD3C5206}_arc_d[1].gif[/img] 試題5:編寫一個(gè)函數(shù),作用是把一個(gè)char組成的字符串循環(huán)右移n個(gè)。比如原來(lái)是“abcdefghi”如果n=2,移位后應(yīng)該是“hiabcdefgh” 函數(shù)頭是這樣的://pStr是指向以'/0'結(jié)尾的字符串的指針//steps是要求移動(dòng)的nvoid LoopMove ( char * pStr, int steps ){ //請(qǐng)?zhí)畛?..} 解答: 正確解答1:void LoopMove ( char *pStr, int steps ){ int n = strlen( pStr ) - steps; char tmp[MAX_LEN]; strcpy ( tmp, pStr + n ); strcpy ( tmp + steps, pStr); *( tmp + strlen ( pStr ) ) = '/0'; strcpy( pStr, tmp );} 正確解答2:void LoopMove ( char *pStr, int steps ){ int n = strlen( pStr ) - steps; char tmp[MAX_LEN]; memcpy( tmp, pStr + n, steps ); memcpy(pStr + steps, pStr, n ); memcpy(pStr, tmp, steps ); } 剖析: 這個(gè)試題主要考查面試者對(duì)標(biāo)準(zhǔn)庫(kù)函數(shù)的熟練程度,在需要的時(shí)候引用庫(kù)函數(shù)可以很大程度上簡(jiǎn)化程序編寫的工作量?! ∽铑l繁被使用的庫(kù)函數(shù)包括: ?。?) strcpy (2) memcpy ?。?) memset
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注