1.#import和#include的區(qū)別以及 @class 相關(guān)作用鹃操?
-
import和#include都能完整地包含某個(gè)文件的內(nèi)容疾掰,#import能防止同一個(gè)文件被包含多次
- @class僅僅是聲明一個(gè)類名,并不會(huì)包含類的完整聲明;@class告訴編譯器某個(gè)類的聲明,當(dāng)執(zhí)行時(shí),才去查看類的實(shí)現(xiàn)文件,可以解決頭文件的相互包含
-
import <> 用來(lái)包含系統(tǒng)自帶的文件邑飒,#import “”用來(lái)包含自定義的文件
- 詳細(xì)說(shuō)明
1.#import指令是Object-C針對(duì)#include的改進(jìn)版本,#import確保引用的文件只會(huì)被引用一次级乐,這樣你就不會(huì)陷入遞歸包含的問(wèn)題中
2.#import與@class二者的區(qū)別
在于:
- #import會(huì)鏈入該頭文件的全部信息疙咸,包括實(shí)體變量和方法等;而@class只是告訴編譯器风科,其后面聲明的名稱是類的名稱撒轮,至于這些類是如何定義的乞旦,暫時(shí)不用考慮。在頭文件中题山, 一般只需要知道被引用的類的名稱就可以了兰粉。 不需要知道其內(nèi)部的實(shí)體變量和方法,所以在頭文件中一般使用@class來(lái)聲明這個(gè)名稱是類的名稱顶瞳。 而在實(shí)現(xiàn)類里面玖姑,因?yàn)闀?huì)用到這個(gè)引用類的內(nèi)部的實(shí)體變量和方法,所以需要使用#import來(lái)包含這個(gè)被引用類的頭文件慨菱。
- 在編譯效率方面考慮焰络,如果你有100個(gè)頭文件都#import了同一個(gè)頭文件,或者這些文件是依次引用的抡柿,如A–>B, B–>C, C–>D這樣的引用關(guān)系舔琅。當(dāng)最開始的那個(gè)頭文件有變化的話,后面所有引用它的類都需要重新編譯洲劣,如果你的類有很多的話,這將耗費(fèi)大量的時(shí)間课蔬。而是用@class則不會(huì)囱稽。
- 如果有循環(huán)依賴關(guān)系,如:A–>B, B–>A這樣的相互依賴關(guān)系二跋,如果使用#import來(lái)相互包含战惊,那么就會(huì)出現(xiàn)編譯錯(cuò)誤,如果使用@class在兩個(gè)類的頭文件中相互聲明扎即,則不會(huì)有編譯錯(cuò)誤出現(xiàn)吞获。所以,一般來(lái)說(shuō)谚鄙,@class是放在interface中的各拷,只是為了在interface中引用這個(gè)類,把這個(gè)類作為一個(gè)類型來(lái)用的闷营。 在實(shí)現(xiàn)這個(gè)接口的實(shí)現(xiàn)類中烤黍,如果需要引用這個(gè)類的實(shí)體變量或者方法之類的,還是需要import在@class中聲明的類進(jìn)來(lái).
2.用NSLog函數(shù)輸出一個(gè)浮點(diǎn)類型傻盟,結(jié)果四舍五入速蕊,并保留一位小數(shù)
float num = 1.011;
NSLog(@"%.1f", num);
//使用%f來(lái)格式化,其中要保留一位小數(shù)娘赴,因此再用%.1f就是保留一位
3.property屬性的修飾符有什么樣的作用
property是屬性訪問(wèn)聲明规哲,擴(kuò)號(hào)內(nèi)支持以下幾個(gè)屬性:
- readonly:是只讀特性,只生成get方法的聲明和實(shí)現(xiàn),不會(huì)生成setter方法 ;不希望屬性在類外改變
- readwrite:是可讀可寫特性,同時(shí)生成get方法和set方法的聲明和實(shí)現(xiàn)
-
assign
:是賦值特性诽表,set方法的實(shí)現(xiàn)是直接賦值唉锌,用于基本數(shù)據(jù)類型
腥光,不進(jìn)行任何retain操作,為了解決原類型與環(huán)循引用問(wèn)題 -
retain
:表示持有特性,set方法的實(shí)現(xiàn)是release舊值糊秆,retain新值武福,傳入?yún)?shù)的retaincount會(huì)+1;用于OC對(duì)象類型
-
copy
:表示拷貝特性,set方法的實(shí)現(xiàn)是release舊值,copy新值痘番,用于NSString捉片、block
等類型,這是為了減少對(duì)上下文的依賴而引入的機(jī)制 - nonatomic 非原子操作汞舱,決定編譯器生成的setter getter是否是原子操作伍纫,atomic表示多線程安全,一般使用nonatomic
- getter=getName昂芜、setter=setName:設(shè)置setter與getter的方法名
補(bǔ)充:
- retain 和copy用戶對(duì)象,copy用于當(dāng) a指向一個(gè)對(duì)象,b也想指向同樣的對(duì)象的時(shí)候,如果用assign,a如果釋放,再 調(diào)用b會(huì)crash,如果用copy 的方式,a和b各自有自己的內(nèi)存,就可以解決這個(gè)問(wèn)題莹规。retain 會(huì)使計(jì)數(shù)器加1,也可以解 決assign的問(wèn)題。另外:atomic和nonatomic用來(lái)決定編譯器生成的getter和setter是否為原子操作泌神。 在多線程環(huán)境 下,原子操作是必要的,否則有可能引起錯(cuò)誤的結(jié)果良漱。
- strong:strong和retain相似,只要有一個(gè)strong指針指向?qū)ο螅搶?duì)象就不會(huì)被銷毀
- weak:聲明為weak的指針欢际,weak指針指向的對(duì)象一旦被釋放母市,weak的指針都將被賦值為nil;
- unsafeunretained:用unsafeunretained聲明的指針损趋,指針指向的對(duì)象一旦被釋放患久,這些指針將成為野指針。
4.寫一個(gè)setter方法用于完成@property (nonatomic,retain)NSString *name,寫一個(gè)setter方法用于完成@property(nonatomic浑槽,copy)NSString *name.
//@property (nonatomic, retain) NSString *name;
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];
_name = [name retain];
}
}
// @property(nonatomic, copy) NSString *name;
- (void)setName:(NSString *)name
{
if (_name != name) {
[_name release];
_name = [name copy];
}
}
5.對(duì)于語(yǔ)句NSString*obj = [[NSData alloc] init]; 蒋失,編譯時(shí)
和運(yùn)行時(shí)
obj分別是什么類型?
- 在編譯時(shí)桐玻,我們所聲明的obj是NSString *類型篙挽,因此是NSString類型對(duì)象。
- 在運(yùn)行時(shí)畸冲,由于指針obj所指向的是NSData類型對(duì)象的內(nèi)存嫉髓,因此實(shí)際上是NSData類型的對(duì)象。
- 說(shuō)明:
在編譯時(shí)邑闲,這一行代碼會(huì)轉(zhuǎn)換成類似這樣:
NSString *obj = ((id (*)(id, SEL))objc_msgSend)([NSData class], @selector(alloc));
obj = ((id (*)(id, SEL))objc_msgSend)((id)obj, @selector(init));
由于在編譯時(shí)算行,轉(zhuǎn)換成id,因此可以用NSString *指向NSData對(duì)象苫耸,而id是具備運(yùn)行時(shí)特性的州邢,因此在鏈接時(shí),通過(guò)id的isa指針可以找到其所屬的類,因此最終類型還是通過(guò)isa確定其所屬類型量淌。
6.常見的object-c的數(shù)據(jù)類型有那些骗村,和C的基本數(shù)據(jù)類型有什么區(qū)別?
- 常用OC類型:NSString呀枢、NSArray胚股、NSDictionary、NSData裙秋、NSNumber等
- OC對(duì)象需要手動(dòng)管理內(nèi)存琅拌,C的基本數(shù)據(jù)類型不需要管理內(nèi)存
6-1、OC中的數(shù)字對(duì)象都有哪些,簡(jiǎn)述它們與基本數(shù)據(jù)類型的區(qū)別是什么
- Objective-C中的數(shù)字對(duì)象NSNumber;
- Objective-C中的基本類型和C語(yǔ)言中的基本類型一樣.主要有:int,long,float,double,char,void,bool等.
- 對(duì)于基本類型變量,不需要用指針,也不用手動(dòng)回收,方法執(zhí)行結(jié)束會(huì)自動(dòng)回收.數(shù)字對(duì)象需要指針,也需要手動(dòng)回收內(nèi)存摘刑。
7. id聲明的對(duì)象有什么特性进宝?
id 聲明的對(duì)象具有運(yùn)行時(shí)
的特性,即可以指向任意類型的objcetive-c的對(duì)象枷恕;
/// Represents an instance of a class.
struct objc_object {
Class isa OBJC_ISA_AVAILABILITY;
};
/// A pointer to an instance of a class.
typedef struct objc_object *id;
id類型是一個(gè)指向objc_object結(jié)構(gòu)體類型的指針党晋,這個(gè)結(jié)構(gòu)體只有一個(gè)指向?qū)ο鬅o(wú)類的指針isa,因此id可以指向任何類型的對(duì)象徐块,故其具備運(yùn)行時(shí)特性
8.Objective-C如何對(duì)內(nèi)存管理的,說(shuō)說(shuō)你的看法和解決方法?
Objective-C的內(nèi)存管理主要有三種方式ARC(自動(dòng)內(nèi)存計(jì)數(shù))未玻、手動(dòng)內(nèi)存計(jì)數(shù)、內(nèi)存池蛹锰。
- 每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù)器深胳,每個(gè)新對(duì)象的計(jì)數(shù)器是1,當(dāng)對(duì)象的計(jì)數(shù)器減為0時(shí)铜犬,就會(huì)被銷毀
- 通過(guò)retain可以讓對(duì)象的計(jì)數(shù)器+1、release可以讓對(duì)象的計(jì)數(shù)器-1
- 還可以通過(guò)autorelease pool管理內(nèi)存
- 如果用ARC轻庆,編譯器會(huì)自動(dòng)生成管理內(nèi)存的代碼
9.內(nèi)存管理的幾條原則時(shí)什么癣猾?按照默認(rèn)法則.哪些方法生成的對(duì)象需要手動(dòng)釋放?在和property結(jié)合的時(shí)候怎樣有效的避免內(nèi)存泄露余爆?
- 黃金法則:
- 誰(shuí)創(chuàng)建纷宇,誰(shuí)release
? 如果你通過(guò)alloc、new或[mutable]copy來(lái)創(chuàng)建一個(gè)對(duì)象蛾方,那么你必須調(diào)用release或autorelease
? 換句話說(shuō)像捶,不是你創(chuàng)建的,就不用你去[auto]release
- 誰(shuí)創(chuàng)建纷宇,誰(shuí)release
- 誰(shuí)retain桩砰,誰(shuí)release
? 只要你調(diào)用了retain拓春,無(wú)論這個(gè)對(duì)象是如何生成的,你都要調(diào)用release - 總結(jié)
? 有始有終亚隅,有加就有減
? 曾經(jīng)讓對(duì)象的計(jì)數(shù)器+1硼莽,就必須在最后讓對(duì)象計(jì)數(shù)器-1- 只要調(diào)用了alloc、copy煮纵、new方法產(chǎn)生了一個(gè)新對(duì)象懂鸵,都必須在最后調(diào)用一次release或者autorelease
- 只要調(diào)用了retain偏螺,都必須在最后調(diào)用一次release或者autorelease
- @property如果用了copy或者retian,就需要對(duì)不再使用的屬性做一次release操作
- 如果用了ARC匆光,另外討論
10.看下面的程序,三次NSLog會(huì)輸出什么套像?為什么?
NSMutableArray* ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"test"]; // 1
[str retain]; // 2
[ary addObject:str]; // 3
NSLog(@"%d", [str retainCount]);
[str retain]; // 4
[str release]; // 3
[str release]; // 2
NSLog(@"%d", [str retainCount]);
[ary removeAllObjects]; // 1
NSLog(@"%d", [str retainCount]);
結(jié)果:3终息、2夺巩、1
11.OC中創(chuàng)建線程
的方法是什么?如何指定在主線程
中執(zhí)行代碼采幌?如何延時(shí)
執(zhí)行代碼劲够?
1. 創(chuàng)建線程的方法
? NSThread
? NSOperationQueue和NSOperation
? GCD
2. 主線程中執(zhí)行代碼
? [self performSelectorOnMainThread: withObject: waitUntilDone:];
? [self performSelector: onThread:[NSThread mainThread] withObject: waitUntilDone:];
? dispatch_async(dispatch_get_main_queue(), ^{
});
? [NSOperationQueue mainQueue]addOperationWithBlock:^{
}
3. 延時(shí)執(zhí)行
? double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
});
[self performSelector: withObject: afterDelay:];
[NSTimer scheduledTimerWithTimeInterval: target: selector: userInfo: repeats:];
12.Object-C有多繼承嗎?沒(méi)有的話用什么代替休傍?
- OC是單繼承征绎,沒(méi)有多繼承
- 有時(shí)可以用分類和協(xié)議來(lái)代替多繼承
注:多繼承即一個(gè)子類可以有多個(gè)父類,它繼承了多個(gè)父類的特 性。
Object-c的類沒(méi)有多繼承,只支持單繼承,如果要實(shí)現(xiàn)多繼承的話,可以通過(guò)類別和協(xié)議的方式來(lái)實(shí)現(xiàn),OC類似于多繼承,是在 用protocol委托代理來(lái)實(shí)現(xiàn)的;可以實(shí)現(xiàn)多個(gè)接口,通過(guò)實(shí)現(xiàn)多個(gè)接口可以完成C++的多重繼承;Category是類別,一 般情況用分類好,用Category去重寫類的方法,僅對(duì)本Category有效,不會(huì)影響到其他類與原有類的關(guān)系磨取。
13.Object-C有私有方法嗎人柿?私有變量呢?
- OC沒(méi)有類似@private的修飾詞來(lái)修飾方法忙厌,只要寫在.h文件中凫岖,就是公共方法
- 可以直接在.m文件中(比如類擴(kuò)展)聲明和實(shí)現(xiàn)方法,對(duì)編譯器來(lái)說(shuō)是私有的
- objective-c類里面的方法只有兩種, 靜態(tài)方法和實(shí)例方法.但是可以通過(guò)把方法的聲明和定義都放在.m文件中來(lái)實(shí)現(xiàn)一個(gè)表 面上的私有方法逢净。
- 有私有變量,可以通過(guò)@private來(lái)修飾,或者把聲明放到.m文件中哥放。在Objective‐C中,所有實(shí)例變 量默認(rèn)都是私有的,所有實(shí)例方法默認(rèn)都是公有的
14.關(guān)鍵字const
什么含義?
const int a;
int const a;
const int *a;
int const *a;
int * const a;
int const * const a;
- 前兩個(gè)的作用是一樣:a 是一個(gè)常整型數(shù)
- 第三爹土、四個(gè)意味著 a 是一個(gè)指向常整型數(shù)的指針(整型數(shù)是不可修改的甥雕,但指針可以)
- 第五個(gè)的意思:a 是一個(gè)指向整型數(shù)的常指針(指針指向的整型數(shù)是可以修改的,但指針是不可修改的)
- 最后一個(gè)意味著:a 是一個(gè)指向常整型數(shù)的常指針(指針指向的整型數(shù)是不可修改的胀茵,同時(shí)指針也是不可修改的)
Const只是一個(gè)修飾符
社露,不管怎么樣a仍然是一個(gè)int型的變量
本質(zhì):const在誰(shuí)后面誰(shuí)就不可修改,const在最前面則將其后移一位即可琼娘,二者等效
const關(guān)鍵字至少有下列n個(gè)作用
:
欲阻止一個(gè)變量被改變峭弟,可以使用const關(guān)鍵字。在定義該const變量時(shí)脱拼,通常需要對(duì)它進(jìn)行初始化瞒瘸,因?yàn)橐院缶蜎](méi)有機(jī)會(huì)再去改變它了;
對(duì)指針來(lái)說(shuō)挪拟,可以指定指針本身為const挨务,也可以指定指針?biāo)傅臄?shù)據(jù)為const,或二者同時(shí)指定為const;
在一個(gè)函數(shù)聲明中谎柄,const可以修飾形參丁侄,表明它是一個(gè)輸入?yún)?shù),在函數(shù)內(nèi)部不能改變其值朝巫;
對(duì)于類的成員函數(shù)鸿摇,若指定其為const類型,則表明其是一個(gè)常函數(shù)劈猿,不能修改類的成員變量拙吉;
對(duì)于類的成員函數(shù),有時(shí)候必須指定其返回值為const類型揪荣,以使得其返回值不為“左值”筷黔。
15.static的作用?
- static修飾的函數(shù)是一個(gè)內(nèi)部函數(shù)仗颈,只能在本文件中調(diào)用佛舱,其他文件不能調(diào)用
- static修飾的全部變量是一個(gè)內(nèi)部變量,只能在本文件中使用挨决,其他文件不能使用
- static修飾的局部變量只會(huì)初始化一次请祖,并且在程序退出時(shí)才會(huì)回收內(nèi)存
16.線程和進(jìn)程的區(qū)別?
- 一個(gè)應(yīng)用程序?qū)?yīng)一個(gè)進(jìn)程脖祈,一個(gè)進(jìn)程幫助程序占據(jù)一塊存儲(chǔ)空間
- 要想在進(jìn)程中執(zhí)行任務(wù)肆捕,就必須開啟線程,一條線程就代表一個(gè)任務(wù)
- 一個(gè)進(jìn)程中允許開啟多條線程盖高,也就是同時(shí)執(zhí)行多個(gè)任務(wù)
補(bǔ)充:
- 線程是進(jìn)程的基本單位
- 進(jìn)程和線程都是由操作系統(tǒng)所體會(huì)的程序運(yùn)行的基本單元,系統(tǒng)利用該基本單元實(shí)現(xiàn)系統(tǒng)對(duì)應(yīng)用的并發(fā)性慎陵。
- 進(jìn)程和線程的主要差別在于它們是不同的操作系統(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)程。