1、截取字符串”20 | http://www.baidu.com”中,”|”字符前面和后面的數據,分別輸出它們
? ? NSString *str = @"20|http://www.baidu.com";
? ? NSArray *arr = [str componentsSeparatedByString:@"|"];
? ? NSLog(@"%@",arr[0]);
? ? NSLog(@"%@",arr[1]);
2、.NSString *obj = [[NSSData alloc]init] ,obj在編譯時和運行時分別是什么類型的對象
編譯時是nsstring, 運行時是nsdata的一個實例
3、viewController的loadView,viewDidLoad,viewDidUnload分別是在什么時候調用的?
loadView:view準備加載到當前屏幕時,檢查當前view不存在,調用loadView加載
viewDidLoad:loadView加載完成后,調用
viewDidUnload:view不再顯示在當前屏幕時,調用。
4、屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那種情況下用?
readwrite 是可讀可寫特性;需要生成getter方法和setter方法時
readonly 是只讀特性 只會生成getter方法 不會生成setter方法 ;不希望屬性在類外改變
assign 是賦值特性,setter方法將傳入參數賦值給實例變量;僅設置變量時;
retain 表示持有特性,setter方法將傳入參數先保留,再賦值,傳入參數的retaincount會+1;
copy 表示賦值特性,setter方法將傳入對象復制一份;需要完全一份新的變量時。
nonatomic 非原子操作,決定編譯器生成的setter getter是否是原子操作,atomic表示多線程安全,一般使用nonatomic
5、類別的作用?繼承和類別在實現中有何區別?
category 可以在不獲悉,不改變原來代碼的情況下往里面添加新的方法,只能添加,不能刪除修改,并且如果類別和原來類中的方法產生名稱沖突,則類別將覆蓋原來的方法,因為類別具有更高的優先級。
類別主要有3個作用:
1).將類的實現分散到多個不同文件或多個不同框架中。
2).創建對私有方法的前向引用。
3).向對象添加非正式協議。
繼承可以增加,修改或者刪除方法,并且可以增加屬性。
6、類別和類擴展的區別。
category和extensions的不同在于 后者可以添加屬性。另外后者添加的方法是必須要實現的。
extensions可以認為是一個私有的Category。
7、frame和bounds有什么不同?
frame指的是:該view在父view坐標系統中的位置和大小。(參照點是父親的坐標系統)
bounds指的是:該view在本身坐標系統中 的位置和大小。(參照點是本身坐標系統)
8、import 跟#include 又什么區別,@class呢, #import<> 跟 #import””又什么區別?
import是Objective-C導入頭文件的關鍵字,#include是C/C++導入頭文件的關鍵字,使用#import頭文件會自動只導入一次,不會重復導入,相當于#include和#pragma once;
@class告訴編譯器某個類的聲明,當執行時,才去查看類的實現文件,可以解決頭文件的相互包含;#import<>用來包含系統的頭文件,#import””用來包含用戶頭文件。
9、以下代碼運行結果如何?
- (void)viewDidLoad{
[super viewDidLoad];
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
只輸出:1 。發生主線程鎖死。
10、關于block
void test1()
{
int a = 10;
void (^block)() = ^{
NSLog(@"a is %d", a);
};
a = 20;
block(); // 10
}
void test2()
{
__block int a = 10;
void (^block)() = ^{
NSLog(@"a is %d", a);
};
a = 20;
block(); // 20
}
void test3()
{
static int a = 10;
void (^block)() = ^{
NSLog(@"a is %d", a);
};
a = 20;
block(); // 20
}
int a = 10;
void test4()
{
void (^block)() = ^{
NSLog(@"a is %d", a);
};
a = 20;
block();//20
}
11、block和weak區別?
__block不管是ARC還是MRC模式下都可以使用,可以修飾對象,還可以修飾基本數據類型。
__weak只能在ARC模式下使用,也只能修飾對象(NSString),不能修飾基本數據類型(int)。
block對象可以在block中被重新賦值,weak不可以。
12、創建一個單例
+(instancetype)shareSingleton{
static Singleton *singleton = nil;
static dispatch_once_t onceToken;? //給單例加了一個線程鎖
dispatch_once(&onceToken, ^{
singleton = [[Singleton alloc] init];
});
return singleton;
13、寫一個標準宏MIN,這個宏輸入兩個參數并返回較小的一個
#define kMIN(X,Y) ((X) > (Y)) ? (Y) :(X)
14、簡述應用程序按Home鍵進入后臺時的生命周期,以及從后臺回到前臺時的生命周期
進入后臺生命周期走:
- (void)applicationWillResignActive:(UIApplication*)application;
- (void)applicationDidEnterBackground:(UIApplication*)application;
回到前臺生命周期走:
- (void)applicationWillEnterForeground:(UIApplication*)application;
- (void)applicationDidBecomActive:(UIApplication*)application;
15、將字符串“2015-04-10”格式化日期轉為NSDate類型
NSString *timeStr = @"2015-04-10";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd";
formatter.timeZone = [NSTimeZone defaultTimeZone];
NSDate *date = [formatter dateFromString:timeStr];
// 2015-04-09 16:00:00 +0000
NSLog(@"%@", date);
16、isMemberOfClass 和 isKindOfClass 聯系與區別
聯系:兩者都能檢測一個對象是否是某個類的成員
區別:
isKindOfClass:確定一個對象是否是一個類的成員,或者是派生自該類的成員.
isMemberOfClass:確定一個對象是否是當前類的成員.
舉例:如 ClassA派 生 自NSObject 類 , ClassA *a = [ClassA alloc] init];,[a isKindOfClass:[NSObject class]] 可以檢查出 a 是否是 NSObject派生類 的成員,但 isMemberOfClass 做不到。
17、描述應?用程序的啟動順序
程序入口main函數創建UIApplication實例和UIApplication代理實例.
重寫UIApplication代理實例,設置rootviewcontroller.
在第一viewController中添加控件,實現對應的程序界面.
18、在某個方法中 self.name = _name,name = _name 它 們有區別嗎,為什么?
self.name = "object"會調用對象的setName()方法,
name = "object"會直接把object賦值給當前對象的name 屬性。
并且 self.name 這樣retainCount會加1,而name就不會。
19、解釋self = [super init]方法
容錯處理,當父類初始化失敗,會返回一個nil,表示初始化失敗,由于繼承的關系,子類是要得到父類的實例和行為,因此我們必須先初始化父類,然后初始化子類
20、我們說的oc是動態運行時語言是什么意思?
答案:多態。 主要是將數據類型的確定由編譯時,推遲到了運行時。
這個問題其實淺涉及到兩個概念,運行時和多態。
簡單來說,運行時機制使我們直到運行時才去決定一個對象的類別,以及調用該類別對象指定方法。
多態:不同對象以自己的方式響應相同的消息的能力叫做多態。意思就是假設生物類(life)都用有一個相同的方法-eat;
那人類屬于生物,豬也屬于生物,都繼承了life后,實現各自的eat,但是調用是我們只需調用各自的eat方法。
也就是不同的對象以自己的方式響應了相同的消息(響應了eat這個選擇器)。
21、自動釋放池是什么,如何工作
當您向一個對象發送一個autorelease消息時,Cocoa就會將該對象的一個引用放入到最新的自動釋放.它仍然是個正當的對象,因此自動釋放池定義的作用域內的其它對象可以向它發送消息。當程序執行到作用域結束的位置時,自動釋放池就會被釋放,池中的所有對象也就被釋放。
22、簡述內存分區情況
1).代碼區:存放函數二進制代碼
2).數據區:系統運行時申請內存并初始化,系統退出時由系統釋放。存放全局變量、靜態變量、常量
3).堆區:通過malloc等函數或new等操作符動態申請得到,需程序員手動申請和釋放
4).棧區:函數模塊內申請,函數結束時由系統自動釋放。存放局部變量、函數參數
23、隊列和棧有什么區別
隊列和棧是兩種不同的數據容器。從”數據結構”的角度看,它們都是線性結構,即數據元素之間的關系相同。
隊列是一種先進先出的數據結構,它在兩端進行操作,一端進行入隊列操作,一端進行出列隊操作。
棧是一種先進后出的數據結構,它只能在棧頂進行操作,入棧和出棧都在棧頂操作。
24、Quatrz 2D的繪圖功能的三個核心概念是什么并簡述其作用。
答:上下文:主要用于描述圖形寫入哪里;
路徑:是在圖層上繪制的內容;
狀態:用于保存配置變換的值、填充和輪廓, alpha 值等。
25、什么是沙盒模型?哪些操作是屬于私有api范疇?
某個iphone工程進行文件操作有此工程對應的指定的位置,不能逾越。
iphone沙箱模型的有四個文件夾documents,tmp,app,Library,永久數據存儲一般
放documents文件夾,得到模擬器的路徑的可使用NSHomeDirectory()方法。
Nsuserdefaults保存的文件在Library/Preference:?
26、重寫一個NSString類型的,retain方式聲明name屬性的setter和getter方法
-(void)settetName:(NSString *)name{
if(_name){
[_name release];
}
_name = [name retain];
}
-(NSString *)getterName{
return [[_name retain]autorelease];
27、如監測系統鍵盤的彈出
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShown:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
/** 鍵盤彈出動畫 */
-(void)onKeyboradShow:(NSNotification *)notify
{
CGFloat keyboard = [[notify.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]CGRectValue].size.height;
CGFloat duration = [[notify.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]floatValue];
[UIView animateWithDuration:duration + 0.25 delay:0 usingSpringWithDamping:1 initialSpringVelocity:1 options:UIViewAnimationOptionLayoutSubviews animations:^{
self.inputView.frame = CGRectMake(0, k_screenHeight - keyboard - 50, k_screenWidth, 50);
} completion:nil];
self.isOriginal = NO;
self.maskView.hidden = NO;
}
/** 鍵盤收起動畫 */
-(void) onKeyboradHide:(NSNotification *) notify
{
CGFloat duration = [[notify.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]floatValue];
[UIView animateWithDuration:duration delay:0 usingSpringWithDamping:1 initialSpringVelocity:1 options:UIViewAnimationOptionLayoutSubviews animations:^{
self.inputView.frame = CGRectMake(0, k_screenHeight - 50, k_screenWidth, 50);
} completion:nil];
self.isOriginal = NO;
self.maskView.hidden = YES;
}
28、用OC寫一個冒泡排序
NSMutableArray *array = [NSMutableArray arrayWithArray:@[@"3",@"1",@"10",@"5",@"2",@"7",@"12",@"4",@"8"]];
for (int i =0; i < array.count;i ++) {
? ? for (int j =0; j < array.count -1 - i; j++) {
? ? ? ? if([[array objectAtIndex:j]integerValue] > [[array objectAtIndex:j + 1]integerValue]) {
? ? ? ? [array exchangeObjectAtIndex:j withObjectAtIndex:j + 1];
? ? ? ? }
? ? }
}
NSLog(@"%@",array);
29、回答person的retainCount值,并解釋為什么
Person * per = [[Person alloc] init]; 此時person 的retainCount的值是1
self.person = per;
在self.person 時,如果是assign,person的 retainCount的值不變,仍為1
若是:retain person的retainCount的值加1,變為2
若是:copy person的retainCount值不變,仍為1
30、實用sql語句查詢出省名以“湖”開頭,右邊為“436001”所在的市區
SELECT *FROM CITYS WHERE PROVINCE_NAME LIKE ‘湖%’ AND POST_CODE = 436001;
31、打印結果為多少
int a[5] = {1,2,3,4,5};?
int *ptr = (int *)(&a+1);
NSLog(@"%d,%d",*(a + 1),*(ptr - 1));
打印結果為: 2,5
1.*(a+1)=a[0+1]=a[1]=2
2.&a表示對數組取地址,&a+1表示a[5]后面一個地址,(ptr-1)表示對當前數組元素地址向前移動一位,并取值,故等于a[4]=5
32、用預處理指令#define聲明一個常數,用以表明1年中有多少秒(忽略閏年問題)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
33、簡述內存分區情況
1)代碼區:存放函數二進制代碼
2)數據區:系統運行時申請內存并初始化,系統退出時由系統釋放。存放全局變量、靜態變量、常量
3)堆區:通過malloc等函數或new等操作符動態申請得到,需程序員手動申請和釋放
4)棧區:函數模塊內申請,函數結束時由系統自動釋放。存放局部變量、函數參數
34、const char *p;? charconst*p;? char*const p;? const char* const p;四個修飾指針有什么區別
1)定義了一個指向不可變的字符串的字符指針
2)和(1)一樣
3)定義了一個指向字符串的指針,該指針值不可改變,即不可改變指向
4)定義了一個指向不可變的字符串的字符指針,且該指針也不可改變指向
35、OC中加號方法與減號的區別?
加號方法是類方法,屬于靜態方法
減號方法是實例方法必須由類的實例來調用
36、ViewController 的 loadView, viewDidLoad,viewDidUnload 分別是在什么時候調用的?在自定義ViewController的時候這幾個函數里面應該做什么工作?
viewDidLoad在view 從nib文件初始化時調用,loadView在controller的view為nil時調用。此方法在編程實現view時調用,view 控制器默認會注冊memory warning notification,當view controller的任何view 沒有用的時候,viewDidUnload會被調用,在這里實現將retain 的view release,如果是retain的IBOutlet view 屬性則不要在這里release,IBOutlet會負責release 。
37、有哪幾種手勢通知方法、寫清楚方法名
-(void)touchesBegan:(NSSet*)touchedwithEvent:(UIEvent*)event;
-(void)touchesMoved:(NSSet*)touched withEvent:(UIEvent*)event;
-(void)touchesEnded:(NSSet*)touchedwithEvent:(UIEvent*)event;
-(void)touchesCanceled:(NSSet*)touchedwithEvent:(UIEvent*)event;
38、id 聲明的對象有什么特性?
id 是個很重要的類型,是個可以指向任何類型的指針或者可以理解為指向任何未知類型的指針。
39、獲取項目根路徑,并在其下創建一個名稱為userData 的目錄
// 獲取根路徑
NSArray *paths=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString *documentsDirectory = [paths objectAtIndex:];
// 創建文件系統管理器
NSFileManager *fileManager = [[NSFileManageralloc] init];
// 判斷userData 目錄是否存在
if(![fileManagerfileExistsAtPath:[NSStringstringWithFormat:@"%@/userData",documentsDirectory]]) {
// 不存在, 創建一個userData目錄
[fileManagercreateDirectoryAtPath:[NSStringstringWithFormat:@"%@/userData",documentsDirectory]withIntermediateDirectories:falseattributes:nilerror:nil];
}
40、tableView 的重用機制
UITableView 通過重用單元格來達到節省內存的目的: 通過為每個單元格指定一個重用標識符(reuseIdentifier),即指定了單元格的種類,以及當單元格滾出屏幕時,允許恢復單元格以便重用.對于不同種類的單元格使用不同的ID,對于簡單的表格,一個標識符就夠了.
41、用變量a 給出下面的定義
a)? ? 一個整型
b)? ? 一個指向整型數的指針
c)? ? 一個指向指針的的指針,它指向的指針是指向一個整型數
d)? ? 一個有10 個整型數的數組
e)? ? 一個有10 個指針的數組,該指針是指向一個整型數的
f)? ? 一個指向有10 個整型數數組的指針
g)? ? 一個指向函數的指針,該函數有一個整型參數并返回一個整型數
h)? ? 一個有10 個指針的數組,該指針指向一個函數,該函數有一個整型參數并返回一個整型數
a)? ? int a;
b)? ? int *a;
c)? ? int **a;
d)? ? int a[10]
e)? ? int *a[10];
f)? ? int (*a)[10];
g)? ? int (*a)(int);
i)? ? int (*a[10])(int);
42、用NSLog 函數輸出一個浮點類型,結果四舍五入,并保留一位小數
NSLog(@”%0.1f”,4.4324);
43、switch 語句 if 語句區別與聯系
均表示條件的判斷,switch語句表達式只能處理的是整型、字符型和枚舉類型,而選擇流程語句則沒有這樣的限制。但switch語句比選擇流程控制語句效率更高。
44、對象可以被copy的條件
只有實現了NSCopying和NSMutableCopying協議的類的對象才能被拷貝,分為不可變拷貝和可變拷貝,
NSCopying協議方法為:
- (id)copyWithZone:(NSZone *)zone
{
Person *person = [[[Person class] allocWithZone:zone] init];
person.age = self.age;
person.name = self.name;
return person;
}
45、UITableViewCell上有個UILabel,顯示NSTimer實現的秒表時間,手指滾動cell過程中,label是否刷新,為什么?
這是否刷新取決于timer加入到Run Loop中的Mode是什么。Mode主要是用來指定事件在運行循環中的優先級的,分為:
NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默認,空閑狀態
UITrackingRunLoopMode:ScrollView滑動時會切換到該Mode
UIInitializationRunLoopMode:run loop啟動時,會切換到該mode
NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
蘋果公開提供的Mode有兩個:
NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
NSRunLoopCommonModes(kCFRunLoopCommonModes)
在編程中:如果我們把一個NSTimer對象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主運行循環中的時候, ScrollView滾動過程中會因為mode的切換,而導致NSTimer將不再被調度。當我們滾動的時候,也希望不調度,那就應該使用默認模式。但是,如果希望在滾動時,定時器也要回調,那就應該使用common mode。
46、有a、b、c、d 4個異步請求,如何判斷a、b、c、d都完成執行?如果需要a、b、c、d順序執行,該如何實現?
對于這四個異步請求,要判斷都執行完成最簡單的方式就是通過GCD的group來實現:
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, ^{ /*任務a */ });
dispatch_group_async(group, queue, ^{ /*任務b */ });
dispatch_group_async(group, queue, ^{ /*任務c */ });
dispatch_group_async(group, queue, ^{ /*任務d */ });
dispatch_group_notify(group,dispatch_get_main_queue(), ^{ // 在a、b、c、d異步執行完成后,會回調這里});
當然,我們還可以使用非常老套的方法來處理,通過四個變量來標識a、b、c、d四個任務是否完成,然后在runloop中讓其等待,當完成時才退出runloop。但是這樣做會讓后面的代碼得不到執行,直到Run loop執行完畢。
解釋:要求順序執行,那么可以將任務放到串行隊列中,自然就是按順序來異步執行了。
47、使用block有什么好處?使用NSTimer寫出一個使用block顯示(在UILabel上)秒表的代碼
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
repeats:YES
callback:^() {
weakSelf.secondsLabel.text = ...
}
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
48、一個view已經初始化完畢,view上面添加了n個button,除用view的tag之外,還可以采用什么辦法來找到自己想要的button來修改button的值
第一種:如果是點擊某個按鈕后,才會刷新它的值,其它不用修改,那么不用引用任何按鈕,直接在回調時,就已經將接收響應的按鈕給傳過來了,直接通過它修改即可。
第二種:點擊某個按鈕后,所有與之同類型的按鈕都要修改值,那么可以通過在創建按鈕時將按鈕存入到數組中,在需要的時候遍歷查找。
49、TCP連接的三次握手
第一次握手:客戶端發送syn包(syn=j)到服務器,并進入SYN_SEND狀態,等待服務器確認;
第二次握手:服務器收到syn包,必須確認客戶的SYN(ack=j+1),同時自己也發送一個SYN包,即SYN+ACK包,此時服務器進入SYN+RECV狀態;
第三次握手:客戶端收到服務器的SYN+ACK包,向服務器發送確認包ACK(ack=k+1),此發送完畢,客戶端和服務器進入ESTABLISHED狀態,完成三次狀態。
50、Scoket連接和HTTP連接的區別:
HTTP協議是基于TCP連接的,是應用層協議,主要解決如何包裝數據。Socket是對TCP/IP協議的封裝,Socket本身并不是協議,而是一個調用接口(API),通過Socket,我們才能使用TCP/IP協議。
HTTP連接:短連接,客戶端向服務器發送一次請求,服務器響應后連接斷開,節省資源。服務器不能主動給客戶端響應(除非采用HTTP長連接技術),iPhone主要使用類NSURLConnection。
Socket連接:長連接,客戶端跟服務器端直接使用Socket進行連接,沒有規定連接后斷開,因此客戶端和服務器段保持連接通道,雙方可以主動發送數據,一般多用于游戲.Socket默認連接超時時間是30秒,默認大小是8K(理解為一個數據包大小)。
51、HTTP協議的特點,關于HTTP請求GET和POST的區別
GET和POST的區別:HTTP超文本傳輸協議,是短連接,是客戶端主動發送請求,服務器做出響應,服務器響應之后,鏈接斷開。HTTP是一個屬于應用層面向對象的協議,HTTP有兩類報文:請求報文和響應報文。HTTP請求報文:一個HTTP請求報文由請求行、請求頭部、空行和請求數據4部分組成。HTTP響應報文:由三部分組成:狀態行、消息報頭、響應正文。GET請求:參數在地址后拼接,沒有請求數據,不安全(因為所有參數都拼接在地址后面),不適合傳輸大量數據(長度有限制,為1024個字節)。? GET提交、請求的數據會附在URL之后,即把數據放置在HTTP協議頭中。
以?分割URL和傳輸數據,多個參數用&連接。如果數據是英文字母或數字,原樣發送,
如果是空格,轉換為+,如果是中文/其他字符,則直接把字符串用BASE64加密。POST請求:參數在請求數據區放著,相對GET請求更安全,并且數據大小沒有限制。把提交的數據放置在HTTP包的包體中.GET提交的數據會在地址欄顯示出來,而POST提交,地址欄不會改變。傳輸數據的大小:GET提交時,傳輸數據就會受到URL長度限制,POST由于不是通過URL傳值,理論上書不受限。安全性:POST的安全性要比GET的安全性高;通過GET提交數據,用戶名和密碼將明文出現在URL上,比如登陸界面有可能被瀏覽器緩存。HTTPS:安全超文本傳輸協議(Secure Hypertext Transfer Protocol),它是一個安全通信通道,基于HTTP開發,用于客戶計算機和服務器之間交換信息,使用安全套結字層(SSI)進行信息交換,即HTTP的安全版。
52、網絡七層協議
應用層:
1.用戶接口、應用程序;
2.Application典型設備:網關;
3.典型協議、標準和應用:TELNET、FTP、HTTP
表示層:
1.數據表示、壓縮和加密presentation
2.典型設備:網關
3.典型協議、標準和應用:ASCLL、PICT、TIFF、JPEG|MPEG
4.表示層相當于一個東西的表示,表示的一些協議,比如圖片、聲音和視頻MPEG。
會話層:
1.會話的建立和結束;
2.典型設備:網關;
3.典型協議、標準和應用:RPC、SQL、NFS、X WINDOWS、ASP
傳輸層:
1.主要功能:端到端控制Transport;
2.典型設備:網關;
3.典型協議、標準和應用:TCP、UDP、SPX
網絡層:
1.主要功能:路由、尋址Network;
2.典型設備:路由器;
3.典型協議、標準和應用:IP、IPX、APPLETALK、ICMP;
數據鏈路層:
1.主要功能:保證無差錯的疏忽鏈路的data link;
2.典型設備:交換機、網橋、網卡;
3.典型協議、標準和應用:802.2、802.3ATM、HDLC、FRAME RELAY;
物理層:
1.主要功能:傳輸比特流Physical;
2.典型設備:集線器、中繼器
3.典型協議、標準和應用:V.35、EIA/TIA-232.
53、對NSUserDefaults的理解
NSUserDefaults:系統提供的一種存儲數據的方式,主要用于保存少量的數據,默認存儲到library下的Preferences文件夾。
54、SDWebImage原理
從內存中(字典)找圖片(當這個圖片在本次程序加載過),找到直接使用;
從沙盒中找,找到直接使用,緩存到內存。
從網絡上獲取,使用,緩存到內存,緩存到沙盒。
55、@synthesize、@dynamic的理解
@synthesize是系統自動生成getter和setter屬性聲明;@synthesize的意思是,除非開發人員已經做了,否則由編譯器生成相應的代碼,以滿足屬性聲明;
@dynamic是開發者自已提供相應的屬性聲明,@dynamic意思是由開發人員提供相應的代碼:對于只讀屬性需要提供setter,對于讀寫屬性需要提供 setter 和getter。查閱了一些資料確定@dynamic的意思是告訴編譯器,屬性的獲取與賦值方法由用戶自己實現, 不自動生成。
56、UIViewController的完整生命周期
-[ViewController initWithNibName:bundle:];
-[ViewController init];
-[ViewController loadView];
-[ViewController viewDidLoad];
-[ViewController viewWillAppear:];
-[ViewController viewDidAppear:];
-[ViewController viewWillDisappear:];
-[ViewController viewDidDisappear:];
57、#define定義的宏和const定義的常量有什么區別?
#define定義宏的指令,程序在預處理階段將用#define所定義的內容只是進行了替換。因此程序運行時,常量表中并沒有用#define所定義的宏,系統并不為它分配內存,而且在編譯時不會檢查數據類型,出錯的概率要大一些。
const定義的常量,在程序運行時是存放在常量表中,系統會為它分配內存,而且在編譯時會進行類型檢查。
#define定義表達式時要注意“邊緣效應”,例如如下定義:
#define N 2 + 3 // 我們預想的N值是5,我們這樣使用N
inta = N/ 2;? // 我們預想的a的值是2.5,可實際上a的值是3.5
58、TCP和UDP的區別是什么
TCP:面向連接、傳輸可靠(保證數據正確性,保證數據順序傳輸)、用于傳輸大量數據(流模式)、速度慢,建立連接需要開銷較多(時間,系統資源)。
UDP:面向非連接、傳輸不可靠、用于傳輸少量數據(數據包模式)、速度快,傳輸的是報文。
59、MD5和Base64的區別是什么,各自使用場景是什么?
MD5:是一種不可逆的摘要算法,用于生成摘要,無法逆著破解得到原文。常用的是生成32位摘要,用于驗證數據的有效性。比如,在網絡請求接口中,通過將所有的參數生成摘要,客戶端和服務端采用同樣的規則生成摘要,這樣可以防篡改。又如,下載文件時,通過生成文件的摘要,用于驗證文件是否損壞。
Base64:屬于加密算法,是可逆的,經過encode后,可以decode得到原文。在開發中,有的公司上傳圖片采用的是將圖片轉換成base64字符串,再上傳。在做加密相關的功能時,通常會將數據進行base64加密/解密。
60、發送10個網絡請求,然后再接收到所有回應之后執行后續操作,如何實現?
從題目分析可知,10個請求要全部完成后,才執行某一功能。比如,下載10圖片后合成一張大圖,就需要異步全部下載完成后,才能合并成大圖。
做法:通過dispatch_group_t來實現,將每個請求放入到Group中,將合并成大圖的操作放在dispatch_group_notify中實現。
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, ^{ /*加載圖片1 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片2 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片3 */ });
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 合并圖片
});
61、對象添加到通知中心中,當通知中心發通知時,這個對象卻已經被釋放了,可能會出現什么問題?
其實這種只是考查對通知的簡單應用。通知是多對多的關系,主要使用場景是跨模塊傳值。當某對象加入到通知中心后,若在對象被銷毀前不將該對象從通知中心中移除,當發送通知時,就會造成崩潰。這是很常見的。所以,在添加到通知中心后,一定要在釋放前移除。
62、這段代碼有什么問題,如何修改
for (int i = 0; i < someLargeNumber; i++) {NSString *string = @”Abc”;
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];NSLog(@“%@”, string);
}
會出現內存泄露
修改之后:
for(int i = 0; i<1000;i++){
NSAutoreleasePool * pool1 = [[NSAutoreleasePool alloc] init];NSString *string = @"Abc";
string = [string lowercaseString];
string = [string stringByAppendingString:@"xyz"];NSLog(@"%@",string);
//釋放池
[pool1 drain];}
63、父類實現深拷貝時,子類如何實現深度拷貝。父類沒有實現深拷貝時,子類如何實現深度拷貝。
深拷貝同淺拷貝的區別:淺拷貝是指針拷貝,對一個對象進行淺拷貝,相當于對指向對象的指針進行復制,產生一個新的指向這個對象的指針,那么就是有兩個指針指向同一個對象,這個對象銷毀后兩個指針都應該置空。深拷貝是對一個對象進行拷貝,相當于對對象進行復制,產生一個新的對象,那么就有兩個指針分別指向兩個對象。當一個對象改變或者被銷毀后拷貝出來的新的對象不受影響。
實現深拷貝需要實現NSCoying協議,實現- (id)copyWithZone:(NSZone *)zone 方法。當對一個property屬性含有copy修飾符的時候,在進行賦值操作的時候實際上就是調用這個方法。
父類實現深拷貝之后,子類只要重寫copyWithZone方法,在方法內部調用父類的copyWithZone方法,之后實現自己的屬性的處理
父類沒有實現深拷貝,子類除了需要對自己的屬性進行處理,還要對父類的屬性進行處理。
64、將一個函數在主線程執行的4種方法
GCD方法,通過向主線程隊列發送一個block塊,使block里的方法可以在主線程中執行。
dispatch_async(dispatch_get_main_queue(), ^{
//需要執行的方法
});
NSOperation 方法
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];? //主隊列
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
//需要執行的方法
}];
[mainQueue addOperation:operation];
NSThread 方法
[self performSelector:@selector(method) onThread:[NSThread mainThread] withObject:nil waitUntilDone:YES modes:nil];
[self performSelectorOnMainThread:@selector(method) withObject:nil waitUntilDone:YES];
[[NSThread mainThread] performSelector:@selector(method) withObject:nil];
RunLoop方法
[[NSRunLoop mainRunLoop] performSelector:@selector(method) withObject:nil];
65、id和NSObject*的區別
id是一個 objc_object 結構體指針,定義是
typedef struct objc_object *id
id可以理解為指向對象的指針。所有oc的對象 id都可以指向,編譯器不會做類型檢查,id調用任何存在的方法都不會在編譯階段報錯,當然如果這個id指向的對象沒有這個方法,該崩潰還是會崩潰的。
NSObject *指向的必須是NSObject的子類,調用的也只能是NSObjec里面的方法否則就要做強制類型轉換。
不是所有的OC對象都是NSObject的子類,還有一些繼承自NSProxy。NSObject *可指向的類型是id的子集。
66、static關鍵字的作用
1、節省內存。靜態變量只存儲一處,但供所有對象使用。
2、它的值是可以更新的。
3、可提高時間效率。只要某個對象對靜態變量更新一次,所有的對象都能訪問更新后的值。
67、RunLoop是什么?
一個RunLoop就是一個事件處理的循環,用來不停的調度工作以及處理輸入時間。使用runloop的目的是讓你的線程在有工作的時候忙于工作,而沒工作的時候處于休眠狀態。主要是是為了減少 cpu無謂的空轉。每個線程都有Runloop, 主線程的Runloop時默認開啟的, 手動開辟的子線程Runloop是默認不開啟 的, 如果需要開啟, 需要調用API[[NSRunloop? currentRunloop] run]開啟.
最常見的需要開啟Runloop的是在子線程里面調用計時器(NSTimer), 如果不開啟runloop循環方法就不能正常執行.
68、字符串替換方法
[string stringByReplacingOccurrencesOfString:@"png" withString: @""]
69、數組和指針的區別
(1)數組可以申請在棧區和數據區;指針可以指向任意類型的內存塊
(2)sizeof作用于數組時,得到的是數組所占的內存大小;作用于指針時,得到的都是4個字節的大小
(3)數組名表示數組首地址,值不可以改變,如不可以將++作用于數組名上;普通指針的值可以改變,如可將++作用于指針上
(4)用字符串初始化字符數組是將字符串的內容拷貝到字符數組中;用字符串初始化字符指針是將字符串的首地址賦給指針,也就是指針指向了該數組
70、在Obj-c中有沒有私有方法?私有變量?一般采用什么方法實現?
objective-c – 類里面的方法只有兩種, 靜態方法和實例方法. 這似乎就不是完整的面向對象了,按照OO的原則就是一個對象只暴露有用的東西. 如果沒有了私有方法的話, 對于一些小范圍的代碼重用就不那么順手了. 在類里面聲名一個私有方法
@interfaceController : NSObject { NSString *something; }
+(void)thisIsAStaticMethod;
-(void)thisIsAnInstanceMethod;
@end
@interfaceController (private)
-(void)thisIsAPrivateMethod;
@end
@private可以用來修飾私有變量
在Objective‐C中,所有實例變量默認都是私有的,所有實例方法默認都是公有的
71、在終端環境下,分別說明4,2,1,0對應的權限是什么
linux系統下文件的權限由三位二進制數表示,從左到右依次表示讀、寫、可執行。0表示不行,1表示行。4對應2進制的100,就是可讀不可寫不可執行。
72、隊列和棧有什么區別
隊列和棧是兩種不同的數據容器。從”數據結構”的角度看,它們都是線性結構,即數據元素之間的關系相同。
隊列是一種先進先出的數據結構,它在兩端進行操作,一端進行入隊列操作,一端進行出列隊操作。
棧是一種先進后出的數據結構,它只能在棧頂進行操作,入棧和出棧都在棧頂操作。
73、HTTP協議中,POST和GET的區別是什么?
答案:1.GET 方法
GET 方法提交數據不安全,數據置于請求行,客戶端地址欄可見;
GET 方法提交的數據大小有限
GET 方法不可以設置書簽
2.POST 方法
POST 方法提交數據安全,數據置于消息主體內,客戶端不可見
POST 方法提交的數據大小沒有限制
POST 方法可以設置書簽
74、鏈表逆序
鏈表逆序就是把一個鏈表按照原來的鏈接順序逆序實現(也就是將頭變成尾,尾變成頭)。
編程思路:其實最關鍵的是先通過原來的鏈接順序找到下個節點,然后再把前個節點反序。
75、假定輸入的字符串中只包含字母和* 號。編寫函數fun,功能是,除了中間和尾部的*號外,
將字符串中其他* 號全部刪除。編寫時,不用c的其他函數。
例:*****A*BC*DEF*G****? ? 結果為:A*BC*DEF*G****
void fun (char *a){
int j=0;
char *p=a;
while (*p==’*')p++;
while (*p){
a[j++]=*p;
p++;
}
a[j]=0;
}
76、objective-c 中的數字對象都有哪些,簡述它們與基本數據類型的區別是什么?
在OC 中NSNumber是數字對象,可以進行拆裝箱操作!
// 將int 轉為NSNumber
NSNumber *num = [NSNumber numberWithInt:123];
// 得到一個int
inttestNum = [numintValue];
77、do-while 與 while-do 的區別?
do-while 先執行循環體,然后判斷條件,如果條件判斷為ture ,則繼續執行循環體,如果判斷為false,則不執行循環體
while-do 是先判斷條件是否正確,若正確則執行循環體,若不正確則不執行循環體。
所以do-while 至少循環一次,而while-do有可能一次也不循環。
78、類變量的@protected ,@private,@public,@package,聲明各有什么含義?
@private:作用范圍只能在自身類
@protected:作用范圍在自身類和繼承自己的子類? (默認)
@public:作用范圍最大,可以在任何地方被訪問。
@package:這個類型最常用于框架類的實例變量,同一包內能用,跨包就不能訪問
79、談談你對多線程開發的理解?ios中有幾種實現多線程的方法?
好處:
1.使用線程可以把占據時間長的程序中的任務放到后臺去處理
2.用戶界面可以更加吸引人,這樣比如用戶點擊了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理的進度
3.程序的運行速度可能加快
4·在一些等待的任務實現上如用戶輸入、文件讀寫和網絡收發數據等,線程就比較有用了。
缺點:
1.如果有大量的線程,會影響性能,因為操作系統需要在它們之間切換。
2.更多的線程需要更多的內存空間。
3.線程的中止需要考慮其對程序運行的影響。
4.通常塊模型數據是在多個線程間共享的,需要防止線程死鎖情況的發生。
實現多線程的方法:NSObject類方法、NSThread、NSOperation、GCD
80、假設有一個字符串aabcad,請寫一段程序,去掉字符串中不相鄰的重復字符串,即上述字符串處理之后的輸出結果為:aabcd
1、NSMutableString * str = [[NSMutableString alloc]initWithFormat;@“aabcad”];
for (int i = 0 ,i < str.length - 1 ;i++){
? ? unsigned char a = [str characterAtIndex:i];
? ? for (int j = i + 1 ,j < str.length ,j++){
? ? ? ? unsigned char b = [str characterAtIndex:j];
? ? ? ? if (a == b ){
? ? ? ? ? ? if (j == i + 1){
? ? ? ? ? ? }else{
? ? ? ? ? ? ? ? [str deleteCharactersInRange:NSMakeRange(j, 1)];
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
NSLog(@“%@”,str);
81、ViewController 的 alloc,loadView, viewDidLoad,viewWillAppear,viewDidUnload,dealloc、init分別是在什么時候調用的?在自定義ViewController的時候這幾個函數里面應該做什么工作?
alloc申請內存時調用
loadView加載視圖時調用
ViewDidLoad視圖已經加載后調用
ViewWillAppear視圖將要出現時調用
ViewDidUnload視圖已經加載但沒有加載出來調用
dealloc銷毀該視圖時調用
init視圖初始化時調用
82、應用如何找到最合適的控件來處理事件?
1.首先判斷主窗口(keyWindow)自己是否能接受觸摸事件
2.判斷觸摸點是否在自己身上
3.子控件數組中從后往前遍歷子控件,重復前面的兩個步驟(所謂從后往前遍歷子控件,就是首先查找子控件數組中最后一個元素,然后執行1、2步驟)
4.view,比如叫做fitView,那么會把這個事件交給這個fitView,再遍歷這個fitView的子控件,直至沒有更合適的view為止。
5.如果沒有符合條件的子控件,那么就認為自己最合適處理這個事件,也就是自己是最合適的view
83、事件的傳遞和響應的區別:
事件的傳遞是從上到下(父控件到子控件),事件的響應是從下到上(順著響應者鏈條向上傳遞:子控件到父控件。
84、簡述你對UIView UIWindow 和CALayer的理解
UIView和CALayer都是源自NSObject。
1、UIView的繼承結構為:UIResponder:NSObject。可以看出UIView的直接父類為UIResponder類。
可見UIResponder是用來響應事件的,也就是說UIView可以響應用戶事件。
2.CALayer的繼承結構:NSObject
直接從NSObject繼承,因為缺少了UIResponder類,所以CALayer不能響應任何的用戶事件。
它們分別所屬的框架
1.UIView是在/System/Library/Frameworks/UIKit.framework中定義的。
我們都知道UIKit主要是用來構建用戶界面并且是可以響應事件的。
2.CALayer是在/System/Library/Frameworks/QuartzCore.framework定義的。而且CALayer作為一個低級的可以承載繪制內容的底層對象出現在該框架中。
綜上來看UIView與CALayer的最大區別在于UIView可以響應用戶事件,而CALayer不可以。UIView側重于對顯示內容的管理,CALayer側重于對內容的繪制。
由此可見UIView確實是CALayer 的高級封裝。
UIView和CALayer相互依賴,UIView依賴于CALayer提供的內容,CALayer依賴UIView提供的容器來顯示繪制的內容。但歸根到底CALayer是這一切的基礎,如果沒有CALayer,UIView自身也不會存在,UIView是一個特殊的CALayer的實現,添加了響應事件的能力。
UIwindow是UIView的子類,UIWindow的主要作用:一是提供一個區域來顯示UIView,二是將事件(event)的分發給UIView,一個應用基本上只有一個UIWindow.
iOS程序啟動完畢后,創建的第一個視圖控件就是UIWindow,接著創建控制器的view,最后將控制器的view添加到UIWindow上,于是控制器的view就顯示在屏幕上了。一個iOS程序之所以能顯示到屏幕上,完全是因為它有UIWindow。即沒有UIWindow,就看不見任何UI界面。
85、簡述聲明一個屬性時,使用copy與strong的區別
1) 當原字符串是NSString時,字符串是不可變的,不管是Strong還是Copy屬性的對象,都是指向原對象,Copy操作只是做了次淺拷貝。
2) 當原字符串是NSMutableString時,Strong屬性只是增加了原字符串的引用計數,而Copy屬性則是對原字符串做了次深拷貝,產生一個新的對象,且Copy屬性對象指向這個新的對象,且這個Copy屬性對象的類型始終是NSString,而不是NSMutableString,因此其是不可變的。
3) 這里還有一個性能問題,即在原字符串是NSMutableString,Strong是單純的增加對象的引用計數,而Copy操作是執行了一次深拷貝,所以性能上會有所差異(雖然不大)。如果原字符串是NSString時,則沒有這個問題。
所以,在聲明NSString屬性時,到底是選擇strong還是copy,可以根據實際情況來定。不過,一般我們將對象聲明為NSString時,都不希望它改變,所以大多數情況下,我們建議用copy,以免因可變字符串的修改導致的一些非預期問題。
86、objc中的類方法和實例方法有什么區別
實例方法:實例出的對象所用的方法,原理是向某個對象發送一條消息,如果對象中有相應的消息就會做出回應,OC用的就是這種消息模式.
類方法:也叫靜態方法,不需要申明一個對象,可以直接調用,一般是有返回值的,其主要作用就是返回一個對應的實例(如數組,字符串或者就是本類的一個對象等),
類方法
類方法屬于類對象
類方法只能通過類對象調用
類方法中的self是類對象
類方法可以調用其他類方法
類方法中不能訪問成員變量
類方法不能直接調用對象方法
實例方法
實例方法是屬于實例對象的
實例方法只能呢通過實例對象調用
實例方法中的self是實例對象
實例方法中可以訪問成員變量
實例方法中直接調用實例方法
實例方法中也可以調用類方法(通過類名)
87、如果gcd創建3個任務,如何取消最后一個
GCD原生并不支持取消操作。
dispatch_suspend函數也只能暫停開啟新的未執行的block,已經處于執行中的block是無法暫停的。
但是,通過參考NSOperation的cancel機制,你只要加一個外邊變量,用于標記block是否需要取消。然后block中通過及時的檢測這個外部變量的狀態,當發現需要取消時,停止block中的后續操作,釋放資源。就能達到及時取消block的目的。這里有個例子:
https://github.com/Tinghui/HUIGCDDispatchAsync
88、請簡述AFNetWorking的實現原理
NSURLConnection + NSOperation
NSURLConnection 是 Foundation URL 加載系統的基石。一個 NSURLConnection 異步地加載一個NSURLRequest 對象,調用 delegate 的 NSURLResponse / NSHTTPURLResponse 方法,其 NSData 被發送到服務器或從服務器讀取;delegate 還可用來處理 NSURLAuthenticationChallenge、重定向響應、或是決定 NSCachedURLResponse 如何存儲在共享的 NSURLCache 上。
NSOperation 是抽象類,模擬單個計算單元,有狀態、優先級、依賴等功能,可以取消。
AFNetworking 的第一個重大突破就是將兩者結合。AFURLConnectionOperation 作為 NSOperation 的子類,遵循 NSURLConnectionDelegate 的方法,可以從頭到尾監視請求的狀態,并儲存請求、響應、響應數據等中間狀態。
89、下面的代碼輸出什么?
@implementation Son : Father
- (id)init
{
self = [super init];
if (self) {
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
2016-05-13 17:52:51.694 Test[12816:262134] Son
2016-05-13 17:52:51.696 Test[12816:262134] Son
原因:調用父類初始化的時候,是不看指針看對象的,因此誰調用super誰就是super的擁有者
90、SDWebImage的原理
1.入口
setImageWithURL:placeholderImage:options: 會先把placeholderImage展示,然后 SDWebImageManager根據URL開始處理圖片.
2.進入
SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交給SDImageCache從緩存查找圖片是否已經下載 :
通過: queryDiskCacheForKey:delegate:userInfo:.
3.先從內存圖片緩存查找是否有圖片,如果內存中已經有圖片緩存SDWebImageDelegate回調imageCache:didFindImage:ForKey:userInfo: 到SDWebImageManager
4.SDWebImageManagerDelegate回調
webImageManager:didFinishWithImage:
到UIImageView+WebCache等前端展示圖片
5.如果內存緩存中沒有,生成NSInvocationOperation添加到隊列開始從硬盤查找圖片是否已經緩存。
6.根據 URLKey 在硬盤緩存目錄下嘗試讀取圖片文件.這一步是在 NSOperation 進行的操作,所以回主線程進行結果回調.
7.如果上一操作從硬盤讀取到了圖片,將圖片添加到內存緩存中,如果內存空間過小會先清空內存緩存.
SDImageCacheDelegate回調 imageCache:didFindImage:forKey:userInfo: 進而回調展示圖片.
8.如果從硬盤緩存目錄讀取不到圖片,說明所有緩存都不存在該圖片,需要下載圖片,回調imageCache:didNotFindImageForKey:userInfo:。
9.共享或重新生成一個下載器 SDWebImageDownloder開始下載圖片
10.圖片下載由 NSURLConnection來做,實現相關的Delegate來判斷圖片下載中,下載完成和下載失敗.
11.connection:didReceiveData:中利用 ImageIO 做了按圖片下載進度加載效果。
12.connectionDidFinishLoading: 數據下載完成后交給 SDWebImageDecoder 做圖片解碼處理。
13.圖片解碼處理在一個 NSOperationQueue 完成,不會拖慢主線程 UI。如果有需要對下載的圖片進行二次處理,最好也在這里完成,效率會好很多。
14.在主線程notifyDelegateOnMainThreadWithInfo:宣告解碼完成,imageDecoder:didFinishDecodingImage:userInfo:回調給 SDWebImageDownloader。
15.imageDownloader:didFinishWithImage: 回調給 SDWebImageManager 告知圖片下載完成。
16.通知所有的 downloadDelegates 下載完成,回調給需要的地方展示圖片。
17.將圖片保存到 SDImageCache 中,內存緩存和硬盤緩存同時保存。寫文件到硬盤也在以單獨 NSInvocationOperation 完成,避免拖慢主線程。
18.SDImageCache 在初始化的時候會注冊一些消息通知,在內存警告或退到后臺的時候清理內存圖片緩存,應用結束的時候清理過期圖片。
19.SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。
20.SDWebImagePrefetcher 可以預先下載圖片,方便后續使用
91、BAD_ACCESS在什么情況下出現?如何調試BAD_ACCESS錯誤?
什么是 EXC_BAD_ACCESS?
不管什么時候當你遇到EXC_BAD_ACCESS這個錯誤,那就意味著你向一個已經釋放的對象發送消息。訪問了野指針,比如對一個已經釋放的對象執行了release、訪問已經釋放對象的成員變量或者發消息。
EXC_BAD_ACCESS的本質
技術層面的解釋有些復雜。在C和Objective-C中,你一直在處理指針。指針無非是存儲另一個變量的內存地址的變量。當您向一個對象發送消息時,指向該對象的指針將會被引用。這意味著,你獲取了指針所指的內存地址,并訪問該存儲區域的值。
當該存儲器區域不再映射到您的應用時,或者換句話說,該內存區域在你認為使用的時候卻沒有使用,該內存區域是無法訪問的。 這時內核會拋出一個異常( EXC ),表明你的應用程序不能訪問該存儲器區域(BAD ACCESS) 。
總之,當你碰到EXC_BAD_ACCESS ,這意味著你試圖發送消息到的內存塊,但內存塊無法執行該消息。但是,在某些情況下, EXC_BAD_ACCESS是由被損壞的指針引起的。每當你的應用程序嘗試引用損壞的指針,一個異常就會被內核拋出。
調試EXC_BAD_ACCESS
1.重寫object的respondsToSelector方法,現實出現EXEC_BAD_ACCESS前訪問的最后一個object
2.通過 Zombie
3.設置全局斷點快速定位問題代碼所在行
4.Xcode 7 已經集成了BAD_ACCESS捕獲功能:Address Sanitizer。 用法如下:在配置中勾選?Enable Address Sanitizer
92、找錯誤(1)
char * GetMemory(void){
char p[] = "Hello World";
return p;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
char * str = NULL;
str = GetMemory();
printf("%s\n",str);
}
return 0;
}
錯誤為:
char p[] = "Hello World";
return p;//不能返回棧地址,因為棧空間自動釋放,應該返回棧空間的數據
正確應該為:
char *p = "Hello World";
93、找錯誤(2)
void GetMemory(char **p, int num){
*p = (char *)malloc(num);
}
void Test(void){
char * str = NULL;
GetMemory(&str, 100);
strcpy(str, "Hello");
printf(str);
}
// 堆空間需要手動釋放,申請了堆內存時也要判斷是否申請成功
char * str = NULL;
GetMemory(&str, 100);
if(str) {
strcpy(str, "Hello");
printf("%s",str);
free(str);
str = NULL;
}
94、寫出下列兩個屬性的Setter方法
@property (nonatomic, retain) NSString * name;
@property (nonatomic, copy) NSString * name;
- (void) setName:(NSString *) name {
if( _name != name) {
?[_name release];
_name = [name retain];
}
}
- (void) setName:(NSString *) name {
_name = [name copy];
}
retain修飾的屬性setter方法的實現步驟:
1:判斷新值與舊值是否相等,如果不等執行以下操作
2:將舊值執行一次release操作(舊值release)
3:再將新值執行一次retain操作再賦給舊值(新值retain再賦值)
copy修飾的屬性:如果要保證返回的是一個不可變的版本就要將新值執行一次copy操作
95、類別和繼承什么區別
1.類別是對方法的擴展,不能添加成員變量。繼承可以在原來父類的成員變量的基礎上,添加新的成員變量
2.類別只能添加新的方法,不能修改和刪除原來的方法。繼承可以增加、修改和刪除方法。
3.類別不提倡對原有的方法進行重載。繼承可以通過使用super對原來方法進行重載。
4.類別可以被繼承,如果一個父類中定義了類別,那么其子類中也會繼承此類別。
96、線程與進程的區別和聯系
進程: 進程是一個“執行中的程序”。程序是一個沒有生命的實體,只有處理器賦予程序生命時,它才能成為一個活動的實體,我們稱其為進程。進程是一個具有獨立功能的程序關于某個數據集合的一次運行活動。它可以申請和擁有系統資源,是一個動態的概念,是一個活動的實體。它不只是程序的代碼,還包括當前的活動,通過程序計數器的值和處理寄存器的內容來表示。
線程: 通常在一個進程中可以包含若干個線程,它們可以利用進程所擁有的資源。在引入線程的操作系統中,通常都是把進程作為分配資源的基本單位,而把線程作為獨立運行和獨立調度的基本單位。由于線程比進程更小,基本上不擁有系統資源,故對它的調度所付出的開銷就會小得多,能更高效的提高系統內多個程序間并發執行的程度。
線程與進程的區別:
a.地址空間和其它資源:進程間相互獨立,同一進程的各線程間共享。某進程內的線程在其它進程不可見。
b.通信:進程間通信IPC,線程間可以直接讀寫進程數據段(如全局變量)來進行通信——需要進程同步和互斥手段的輔助,以保證數據的一致性。
c.調度和切換:線程上下文切換比進程上下文切換要快得多。
d.在多線程OS中,進程不是一個可執行的實體
97、數組去重有哪些方式
1)、利用NSDictionary的AllKeys(AllValues)方法
NSMutableDictionary *dic = [[NSMutableDictionary alloc]initWithCapacity:0];
for(NSString *str in dataArray){
[dic setValue:str forKey:str];
}
2)、利用NSSet的AllObjects方法
NSSet *set = [NSSet setWithArray:dataArray];
NSLog(@"%@",[set allObjects]);
3)、利用數組的containsObject來去除
NSMutableArray *listAry = [[NSMutableArray alloc]init];
for (NSString *str in dataArray) {
if (![listAry containsObject:str]) {
[listAry addObject:str];
}
}
98、同時實現一個property 屬性的setter 和 getter的方法,調用_ivar會報錯
在.h或者.m文件中用@property聲明一個屬性時。如果同時重寫getter和setter方法,會報“該變量沒有定義的錯誤”。
解決辦法:.m文件中需要加上:
@synthesize propertyName = _propertyName;
原因:因為@property默認給該屬性生成getter和setter方法,當getter和setter方法同時被重寫時,則系統就不會自動生成getter和setter方法了,也不會自動幫你生成_num變量,所以不會識別。
小知識:聲明的property如果沒有特意指定synthesize的話,那么Objective-C就會自動的給你聲明一個_開頭的實例變量。
_xxx訪問的是xxx的地址。self.xxx訪問的是xxx的getter。這兩者并不是完全等價的,self.xxx是用objc_msgSend發消息,_xxx或者self->xxx則是直接訪問內存地址,一般建議在init里面用_xxx,其他地方用self.xxx.
99、@property (copy) NSMutableArray *array;這個寫法會有什么問題?
即使在MRC時代,我們通常會寫成retain,在ARC時代,我們會寫成strong,所以copy會略顯奇怪
嘗試分析一下,copy為內容拷貝,和源對象變成2個擁有相同內容的不同指針,互不影響.
并且因為調用copy方法,所以該array屬性在RunTime的時候,實際上為NSArray,即無法調用add等方法,但是編譯期調用是合法的,所以可能會造成crash.
100、@property的本質是什么?ivar、getter、setter是如何生成并添加到這個類的
@property = ivar + getter + setter
“屬性”(@property)有兩大概念:實例變量(ivar)、存取方法(access method = getter + setter)。
“屬性” (property)作為 Objective-C 的一項特性,主要的作用就在于封裝對象中的數據。 objective-c 對象通常會把其所需要的數據保存為各種實例變量。實例變量一般通過“存取方法”(access method)來訪問。
ivar、 getter、setter是如何生成并添加到這個類的?
自動合成(autosynthesis)
完成屬性定以后,編譯器會自動編寫訪問這些屬性所需的方法,此過程叫做“自動合成”(autosynthesis)。需要強調的是,這一過程是在編譯期間執行的。除了生成方法代碼getter、setter之外,編譯器還要自動向類中添加適當的類型的實例變量,并且屬性名前面添加下劃線。