【潮汐】iOS面試題總結(jié)庶弃,持續(xù)更新中......

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的相互持有

循環(huán)引用原理

那么如何解決這個問題呢慧耍?
通常我們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)行比較。

參考:OC中 判斷2個對象相等(isEqual和hash)

(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)嗎狸臣?

Category的使用及原理

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è)備上,完成消息的推送工作誉帅。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淀散,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚜锨,更是在濱河造成了極大的恐慌档插,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件踏志,死亡現(xiàn)場離奇詭異阀捅,居然都是意外死亡胀瞪,警方通過查閱死者的電腦和手機(jī)针余,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門饲鄙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人圆雁,你說我怎么就攤上這事忍级。” “怎么了伪朽?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵轴咱,是天一觀的道長。 經(jīng)常有香客問我烈涮,道長朴肺,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任坚洽,我火速辦了婚禮戈稿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘讶舰。我一直安慰自己鞍盗,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布跳昼。 她就那樣靜靜地躺著般甲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鹅颊。 梳的紋絲不亂的頭發(fā)上敷存,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音堪伍,去河邊找鬼历帚。 笑死,一個胖子當(dāng)著我的面吹牛杠娱,可吹牛的內(nèi)容都是我干的挽牢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼摊求,長吁一口氣:“原來是場噩夢啊……” “哼禽拔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起室叉,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤睹栖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后茧痕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體野来,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年踪旷,在試婚紗的時候發(fā)現(xiàn)自己被綠了曼氛。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片豁辉。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖舀患,靈堂內(nèi)的尸體忽然破棺而出徽级,到底是詐尸還是另有隱情,我是刑警寧澤聊浅,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布餐抢,位于F島的核電站,受9級特大地震影響低匙,放射性物質(zhì)發(fā)生泄漏旷痕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一顽冶、第九天 我趴在偏房一處隱蔽的房頂上張望苦蒿。 院中可真熱鬧,春花似錦渗稍、人聲如沸佩迟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽报强。三九已至,卻和暖如春拱燃,著一層夾襖步出監(jiān)牢的瞬間秉溉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工碗誉, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留召嘶,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓哮缺,卻偏偏與公主長得像弄跌,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子尝苇,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,089評論 1 32
  • 1.設(shè)計模式是什么糠溜? 你知道哪些設(shè)計模式淳玩,并簡要敘述?設(shè)計模式是一種編碼經(jīng)驗非竿,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,136評論 0 12
  • 設(shè)計模式是什么蜕着? 你知道哪些設(shè)計模式,并簡要敘述红柱? 設(shè)計模式是一種編碼經(jīng)驗承匣,就是用比較成熟的邏輯去處理某一種類型的...
    不懂后悔閱讀 823評論 0 53
  • 1.屬性readwrite蓖乘,readonly,assign悄雅,retain,copy铁蹈,nonatomic 各是什么作...
    曾令偉閱讀 1,044評論 0 10
  • “小時候我們總是偷穿大人的衣服宽闲,偽裝成大人,可當(dāng)我們長大了握牧,卻再也穿不回小孩的衣服了容诬。” 在空氣中都彌漫水蒸氣的下...
    月影拂曉乄閱讀 267評論 1 0