1衫贬、屬性默認(rèn)關(guān)鍵詞是那些,NSString常用什么修飾歇攻,為什么固惯?
對應(yīng)基本數(shù)據(jù)類型默認(rèn)關(guān)鍵字是:atomic, readwrite, assign。
對于普通的 Objective-C 對象默認(rèn)關(guān)鍵字是:atomic, readwrite, strong缴守。
NSString用copy修飾葬毫。為了安全,一般情況下屡穗,我們都不希望字串的值跟著字符串變化贴捡,所以我們一般用copy來設(shè)置string的屬性。
@property (strong,nonatomic) NSString *rStr;
@property (copy, nonatomic) NSString *cStr;
- (void)test{
NSMutableString *mStr = [NSMutableString stringWithFormat:@"abc"];
self.rStr = mStr;
self.cStr = mStr;
NSLog(@"mStr:%p,%p", mStr,&mStr);
NSLog(@"strongStr:%p,%p", _rStr, &_rStr);
NSLog(@"copyStr:%p,%p", _cStr, &_cStr);
}
假如村砂,mStr對象的地址為0x11烂斋,也就是0x11是@“abc”的首地址,mStr變量自身在內(nèi)存中的地址為0x123础废;
當(dāng)把mStr賦值給strong的rStr時汛骂,rStr對象的地址為0x11,rStr變量自身在內(nèi)存中的地址為0x124评腺;rStr與mStr指向同樣的地址帘瞭,他們指向的是同一個對象@“abc”,這個對象的地址為0x11歇僧,所以他們的值是一樣的图张。
當(dāng)把mStr賦值給copy的cStr時,cStr對象的地址為0x22诈悍,cStr變量自身在內(nèi)存中的地址0x125祸轮;cStr與mStr指向的地址是不一樣的,他們指向的是不同的對象侥钳,所以copy是深復(fù)制适袜,一個新的對象,這個對象的地址為0x22舷夺,值為@“abc”苦酱。
如果現(xiàn)在改變mStr的值:
//注意mStr如果這里是不可變字符串,那么這里無法改變给猾,是淺拷貝疫萤。會崩潰
[mStr appendString:@"de"];
NSLog(@"strongStr:%@", _rStr);
NSLog(@"copyStr:%@", _cStr);
結(jié)果:
使用strong的字串rStr的值:@"abcde",
而使用copy的字串cStr的值:@"abc",
如果是不可變字符串
NSString * str = @"abc";
self.rStr = str;
self.cStr = str;
str = @"66666666";
NSLog(@"%@===%@",self.rStr,self.cStr);//打印結(jié)果都是abc
2、nullable敢伸、nonnull 扯饶、NS_ASSUME_NONNULL_BEGIN 和 NS_ASSUME_NONNULL_END 的含義和用途?
__nullable指代對象可以為NULL或者為NIL
__nonnull指代對象不能為null
當(dāng)我們不遵循這一規(guī)則時,編譯器就會給出警告尾序。
事實上钓丰,在任何可以使用const關(guān)鍵字的地方都可以使用__nullable和__nonnull,不過這兩個關(guān)鍵字僅限于使用在指針類型上每币。而在方法的聲明中携丁,我們還可以使用不帶下劃線的nullable和nonnull,如下所示:
- (nullable id)itemWithName:(NSString * nonnull)name
在屬性聲明中兰怠,也增加了兩個相應(yīng)的特性梦鉴,因此上例中的items屬性可以如下聲明:
@property (nonatomic, copy, nonnull) NSArray * items;
當(dāng)然也可以用以下這種方式:
@property (nonatomic, copy) NSArray * __nonnull items;
推薦使用nonnull這種方式,這樣可以讓屬性聲明看起來更清晰痕慢。
如果需要每個屬性或每個方法都去指定nonnull和nullable尚揣,是一件非常繁瑣的事。蘋果為了減輕我們的工作量掖举,專門提供了兩個宏:NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END快骗。在這兩個宏之間的代碼,所有簡單指針對象都被假定為nonnull塔次,因此我們只需要去指定那些nullable的指針方篮。如下代碼所示:
NS_ASSUME_NONNULL_BEGIN
@interface TestNullabilityClass ()
@property (nonatomic, copy) NSArray * items;
- (id)itemWithName:(nullable NSString *)name;
@end
NS_ASSUME_NONNULL_END
3、BAD_ACCESS在什么情況下出現(xiàn)励负?
訪問了懸垂指針藕溅,比如對一個已經(jīng)釋放的對象執(zhí)行了release、訪問已經(jīng)釋放對象的成員變量或者發(fā)消息继榆。 死循環(huán)巾表。
4、以下代碼輸出什么略吨?
- (void)deadLockCase1 {
NSLog(@"1"); // 任務(wù)1
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2"); // 任務(wù)2
});
NSLog(@"3"); // 任務(wù)3
}
控制臺輸出:1 集币,后面就崩潰了。
5翠忠、isKindOfClass和isMemberOfClass的區(qū)別鞠苟?selector的作用?
相同點:
都是NSObject的比較Class的方法.
不同點:
isKindOfClass:確定一個對象是否是一個類的成員,或者是派生自該類的成員秽之〉庇椋或者是繼承自某類。
isMemberOfClass:確定一個對象是否是當(dāng)前類的成員.
selector:通過方法名考榨,獲取在內(nèi)存中的函數(shù)的入口地址跨细。
6、使用NSOperationQueue的addOperationWithBlock要考慮循環(huán)引用嗎河质,為什么冀惭?
7申鱼、為什么標(biāo)準(zhǔn)頭文件都有類似以下的結(jié)構(gòu)?
#ifndef __INCvxWorksh
#define __INCvxWorksh
#ifdef __cplusplus
extern"C"{
#endif
/*...*/
#ifdef __cplusplus
}
#endif
#endif /* __INCvxWorksh */
答案:
#ifndef __INCvxWorksh
#define __INCvxWorksh
#endif
這一段是用來防止頭文件重復(fù)引用云头,vs可以使用#pragma once。但是推薦使用宏定義來防止重復(fù)包含淫半,其跨平臺溃槐,兼容性好。
如果是C++文件科吭,以C的方式編譯昏滴,并執(zhí)行{}內(nèi)的指令。其目的是為了兼容C代碼对人,常出現(xiàn)在動態(tài)鏈接庫的代碼中谣殊。
#ifdef _cplusplus //這句表示如果是c++文件
extern"C"{ //用extern "C"把一段代碼包起來
#endif
#ifdef _cplusplus
}
#endif
8、HTTP七層協(xié)議
TCP協(xié)議對應(yīng)于傳輸層
網(wǎng)絡(luò)七層協(xié)議由下往上分別為物理層牺弄、數(shù)據(jù)鏈路層姻几、網(wǎng)絡(luò)層、傳輸層势告、會話層蛇捌、表示層和應(yīng)用層。其中物理層咱台、數(shù)據(jù)鏈路層和網(wǎng)絡(luò)層通常被稱作媒體層络拌,是網(wǎng)絡(luò)工程師所研究的對象;傳輸層回溺、會話層春贸、表示層和應(yīng)用層則被稱作主機(jī)層,是用戶所面向和關(guān)心的內(nèi)容遗遵。
HTTP協(xié)議對應(yīng)于應(yīng)用層萍恕,TCP協(xié)議對應(yīng)于傳輸層,IP協(xié)議對應(yīng)于網(wǎng)絡(luò)層瓮恭,HTTP協(xié)議是基于TCP連接的,三者本質(zhì)上沒有可比性雄坪。 TCP/IP是傳輸層協(xié)議,主要解決數(shù)據(jù)如何在網(wǎng)絡(luò)中傳輸屯蹦;而HTTP是應(yīng)用層協(xié)議维哈,主要解決如何包裝數(shù)據(jù)。Socket是應(yīng)用層與TCP/IP協(xié)議族通信的中間軟件抽象層登澜,是它的一組接口阔挠。
9、Objective-C 消息發(fā)送與轉(zhuǎn)發(fā)機(jī)制原理
消息發(fā)送和轉(zhuǎn)發(fā)流程可以概括為:
消息發(fā)送(Messaging)是 Runtime 通過 selector 快速查找 IMP 的過程脑蠕,有了函數(shù)指針就可以執(zhí)行對應(yīng)的方法實現(xiàn)购撼;
另外:(Objective-C動態(tài)性的根源在方法的調(diào)用是通過message來實現(xiàn)的跪削,一次發(fā)送message的過程就是一次方法的調(diào)用過程。發(fā)送message只需要指定對象和SEL迂求,Runtime的objc_msgSend會根據(jù)在信息在對象isa指針指向的Class中尋找該SEL對應(yīng)的IMP碾盐,從而完成方法的調(diào)用。)
消息轉(zhuǎn)發(fā)(Message Forwarding)是在查找 IMP 失敗后執(zhí)行一系列轉(zhuǎn)發(fā)流程的慢速通道揩局,如果不作轉(zhuǎn)發(fā)處理毫玖,則會打日志和拋出異常。
消息查找過程IMP
(1)緩存查找
(2)繼續(xù)在類的繼承體系中查找
10凌盯、底層解析weak的實現(xiàn)原理付枫?
weak 實現(xiàn)原理的概括
Runtime維護(hù)了一個weak表,用于存儲指向某個對象的所有weak指針驰怎。weak表其實是一個hash(哈希)表阐滩,Key是所指對象的地址,Value是weak指針的地址(這個地址的值是所指對象指針的地址)數(shù)組县忌。
weak 的實現(xiàn)原理可以概括一下三步:
1掂榔、初始化時:runtime會調(diào)用objc_initWeak函數(shù),初始化一個新的weak指針指向?qū)ο蟮牡刂贰?br>
2芹枷、添加引用時:objc_initWeak函數(shù)會調(diào)用 objc_storeWeak() 函數(shù)衅疙, objc_storeWeak() 的作用是更新指針指向,創(chuàng)建對應(yīng)的弱引用表鸳慈。
3饱溢、釋放時,調(diào)用clearDeallocating函數(shù)走芋。clearDeallocating函數(shù)首先根據(jù)對象地址獲取所有weak指針地址的數(shù)組绩郎,然后遍歷這個數(shù)組把其中的數(shù)據(jù)設(shè)為nil,最后把這個entry從weak表中刪除翁逞,最后清理對象的記錄肋杖。
runtime如何實現(xiàn)weak變量的自動置nil?
runtime 對注冊的類挖函, 會進(jìn)行布局状植,對于 weak 對象會放入一個 hash 表中。 用 weak 指向的對象內(nèi)存地址作為 key怨喘,當(dāng)此對象的引用計數(shù)為0的時候會 dealloc津畸,假如 weak 指向的對象內(nèi)存地址是a,那么就會以a為鍵必怜, 在這個 weak 表中搜索肉拓,找到所有以a為鍵的 weak 對象,從而設(shè)置為 nil梳庆。
11暖途、Block 底層原理總結(jié)卑惜,有幾種類型的Block,Block的循環(huán)引用原理驻售?
(1)Block可以簡單總結(jié):
block本質(zhì)上也是一個OC對象露久,它內(nèi)部也有個isa指針;
block是封裝了函數(shù)調(diào)用以及函數(shù)調(diào)用環(huán)境的OC對象.
(2)Block 有三種類型:
NSGlobalBlock 全局區(qū)的Block
NSStackBlock 棧區(qū)的Block
NSMallocBlock 堆區(qū)的Block
(3)Block的循環(huán)引用原理澳化?
對象风范、變量液走、Block的相互持有
那么如何解決這個問題呢慧耍?
通常我們ARC環(huán)境下面的解決辦法是通過__weak指針來解決這個問題,通過上面講的Block里面的變量是通過訪問的外部變量是否是strong或weak指針來進(jìn)行內(nèi)部對象進(jìn)行相應(yīng)修飾的裙戏,所以如果訪問的外部對象是weak指針時,他們的引用關(guān)系就會如下圖:
12、YTCar *car 實現(xiàn)對象car的手動內(nèi)存管理模式下的set方法
//是一個不斷去掉舊值賦新值的過程
- (void)setCar:(YTCar *)car{
if (_car != car) { //判斷新舊值是否相等
//release掉舊值
[_car release];
//retain新值
_car = [car retain];
}
}
13瘤旨、NSThread、 GCD竖伯、NSOperation的區(qū)別存哲?
1)NSThread
優(yōu)點:NSThread 比其他兩個輕量級。
缺點:需要自己管理線程的生命周期七婴,線程同步祟偷。
線程同步對數(shù)據(jù)的加鎖會有一定的系統(tǒng)開銷。
3)GCD
替代NSThread等線程打厘,自動管理生命周期修肠。
2)NSOperation
優(yōu)點:不需要關(guān)心線程管理, 數(shù)據(jù)同步的事情户盯,可以把精力放在自己需要執(zhí)行的操作上嵌施。
基于GCD底層,使用起來更加面向?qū)ο竺а肌1菺CD多了一些簡單實用的功能吗伤。
14、autorelease 自動釋放池的釋放時機(jī)硫眨,autoreleasepool的實現(xiàn)原理足淆?
(1)runloop就是iOS中的消息循環(huán)機(jī)制,當(dāng)一個runloop結(jié)束時系統(tǒng)才會一次性清理掉被autorelease處理過的對象礁阁,其實本質(zhì)上說是在本次runloop迭代結(jié)束時清理掉被本次迭代期間被放到autorelease pool中的對象的巧号。至于何時runloop結(jié)束并沒有固定的duration!
(2)當(dāng)一個autorelease pool被drain 的時候氮兵,會對pool里的每一個對象發(fā)送一個release消息裂逐;
(3)每一個線程(包括主線程)都有一個AutoreleasePool棧。當(dāng)一個新的池子被創(chuàng)建的時候泣栈,push進(jìn)棧卜高,當(dāng)池子被釋放內(nèi)存時弥姻,pop出棧。對象調(diào)用autorelease方法進(jìn)入棧頂池子中掺涛。當(dāng)線程結(jié)束的時候庭敦,會自動地銷毀所有跟它有關(guān)聯(lián)的池子。
使用容器的block版本的枚舉器時薪缆,內(nèi)部會自動添加一個AutoreleasePool:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
// 這里被一個局部@autoreleasepool包圍著
}];
在普通for循環(huán)和for in 循環(huán)中沒有秧廉,當(dāng)for循環(huán)中便利產(chǎn)生大量autorelease變量時,就需要手動加局部AutoreleasePool拣帽。
autoreleasepool的實現(xiàn)原理疼电?
AutoreleasePool(自動釋放池)是OC中的一種內(nèi)存自動回收機(jī)制,它可以延遲加入AutoreleasePool中的變量release的時機(jī)减拭。在正常情況下蔽豺,創(chuàng)建的變量會在超出其作用域的時候release,但是如果將變量加入AutoreleasePool拧粪,那么release將延遲執(zhí)行修陡。
AutoreleasePool底層實現(xiàn)原理
autoreleasepool的實現(xiàn)原理
15、OC中如何判斷兩個對象完全相同可霎?
(1)isEqual和hash
- (BOOL)isEqual:(id)object {
if (self == object) {
return YES;
}
if (![self class] == [object class]) {
return NO;
}
//此處還需判斷對象中的各個屬性是否相同
...
//若所有屬性都相同則返回
return YES;
}
首先判斷兩個指針是否相等魄鸦,若相等,則均指向同一對象癣朗,所以受測的對象也必定相等拾因。接下來判斷兩對象所屬的類,若屬于同一類旷余。
hash:比較得時候最好是先計算其哈希碼盾致,再進(jìn)行比較。
(2)==
比較的是兩個對象的指針本身荣暮,有時候返回的結(jié)果并不是我們想要的結(jié)果庭惜。
(3)isEqualToString
用于判斷兩個字符串是否相等的方法,當(dāng)然還有isEqualToArray: isEqualToDictionary:
(4)NSSet中可變類的等同性比較【數(shù)組去重】
OC 判斷兩個對象是否相等
16穗酥、retain一個NSTime類型成員變量會有什么問題护赊?
使用NSTimer可能會碰到循環(huán)引用的問題。特別是當(dāng)類具有NSTimer類型的成員變量砾跃,并且需要反復(fù)執(zhí)行計時任務(wù)時骏啰。
_timer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:self
selector:@selector(startCounting) userInfo:nil
repeats:YES];
類有一個成員變量_timer,給_timer設(shè)置的target為這個類本身抽高。這樣類保留_timer判耕,_timer又保留了這個類,就會出現(xiàn)循環(huán)引用的問題翘骂,最后導(dǎo)致類無法正確釋放壁熄。
解決這個問題的方式也很簡單帚豪,當(dāng)類的使用者能夠確定不需要使用這個計時器時,就調(diào)用
[_timer invalidate];
_timer = nil;
17草丧、Category的使用及原理?與Runtime有關(guān)嗎狸臣?
18、數(shù)組去重(順序不會變昌执,去重后數(shù)組為listAry烛亦,并找出重復(fù)的元素(listAryCF)?
/**
數(shù)組去重懂拾,順序不會變
@param array 傳入的數(shù)組
@return 得到去重后的可變數(shù)組
*/
+(NSMutableArray *)arrayDataDeleteChongFuWithArray:(NSArray *)array{
NSMutableArray *listAry = [[NSMutableArray alloc]init];//去重后的數(shù)組
// NSMutableArray *listAryCF = [[NSMutableArray alloc]init];//檢出重復(fù)的元素煤禽,放入數(shù)組
for (NSString *str in array) {
// containsObject 判斷數(shù)組是否包含某個元素
if (![listAry containsObject:str]) {
[listAry addObject:str];
}else{
//附加
//重復(fù)元素加入新數(shù)組
// [listAryCF addObject:str];
// NSLog(@"重復(fù)的元素:%@",str);
}
}
return listAry;
}
19、【重】監(jiān)聽一組異步任務(wù)是否都執(zhí)行結(jié)束,如果都執(zhí)行結(jié)束就能夠得到統(tǒng)一的通知.
// 監(jiān)聽一組異步任務(wù)是否執(zhí)行結(jié)束,如果執(zhí)行結(jié)束就能夠得到統(tǒng)一的通知.
// 創(chuàng)建默認(rèn)優(yōu)先級的全局并發(fā)隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
// 創(chuàng)建調(diào)度組
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"下載圖片A");
});
dispatch_group_async(group, queue, ^{
NSLog(@"下載圖片B");
});
dispatch_group_async(group, queue, ^{
NSLog(@"下載圖片C");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"以上異步任務(wù)都處理下載完成圖片了");
});
20岖赋、masonry為什么不會造成循環(huán)引用的問題呜师?
答案:雖然block持有self,但是self并沒有持有block贾节,顯然block跟self并沒有相互持有,所以不會循環(huán)引用衷畦。
[self.view mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.otherView.mas_centerY);
}];
并不是 block 就一定會造成循環(huán)引用栗涂,是不是循環(huán)引用要看是不是相互持有強引用。block 里用到了 self祈争,那 block 會保持一個 self 的引用斤程,但是 self 并沒有直接或者間接持有 block,所以不會造成循環(huán)引用菩混。
block中持有了self忿墅,但是self.view并沒有持有這個block,因為看到Masonry的源碼是這樣的:
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
21沮峡、以下每行代碼執(zhí)行后疚脐,person對象的retain count分別是多少?
Person *person = [[Person alloc] init];
[person retain];
[person release];
[person release];
答案
Person *person = [[Person alloc] init]; =1
[person retain]; +1 = 2
[person release]; -1 = 1
[person release]; -1 = 0
22邢疙、如何用GCD同步若干個異步調(diào)用(根據(jù)若干個url異步加載多張圖片棍弄,然后在都下載完成后合成一張整圖)
// 使用Dispatch Group追加block到Global Group Queue,這些block如果全部執(zhí)行完畢,就會執(zhí)行Main Dispatch Queue中的結(jié)束處理的block疟游。
// 創(chuàng)建隊列組
dispatch_group_t group = dispatch_group_create();
// 獲取全局并發(fā)隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{ /*加載圖片1 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片2 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片3 */ });
// 當(dāng)并發(fā)隊列組中的任務(wù)執(zhí)行完畢后才會執(zhí)行這里的代碼
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并圖片
});
23呼畸、Objc中向一個nil對象發(fā)送消息會怎樣?
oc中向一個nil對象發(fā)送消息颁虐,首先在尋找對象的isa指針時就是0地址返回了蛮原,所以不會出現(xiàn)任何錯誤。也不會崩潰另绩。
24儒陨、簡單描述客戶端的緩存機(jī)制花嘶?(Describe the cache mechanism of the client?)
緩存分為:內(nèi)存數(shù)據(jù)緩存框全、數(shù)據(jù)庫緩存察绷、文件緩存。
每次想獲取數(shù)據(jù)的時候:
1)先檢測內(nèi)存中有無緩存津辩;
2)再檢測本地數(shù)據(jù)緩存(數(shù)據(jù)庫拆撼、文件);
3)最終發(fā)送網(wǎng)絡(luò)請求喘沿;
4)將網(wǎng)絡(luò)數(shù)據(jù)進(jìn)行緩存(內(nèi)存闸度、數(shù)據(jù)庫、文件)蚜印,以便下次讀取莺禁。
25.1、下面線程輸出順序窄赋?
dispatch_queue_t queue = dispatch_queue_create("com.taikang.com", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"1------%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"2------%@",[NSThread currentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"3------%@",[NSThread currentThread]);
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"4------%@",[NSThread currentThread]);
});
NSLog(@"5------%@",[NSThread currentThread]);
答案:輸出順序:1 2 3 5 4
輸出順序:1 2 3 5 4
25.2哟冬、執(zhí)行這個方法需要幾秒?打印順序是啥忆绰?
- (void)testGCD
{
dispatch_queue_t queue = dispatch_queue_create("test", NULL);
dispatch_async(queue, ^(void){
NSLog(@"1");
sleep(1);
});
dispatch_async(queue, ^(void){
NSLog(@"2");
sleep(1);
});
dispatch_sync(queue, ^(void){
NSLog(@"3");
sleep(1);
});
}
答案:調(diào)用該方法要3秒浩峡,因為sleep是休眠,打印順序:123错敢。
26翰灾、給定一個字符串,請你找出其中不含有重復(fù)字符的 最長子串 的長度稚茅?
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 因為無重復(fù)字符的最長子串是 "abc"纸淮,所以其長度為 3。
測試輸入:abcabcdefbbkcghghjkla
-(void)stringMaxLength{
// NSString *str = @"abcabcbb";
NSString *str = @"abcabcdefbbkcghghjkla";
NSInteger maxLenth = 0;//最大長度
NSString *targetStr = @"";//最大長度對應(yīng)的字符串
for (int i=0; i<str.length; i++) {
for (int j=1; j<str.length+1-i; j++){
NSString *substr = [str substringWithRange:NSMakeRange(i, j)];
BOOL isRepeatStr = NO;
NSMutableArray *tempArr = [NSMutableArray array];
for (int k=0; k<substr.length; k++) {
NSString *subsubStr = [substr substringWithRange:NSMakeRange(k, 1)];
if ([tempArr containsObject:subsubStr]) {
isRepeatStr = YES;
break;
}else{
[tempArr addObject:subsubStr];
}
}
if (isRepeatStr == NO) {
if (substr.length > maxLenth) {
maxLenth = substr.length;
targetStr = substr;
}
}
}
}
NSLog(@"最大長度無重復(fù)字符串長度為:%ld == 字符串為:%@",(long)maxLenth,targetStr);
}
//輸出結(jié)果為:abcdef
輸出結(jié)果為:abcdef
27亚享、 iOS runloop與線程的關(guān)系
runloop是每一個線程一直運行的一個對象咽块,它主要用來負(fù)責(zé)響應(yīng)需要處理的各種事件和消息。每一個線程都有且僅有一個runloop與其對應(yīng)欺税,沒有線程糜芳,就沒有runloop。
在所有線程中魄衅,只有主線程的runloop是默認(rèn)啟動的峭竣,main函數(shù)會設(shè)置一個NSRunLoop對象。而其他的線程runloop默認(rèn)是沒有啟動的晃虫,可以通過[NSRunLoop currentRunLoop]來啟動皆撩。
當(dāng)線程的 RunLoop 開啟后,線程就會在執(zhí)行完任務(wù)后,處于休眠狀態(tài)扛吞,隨時等待接受新的任務(wù)呻惕,而不是退出。
28滥比、什么是isa指針亚脆?
isa是一個Class 類型的指針. 每個實例對象有個isa的指針,他指向?qū)ο蟮念悾鳦lass里也有個isa的指針, 指向meteClass(元類)盲泛。元類保存了類方法的列表濒持。當(dāng)類方法被調(diào)用時,先會從本身查找類方法的實現(xiàn)寺滚,如果沒有柑营,元類會向他父類查找該方法。同時注意的是:元類(meteClass)也是類村视,它也是對象官套。元類也有isa指針,它的isa指針最終指向的是一個根元類(root meteClass).根元類的isa指針指向本身,這樣形成了一個封閉的內(nèi)循環(huán)蚁孔。
29奶赔、Block 為什么用 Copy 修飾?
對于這個問題杠氢,得區(qū)分 MRC 環(huán)境 和 ARC 環(huán)境站刑;當(dāng)Block 引用了普通外部變量時,都是創(chuàng)建在棧區(qū)的修然;對于分配在棧區(qū)的對象,我們很容易會在釋放之后繼續(xù)調(diào)用质况,導(dǎo)致程序奔潰愕宋,所以我們使用的時候需要將棧區(qū)的對象移到堆區(qū),來延長該對象的生命周期结榄。
對于 MRC 環(huán)境中贝,使用 Copy 修飾 Block,會將棧區(qū)的 Block 拷貝到堆區(qū)臼朗。
對于 ARC 環(huán)境邻寿,使用 Strong、Copy 修飾 Block视哑,都會將棧區(qū)的 Block 拷貝到堆區(qū)绣否。
所以,Block 不是一定要用 Copy 來修飾的挡毅,在 ARC 環(huán)境下面 Strong 和 Copy 修飾效果是一樣的蒜撮。
30、解釋static、self段磨、super關(guān)鍵字的作用取逾?
static:函數(shù)體內(nèi)static變量的作用范圍為該函數(shù)體,不同于auto變量苹支,該變量的內(nèi)存只被分配一次砾隅,因此其值在下次調(diào)用時仍維持上次的值.
在模塊內(nèi)的 static 全局變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問.
在模塊內(nèi)的static函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用债蜜,這個函數(shù)的使用范圍被限制在聲明.
在類中的static成員變量屬于整個類所擁有晴埂,對類的所有對象只有一份拷貝。
self:當(dāng)前消息的接收者策幼。
super:向父類發(fā)送消息邑时。
31、在一個對象的方法里面:self.name= “object”;和 name =”object” 有什么不同嗎?
答:self.name =”object”:會調(diào)用對象的setName()方法;
name = “object”:會直接把object賦值給當(dāng)前對象的name屬性特姐。
32晶丘、這段代碼有什么問題嗎?
-(void)setAge:(int)newAge{
self.age = newAge;
}
答案
死循環(huán)唐含,應(yīng)該修改為:_age = newAge;
33浅浮、這段代碼有什么問題,如何修改捷枯?
for (int i = 0; i < someLargeNumber; i++) {
NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];
NSLog(@“%@”, string);
}
答案
打印結(jié)果:string = abcxyz
大次數(shù)循環(huán)會出現(xiàn)內(nèi)存泄露滚秩,加入自動釋放池@autoreleasepool{};在變量使用結(jié)束后立刻釋放。
for (int i = 0; i < someLargeNumber; i++) {
@antoreleasepool {
NSString *string = @”Abc”;
string = [string lowercaseString];//字母全部轉(zhuǎn)小寫
string = [string stringByAppendingString:@"xyz"];//字符串追加
NSLog(@“%@”, string);
}
}
35淮捆、直接修改成員變量或?qū)傩詴|發(fā)KVO嗎郁油?
答案:都不會執(zhí)行。觀察者觀察的是屬性攀痊,只有遵循 KVO 變更屬性值的方式才會執(zhí)行KVO的回調(diào)方法桐腌,例如是否執(zhí)行了setter方法、或者是否使用了KVC賦值苟径。如果賦值沒有通過setter方法或者KVC案站,而是直接修改屬性對應(yīng)的成員變量,例如:僅調(diào)用_name = @"newName"棘街,這時是不會觸發(fā)kvo機(jī)制蟆盐,更加不會調(diào)用回調(diào)方法的。
所以使用KVO機(jī)制的前提是遵循 KVO 的屬性設(shè)置方式來變更屬性值遭殉。
36石挂、Block是如何捕獲Object-C的對象的?
答案:block里捕獲的是該變量指向的內(nèi)存地址险污,而不是直接把當(dāng)前的對象的地址誊稚。
可能是指針拷貝。Block會對外部的變量進(jìn)行一次"臨時“的”拷貝“.產(chǎn)生一個新的指針,對象地址不變。
37里伯、當(dāng)數(shù)據(jù)庫中的某項數(shù)據(jù)為null時,通過FMDB取出的數(shù)據(jù)為?
答案:nil
38城瞎、下面代碼打印什么?
//在NSObject+Test.h中
#import <Foundation/Foundation.h>
@interface NSObject (Test)
-(void)test;
+(void)test1;
@end
@interface ClassA : NSObject
@end
//在NSObject+Test.m中
#import "NSObject+Test.h"
@implementation NSObject (Test)
-(void)test{
NSLog(@"aaa");
}
+(void)test1{
NSLog(@"bbb");
}
@end
@implementation ClassA
@end
答案:在調(diào)用的控制器里調(diào)用打印如下
[NSObject test1];//打印bbb
[ClassA test1];//打印bbb
[[[NSObject alloc]init] test];//打印aaa
[[[ClassA alloc]init] test];//打印aaa
39疾瓮、對于宏定義:#define MIN(A,B) (A) < (B) ? (A) : (B)
float a = 1.0;
float b = MIN(a++, 1.5);
NSLog(@"a===%f,b==%f",a,b);
答案: a===3.000000,b==2.000000
因為運算符優(yōu)先級從高到底:() ++ < ? :
然后a++是先賦值在加1脖镀,++a是先加1在賦值。
在(a++) < (1.5) ? (a++) : (1.5)中狼电,第一次:
算式里第一個a為1,第二個a為2蜒灰。
(1) < (1.5) ? (a++) : (1.5)//第一個賦完值后才開始加1,此時a為2肩碟,拿著去后面用强窖。
(1) < (1.5) ? (2) : (1.5) 所以在三目運算時第二個a為2。所以最終b為2削祈。
最終因為a被++了兩次翅溺,所以a為3。
40髓抑、Protocol(協(xié)議)可以添加@property屬性嗎? Category可以添加@property屬性嗎?
答案
(1)在protocol中使用property只會生成setter和getter方法聲明咙崎,我們使用屬性的目的,是希望遵守我協(xié)議的對象能實現(xiàn)該屬性吨拍。
(2)category使用@property也是只會生成setter和getter方法的聲明褪猛,如果我們真的需要給category增加屬性的實現(xiàn),需要借助于運行時的兩個函數(shù):
obj_setAssociatedObject
obj_getAssociatedObject
41羹饰、在MRC下伊滋,如下代碼:
NSString * a = @"abc";
NSString * b = [a retain];
NSString * c = [b copy];
NSString * d = [c mutableCopy];
NSString * e = [d copy];
請寫出a、b队秩、c笑旺、d、e的引用計數(shù)各是多少刹碾?
答案
2燥撞、2座柱、2迷帜、3、3
42色洞、下面代碼輸出什么戏锹?
NSUserDefaults * userDefaults = [NSUserDefaults standardUserDefaults];
BOOL boolFlag = NO;
[userDefaults setObject:@(boolFlag) forKey:@"boolFlag"];//這里儲存的NSNumber類型
//解釋
id sss = [userDefaults objectForKey:@"boolFlag"];//sss值打印為:0 是NSNumber類型
BOOL yyyy = sss;//yyyy值打印為YES(NSNumber類型轉(zhuǎn)BOOL類型)
//補充:BOOL值進(jìn)行轉(zhuǎn)換時,其基準(zhǔn)是判斷對象是否存在火诸,如果對象存在的時候即為1锦针,不存在則為0; 而 NSNumber 恰好就是一個對象,所以即使它為0的情況下奈搜,在編譯器的眼里依然視為對象存在悉盆,被轉(zhuǎn)換過成1。如果在這里要想將0轉(zhuǎn)換成 NO馋吗,必須先將 NSNumber 類型的IntegerValue取出來焕盟,然后賦測能得到1。
if ([userDefaults objectForKey:@"boolFlag"]) {//有值就走這里==0
BOOL eqByPass = [userDefaults objectForKey:@"boolFlag"];//為YES
if (eqByPass) {//
NSLog(@"A");
}else{
NSLog(@"B");
}
}else{
BOOL eqByPass = [userDefaults objectForKey:@"boolFlag"];
if (eqByPass) {
NSLog(@"C");
}else{
NSLog(@"D");
}
}
答案
輸出A
43宏粤、以下代碼打印順序脚翘?
//執(zhí)行順序
- (void)syncMain{
dispatch_queue_t queue = dispatch_queue_create("serial", nil);
dispatch_async(queue, ^(void){
NSLog(@"1");
});
dispatch_sync(queue, ^(void){
NSLog(@"2");
});
dispatch_async(queue, ^(void){
NSLog(@"3");
dispatch_sync(queue, ^(void){
NSLog(@"4");
});
});
}
答案
1、2绍哎、3 来农,走完3的時候就崩潰了,不會打印4崇堰,線程互斥沃于。
44、如何手動觸發(fā)一個value的KVO?
答案
自動觸發(fā)場景:在注冊 KVO 之前設(shè)置一個初始值赶袄,注冊之后揽涮,設(shè)置一個不一樣的值,這樣就可以觸發(fā)了饿肺。
手動觸發(fā):
鍵值觀察通知依賴于 NSObject 的兩個方法: willChangeValueForKey:和 didChangevlueForKey:蒋困。在一個被觀察屬性發(fā)生改變之前,willChangeValueForKey: 一定會被調(diào)用敬辣,這就會記錄舊的值雪标。而當(dāng)改變發(fā)生后,observeValueForKey:ofObject:change:context: 和 didChangeValueForKey:也會被調(diào)用溉跃。如果可以手動實現(xiàn)這些調(diào)用村刨,就可以實現(xiàn)“手動觸發(fā)”了。
.m文件
//手動觸發(fā) value 的 KVO 撰茎,最后兩行代碼缺一不可
@property (nonatomic, strong) NSDate *now;
- (void)viewDidLoad{
[super viewDidLoad];
_now = [NSDate date];
[self addObserver:self forKeyPath:@"now" options:NSKeyValueObservingOptionNew context:nil];
NSLog(@"1");
[self willChangeValueForKey:@"now"];//手動觸發(fā)self.now的KVO嵌牺,必寫。
NSLog(@"2");
[self didChangeValueForKey:@"now"];//手動觸發(fā)self.now的KVO龄糊,必寫逆粹。
NSLog(@"4");
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"3");
}
//打印順序是:1 2 3 4。
45炫惩、下面代碼有什么問題僻弹?如果有請指出?
-(NSString *)getString{
return (__bridge NSString*)CFStringCreateWithCString(NULL, "h", kCFStringEncodingUTF8);
}
答案
NSLog(@"得到字符串:%@",[self getString]);//打铀隆:h
沒毛病啊蹋绽,老鐵芭毙。
46、下面代碼里 [(__bridge id)obj print] 輸出什么卸耘?(2019)
//MNPerson.h
@interface MNPerson : NSObject
@property(nonatomic,copy)NSString * name;
-(void)print;
@end
//MNPerson.m
#import "MNPerson.h"
@implementation MNPerson
-(void)print{
// self.name = @"1111";
NSLog(@"self.name = %@",self.name);
}
@end
//在ToolsEntController控制器的viewDidLoad里打印
NSLog(@"得到字符串:%@",[self getString]);//打油硕亍:h
id cls = [MNPerson class];
void * obj = &cls;
[(__bridge id)obj print];
答案
[(__bridge id)obj print]打印:self.name = <ToolsEntController: 0x7fb1a5508d50>
如果name有值(如值為1111)就打域伎埂:self.name = 1111
47苛聘、iOS重寫單例,防止通過alloc]init或new忠聚、copy的方式開辟新空間设哗。(20200831)
#import "NetWorkTools.h"
@implementation NetWorkTools
static id _instanceType = nil;
//自定義類方法
+(instancetype)sharadNetWorkTools{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instanceType = [[self alloc]init];
});
return _instanceType;
}
//重寫父類方法,防止通過alloc]init或new的方式開辟新空間
+ (instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instanceType = [super allocWithZone:zone];
});
return _instanceType;
}
//防止對象copy操作
-(id)copyWithZone:(NSZone *)zone{
return _instanceType;
}
@end
48、iOS App推送流程两蟀,APNS-蘋果服務(wù)器网梢。(20200831)
ios 設(shè)備 app在安裝完成后,要完成消息的推送赂毯,需要以下步驟:
(1) app 將設(shè)備的 UUID(蘋果設(shè)備的唯一標(biāo)識) 和 app 的 bundled(項目的唯一標(biāo)識)發(fā)送到 APNS(蘋果服務(wù)器)战虏,請求 deviceToken。
(2)APNS 在收到 app 發(fā)送的請求后党涕,會將加密后的 deviceToken 發(fā)送給 app烦感。
(3)app 拿到 deviceToken 后,將 deviceToken 傳到運營商服務(wù)器上膛堤,比如極光手趣。這樣以來,運營商就獲取了推送權(quán)限肥荔。
(4)當(dāng)有消息需要推送給某一位用戶時绿渣,運營商就可以通過客戶端對應(yīng)的 deviceToken 選擇推送對象。將推送消息和 deviceToken 一并發(fā)送給 APNS燕耿。
(5)APNS 根據(jù)發(fā)送過來的 deviceToken 中符,將推送消息發(fā)送到指定的設(shè)備上,完成消息的推送工作誉帅。