1.不用中間變量,用兩種方法交換A和B的值
A = A+B;
B = A - B;
A = A - B;
2.常見的object-c的數(shù)據(jù)類型有哪些,和C的基本數(shù)據(jù)類型有什么區(qū)別?如:NSInteger和int
答:object的數(shù)據(jù)類型由NSString,NSNumber,NSArray,NSMutableArray,NSData等等,這些都是class,創(chuàng)建后便是對象,而C語言的基本數(shù)據(jù)類型int,只是一定字節(jié)的內(nèi)存空間,用于存放數(shù)值,NSInteger是基本的數(shù)據(jù)類型,并不是NSNumber的子類,當然也不是NSObject的子類。NSInteger是基本數(shù)據(jù)類型int或者Long的別名(NSInteger的定義typedef long NSInteger)它的區(qū)別在于,NSInteger會根據(jù)系統(tǒng)是32位還是64位來決定是本身int還是long.
3.iOS里面的二進制數(shù)據(jù)類型是什么?和NSString如何互相轉(zhuǎn)換?
NSData:用于存儲二進制的數(shù)據(jù)類型
NSData類提供了一種簡單的方式,它用來設(shè)置緩沖區(qū)、將文件的內(nèi)容讀入緩沖區(qū),或?qū)⒕彌_區(qū)的內(nèi)容寫到一個文件。
不變緩沖區(qū)(NSData類),也可定義可變的緩沖區(qū)(NSMutableData類)。
NSData、NSString互轉(zhuǎn):
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
//NSString轉(zhuǎn)換成NSData類型
NSString * newStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
- id聲明的對象有什么特性?
Id 聲明的對象具有運行時的特性。
Id類型可以用來存儲屬于任何類的對象,存儲在id變量中的對象類型在編譯時無法確定,所以一些測試推遲到運行時進行。
6.常見的object-c的數(shù)據(jù)類型有那些,和C的基本數(shù)據(jù)類型有什么區(qū)別?如:NSInteger和int
答:
object-c的數(shù)據(jù)類型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,這些都是類,創(chuàng)建后便是對象,包含父類及自身的方法,可完成復雜的操作。
而C語言的基本數(shù)據(jù)類型int,只是一定字節(jié)的內(nèi)存空間,用于存放數(shù)值。
5.對于語句NSString *obj = [[NSData alloc] init]; obj在編譯時和運行時分別時什么類型的對象?
答:
編譯時是NSString的類型;運行時是NSData類型的對象。
4.寫一個setter方法用于完成
@property (nonatomic,retain)NSString *name,
寫一個setter方法用于完成
@property(nonatomic,copy)NSString *name
答:
//retain
-(void) setName:(NSString *) str
{
[str retain];
[name release];
name = str;
}
// copy
-(void)setName:(NSString *)str {
id t = [str copy];
[name release];
name = t;
}
1、@property中有哪些屬性關(guān)鍵字?
1、寫出四個@property關(guān)鍵字及其解釋,說明為什么NSString最好用Copy來修飾?
做了三件事:
1.生成私有屬性
2.生成setter getter的聲明
3.生成setter getter的實現(xiàn)
生成的 setter 實現(xiàn): 都是直接賦值.
@property(參數(shù)1,參數(shù)2,參數(shù)3...)數(shù)據(jù)類型 變量名;
參數(shù)的作用
1.與多線程相關(guān):
atomic:原子操作:加鎖:安全,效率低,默認
nonatomic:非原子操作:不加鎖: 安全性低,效率高:建議
2.與setter相關(guān)
assign:直接賦值
retain(MRC):與OC對象的管理相關(guān):按照OC對象的setter方法規(guī)范去寫:
3.與讀寫相關(guān)
readonly:只讀:只有g(shù)etter,沒有setter
readwrite:getter setter都有
4.修改生成的 getter setter 方法的名稱:getter = isGoodMan
5.還有另外一種參數(shù),和強弱指針相關(guān):strong,weak
1.@property關(guān)鍵字
a.使用位置: 類的聲明的大括號的外面。
b.使用語法: @property 和屬性相同的類型類型 屬性去掉下劃線 ;
c.作 用: 就會幫我們自動的生成 屬性對應(yīng)的 setter和getter的聲明。@property NSString * name;
就相當于:
-(void)setName:(NSString *)name;
-(NSString *)name;注意:
a.@property命名有規(guī)范:
中間的那個數(shù)據(jù)類型要和屬性的類型一致。
@property的名稱,是屬性去掉下劃線的名稱。
b.也是可以使用點語法的。
c.@property僅僅是幫我們自動的生成了setter和getter的聲明,實現(xiàn)還要我們自己去寫。
1.前面講的那些@property 和@synthesize 是xcode 4.4之前的語法
2.xcode4.4之后,蘋果給@property做了增強。
你只需要寫一個@property,就會自動的幫我們生成了getter和setter的聲明 以及 實現(xiàn)。
@property NSString *name;
實際上就在類的聲明中:
-(void)setName:(NSString *)name;
-(NSString *)name;
以及在類的實現(xiàn)中有:
-(void)setName:(NSString *)name
{
self->_name = name;
}
-(NSString *)name
{
return self->_name;
}
3.如果你只寫一個@property NSString *name;
那么他除了幫你生成setter和getter方法的聲明以及實現(xiàn)之外,還自動的幫你聲明一個屬性(類型和@property類型一致,名字是@property的名字加上下劃線。)
注意:
a.如果僅僅寫一個@property,自動的幫你生成一個同名帶下劃線的 真 私有屬性。 如果你的屬性不想要是真私有的,想讓外界訪問或者想讓子類訪問,那么就不要讓@property自動生成,而是你自己去聲明。
b.@property命名一定要注意,前面沒有下劃線。
- 屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那種情況下用?
readwrite 是可讀可寫特性,會生成getter方法和setter方法
readonly 是只讀特性 ,只會生成getter方法 不會生成setter方法 ;不希望屬性在類外發(fā)生改變時使用
assign 是賦值特性,setter方法將傳入?yún)?shù)賦值給實例變量;僅設(shè)置變量時調(diào)用;
retain 表示持有特性,setter方法將傳入?yún)?shù)先保留,再賦值,傳入?yún)?shù)的retaincount會+1;
copy 表示賦值特性,setter方法將傳入對象復制一份;需要完全一份新的變量時調(diào)用。
nonatomic 非原子操作,決定編譯器生成的setter getter是否是原子操作,
atomic表示多線程安全,一般使用nonatomic
2.#import 跟#include 有什么區(qū)別,@class呢, #import<> 跟 #import”"又什么區(qū)別?
答:#import是Objective-C導入頭文件的關(guān)鍵字,#include是C/C++導入頭文件的關(guān)鍵字;
使用#import頭文件會自動只導入一次,不會重復導入,相當于#include和#pragma once;
@class告訴編譯器某個類的聲明,當執(zhí)行時,才去查看類的實現(xiàn)文件,可以解決頭文件的相互包含;
“#import<>”用來包含系統(tǒng)的頭文件,
"#import””"用來包含用戶頭文件。
- Object-c的類可以多重繼承么?可以實現(xiàn)多個接口么?Category是什么?重寫一個類的方式用繼承好還是分類好?為什么?
Object-c的類不可以多重繼承,可通過偽繼承進行消息轉(zhuǎn)發(fā)實現(xiàn),或者通過@protocol委托方式實現(xiàn);
可以實現(xiàn)多個接口,通過實現(xiàn)多個接口可以完成C++的多重繼承;
Category是類別,是對現(xiàn)有類添加新的方法,對現(xiàn)有類進行擴展;
一般情況用分類好,用Category去重寫類的方法,僅對包含本Category的類有效,不會影響到其他類與原有類的關(guān)系。
1、這段代碼又什么問題,如何修改?
for (int i = 0; i < someLargeNumber; ++i) {
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@",string);
}
1、這段代碼有什么問題,如何修改?
for (int i = 0; i < 1000000; i++) {
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@“string = %@",string);
}
答:
打印結(jié)果:string = abcxyz會出現(xiàn)內(nèi)存泄露
問題處在每執(zhí)行一次循環(huán),就會有一個string加到當前nsrunloop中的自動釋放池中,只有當自動釋放池被release的時候,自動釋放池中的標示了autorelease的這些數(shù)據(jù)所占用的內(nèi)存空間才能被釋放掉。假設(shè),當someLargeNumber大到一定程度時,內(nèi)存空間將被耗盡而沒有被釋放掉,所以就出現(xiàn)了內(nèi)存溢出的現(xiàn)象。目前的解決方法就是在循環(huán)里面加個自動釋放池
for (int i =0; i < someLargeNumber; i++) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *string =@"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@"%@", string);
[pool release];
}
延伸:堆棧的區(qū)別:
(1)管理方式:
對于棧來講,是由編譯器自動管理,無需我們手工控制;
對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。
(2)申請大小:
能從棧獲得的空間較小,堆是向高地址擴展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。堆的大小受限于計算機系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。
(3)碎片問題:
對于堆來講,頻繁的new/delete,勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一一對應(yīng),以至于永遠都不可能有一個內(nèi)存塊從棧中間彈出。
(4)分配方式:
堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。
棧有2種分配方式:靜態(tài)分配和動態(tài)分配。
靜態(tài)分配是編譯器完成的,比如局部變量的分配。
動態(tài)分配由alloca函數(shù)進行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進行釋放,無需我們手工實現(xiàn)。
(5)分配效率:
棧是機器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。堆則是C/C++函數(shù)庫提供的,它的機制是很復雜的。由此可見,頻繁的開辟內(nèi)存空間,并釋放內(nèi)存那必然會導致內(nèi)存泄漏。
在oc中,我們提到過NSAutoreleasePool這個東西,在NSAutoreleasePool中的元素實際上都被默認的變成了autoRelease,更好的讓內(nèi)存得到釋放。
2、為什么NSString最好用Copy來修飾
1.當copy修飾的屬性賦值時的對象是一個不可變對象的時候,不會發(fā)生內(nèi)存的拷貝行為,發(fā)生的僅僅是指針的強引用。
2.當copy修飾的屬性賦值的對象是一個可變對象的時候才會發(fā)生內(nèi)存的拷貝。
3.即使copy修飾的屬性是一個可變對象,發(fā)生了內(nèi)存拷貝,但是其實拷貝出來的對象依然是不可變的,這一點要尤其注意。
2、用@property聲明的NSString(或者NSArray,NSDictionary)經(jīng)常使用copy關(guān)鍵字,為什么?如果改用strong關(guān)鍵字,可能造成什么問題?
答:
1、因為父類指針可以指向子類對象,使用copy的目的是為了讓本對象的屬性不受外界影響,使用copy無論給我傳入是一個可變對象還是不可對象,我本身持有的就是一個不可變的副本.
2、如果我們使用是strong,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性.首先,理解一下copy的特性,copy是先release舊值,然后對之前的內(nèi)容copy一份,創(chuàng)建一份新的內(nèi)存空間,然后把指針指向新的內(nèi)存空間。
當用@property聲明NSString、NSArray、NSDictionary經(jīng)常使用copy關(guān)鍵字,經(jīng)常用此特質(zhì)來保護其封裝性,因為傳遞給設(shè)置方法的新值有可能指向NSMutableString、NSMutableArray或者NSMutableDictionary類的實例,是因為他們是NSString、NSArray、NSDictionary的子類,意思就是說能做增刪改查的功能,此時若是不用copy修飾,那么設(shè)置完之后,NSString、NSArray、NSDictionary的值就可能會在對象不知情的情況下遭人更改。所以,這時就要拷貝一份“不可變” (immutable)的,確保NSString、NSArray、NSDictionary對象中的值不會無意間更改。
12、將16進制(@“#fcdf39”)轉(zhuǎn)成UIColor,請簡單寫一個實現(xiàn)。
+(UIColor *)getColor:(NSString *)hexColor {
unsigned int red,green,blue;
NSRange range;
range.length = 2;
range.location = 0;
[[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&red];
range.location = 2;
[[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&green];
range.location = 4;
[[NSScanner scannerWithString:[hexColor substringWithRange:range]] scanHexInt:&blue];
return [UIColor colorWithRed:(float)(red/255.0f) green:(float)(green / 255.0f) blue:(float)(blue / 255.0f) alpha:1.0f];
}
7、__block在arc和非arc下的含義一樣嗎?
在非arc中,block修飾的變量的引用計算是不變的。
在arc中,會引用到,并且計算+1;
6、readwrite,readonly,assign,retain,copy,nonatomic屬性的作用。
readwrite: 是可讀可寫特性,需要生成getter方法和setter方法時
readonly :是只讀特性 ,只會生成getter方法 不會生成setter方法
assign :是賦值特性,setter方法將傳入?yún)?shù)賦值給實例變量
retain :表示持有特性,setter方法將傳入?yún)?shù)先保留,再賦值,傳入?yún)?shù)的retaincount會+1
copy :表示拷貝特性,setter方法將傳入對象復制一份
nonatomic :非原子操作,決定編譯器生成的setter getter是否是原子操作,atomic表示多線程安全,一般使用nonatomic,效率高
9、下面的代碼報錯?警告?還是正常輸出什么?
Father *father = [Father new];
BOOL b1 = [father respondsToSelector:@selector(respondsToSelector:)];
BOOL b2 = [father respondsToSelector:@selector(respondsToSelector:)];
NSLog(@"%d -- %d",b1,b2);
答案:都輸出”1”(YES)
解釋:objc中:
- 不論是實例對象還是Class,都是id類型的對象(Class同樣是對象)
- 實例對象的isa指向它的Class(儲存所有減號方法),Class對象的isa指向元類(儲存所有加號方法)
- 向一個對象(id類型)發(fā)送消息時,都是從這個對象的isa指針指向的Class中尋找方法
回到題目,當像Father類發(fā)送一個實例方法(- responseToSelector)消息時:
- 會從它的isa,也就是Father元類對象中尋找,由于元類中的方法都是類方法,所以自然找不到。
- 于是沿繼承鏈去父類NSObject元類中尋找,依然沒有。
- 由于objc對這塊的設(shè)計是,NSObject的元類的父類是NSObject類(也就是我們熟悉的NSObject類),其中有所有的實例方法,因此找到了- responseToSelector。
補充:NSObject類中的所有實例方法很可能都對應(yīng)實現(xiàn)了一個類方法(至少從開源的代碼中可以看出來),如+ resonseToSelector,但并非公開的API,如果真的是這樣,上面到第2步就可以找到這個方法。
再補充: 非NSObject的selector這樣做無效。
10、下面代碼輸出什么?
-(void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@“2");
});
NSLog(@"3");
}
答案:輸出1之后程序死鎖
解釋:dispatch_sync文檔中提到:
Calls to dispatch_sync() targeting the current queue will result in dead-lock. Use of dispatch_sync() is also subject to the same multi-party dead-lock problems that may result from the use of a mutex. Use of dispatch_async() is preferred.
sync到當前線程的block將會引起死鎖,所以只會Log出1后主線程就進入死鎖狀態(tài),不會繼續(xù)執(zhí)行。
究其原因,還要看dispatch_sync做的事,它將一個block插入到queue中,這點和async沒有區(qū)別,區(qū)別在于sync會等待到這個block執(zhí)行完成后才回到調(diào)用點繼續(xù)執(zhí)行,而這個block的執(zhí)行還依仗著viewDidLoad中dispatch_sync調(diào)用的結(jié)束,所以造成了循環(huán)等待,導致死鎖。
=============================================
-(void)viewDidLoad {
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_global_queue(0, 0), ^{
NSLog(@"2");
});
NSLog(@"3");
}
這樣會輸出:1,2,3
11、如何理解淺拷貝、深拷貝和完全拷貝?請用代碼簡單表示出來。
1、淺拷貝(shallow copy):
在淺拷貝操作時,對于被復制的對象的每一層都是指針復制,并沒有對物理地址進行復制,所以并不會重新開辟新的空間。
2、深復制(one-level-deep copy):
在深復制操作的時候,是把對象的給復制過來,至少有一層是深復制。其實也不全是深復制,如果數(shù)據(jù)有很多層次,它就只復制了第一層,而第二層還是淺復制。
3、完全復制(real - deep copy):
完全復制操作的時候,就是對于對象的每一層都進行了復制,不僅物理地址復制,對象也復制。這才是真正的深拷貝。
9、下面代碼輸出的結(jié)果是什么?
int a[4] = {10,20,30,40};
int p = a;
printf("%d",p++); //先用再加
printf("%d",++*p); // 先加再用
答:10,21
1、簡述Objective-C中,null、nil、Nil之間的區(qū)別,nil和release的區(qū)別?
Nil: 是 ObjC 類 類型的書面空值,對應(yīng) Class 類型對象。
nil: 是 ObjC 對象 的字面空值,對應(yīng) id 類型的對象,或者使用 @interface 聲明的 ObjC 對象。
NULL: 是任意的 C 指針空值。
NSNull: 是一個代表空值的類,是一個 ObjC 對象。實際上它只有一個單例方法:+[NSNull null],一般用于表示集合中值為空的對象。不管是 NULL、nil 還是 Nil,它們本質(zhì)上是一樣的,都是 (void *)0,只是寫法不同。這樣做的意義是為了區(qū)分不同的數(shù)據(jù)類型,雖然它們值相同,但我們需要理解它們之間的字面意義并用于不同場景,讓代碼更加明確,增加可讀性。
nil 與 NULL 差不多的, NULL是c的指針的值,nil是oc中指針的值。
1、首先說一下他們兩的作用,nil就是把一個對象的指針置為空,只是切斷了指針與內(nèi)存中對象的聯(lián)系,它對內(nèi)存的釋放沒有什么作用;而release才是真正用于內(nèi)存釋放的,release后系統(tǒng)會將該塊內(nèi)存標記為可用(可重新分配)。所以nil并沒有釋放內(nèi)存,只有release才是真正釋放內(nèi)存。
2、二者使用順序,如果沒有release就直接nil,那么雖然不會出錯(release一個空指針是合法的),但卻等于自己制造了內(nèi)存泄漏,因為nil之后release就已經(jīng)不起作用了,我之前的教訓就是一不小心把nil擱在了release之前,所以leak一直報內(nèi)存泄露。
3、相反,如果先release后設(shè)置nil,就不會出現(xiàn)這樣的問題,但是有人就會問,release而沒有設(shè)置nil,會怎樣?其實程序可能也不會報錯,但是要知道設(shè)置nil其實是為了防止指針錯亂,因為一個對象在release之后,給它所分配的內(nèi)存就已經(jīng)被釋放了,如果釋放之后不把指針置空的話,系統(tǒng)再誤用到到這個指針時,那么程序就會崩潰(此種情況特別容易出現(xiàn)在延時調(diào)用函數(shù)中),如果釋放之后把它的指針置為空,則即便后面的程序用到該指針,也不會崩潰。所以O(shè)bjective-C釋放內(nèi)存時必須先release然后nil。
8、為什么很多內(nèi)置類如UITableViewController的delegate屬性都是assign而不是retain的?
如題目原因是:
會引起引用,若是retain,在alloc一次之后,若release一次,會導致內(nèi)訓泄露,若release兩次會導致兩個對象的dealloc嵌套執(zhí)行,結(jié)果就是都沒有執(zhí)行成功,最后崩潰了!所有的引用計數(shù)系都存在循環(huán)應(yīng)用的問題。
例如下面的引用關(guān)系:
對象a創(chuàng)建并引用到了對象b.對象b建并引用到了對象c.*對象c創(chuàng)建并引用到了對象b.這時候b和c的引用計數(shù)分別是2和1.當a不再使用到b,調(diào)用release釋放對b的所有權(quán),因為c還引用了b,所以b引用計數(shù)為1,b不會被釋放。b不釋放,c的引用計數(shù)為1,b不會被釋放。b不釋放,c的引用計數(shù)就是1,c也不會被釋放。從此,b和c永遠都留在內(nèi)存中。這種情況,必須打斷循環(huán)引用,通過其他規(guī)則來維護引用關(guān)系。我們常見的delegate往往是assign方式的屬性而不是retain方式的屬性,賦值不會增加引用計數(shù),就是為了防止delegation兩端產(chǎn)生不必要的循環(huán)引用。如果一個UITableViewController對象a通過retain獲取了UITableView對象b的所有權(quán),這個UITabelView對象的b的delegate又是a,如果這個delegate是retain方式的,那基本上就沒有機會釋放這兩個對象了。自己在設(shè)計使用delegate模式時,也要注意這點。拓展:iphoneOS有沒有垃圾回收?autorelease和垃圾回收制(gc)有什么關(guān)系?
沒有。autorelease只是延遲釋放,gc是每隔一段時間詢問程序,看是否有無指針指向的對象,若有,就將它回收。他們兩者沒有什么關(guān)系。