1、使用NSTimer,需要注意什么?
這里按我的理解就是,主要是涉及runloop了。 一是拖動scrollView的時候,runloop處于EventTracking模式,創建的計時器默認是添加在defalut下,而runloop 有一個特點只會處理當前mode下的輸入源事件和計時器事件, 所以當scrollView滾動的時候,計時器的事件會導致無法觸發,這種情況下,只需需將計時器添加到當前runloop下的common mode下即可;二是,子線程的計時器事件,需要主動添加這句[[NSRunLoop currentRunLoop] run]才能觸發, 子線程的運行循環默認是沒有開啟的
2、self.name = nil 和[_name release]的區別
前者使用property的點操作符,也就相當于調用了name對應的set method,和這句是一樣的:[self setName:nil];
而后者沒有通過property,直接訪問了成員變量,調用了它的release方法。
對于set method來說,用synthesize來讓系統幫我們生成的set方法和如下的類似:
- (void)setAbc:(id)newAbc
{
if(_abc != newAbc){
[_abc release];
_abc = [newAbc retain]; //是retain還是copy取決于你property聲明時的attributes
}
}
如果新值和成員相等,就不需要進行重復的賦值了,不等的話,需要把新值賦給成員,同時,成員_abc原來的內容就不需要了,這里要先調用release進行釋放。(這個具體的原因在那本講Objective-C的書中寫的很清楚,請查看)。
因此在這里,調用self.abc = nil;
就等于掉了[_abc release];? 和_abc = nil;
self.abc = nil;和[_abc release]; 都不一定釋放對象,因為該對象還可能被別的引用,這里的操作的意圖就是:別的地方用沒用_abc我不知道,在這里的_abc我不用了。
在用retain或者copy的property attributes的時候,self.abc = nil;等于如下語句:
if(_abc!= nil)
{
[_abc release];
_abc = nil; //message sent to nil returns nil.
}
所以用起來更簡單一點。
3、@property中一些屬性關鍵字的作用, 默認下分別是哪些關鍵字?
strong? ? ? ? ? ? ? 釋放舊對象將舊對象的值賦予輸入對象,再提高輸入對象的索引計數為1,此關鍵字經常使用。
weak? ? ? ? ? ? ? ? 不增加引用計數,不持有對象,因此也不能決定對象釋放? 對比assign 的一個好處是,當對象消失時指針自動歸為nil
assign? ? ? ? ? ? ? 適用于基礎數據類型(NSInteger CGFloat...)不增加引用計數
copy? ? ? ? ? ? ? ? 建立一個索引計數為1 的對象然后釋放舊對象 此屬性只對那些實行了NSCopying協議的對象類型有效(NSString , Block)
atomic? ? ? ? ? ? 和 nonatomic用來決定編譯器生成的getter和setter是否為原子操作,atomic 設置成員變量的@property屬性時? 默認為是atomic 提供線程安全。
nonatomic? ? ? 非原子性訪問對于屬性賦值的時候不加鎖,多線程并發訪問會提高性能,如果不加此屬性則默認是兩個訪問方法都為原子型事務訪問。
readonly? ? ? ? ? 此標記說明屬性是只讀的
readwrite? ? ? ? ? 此標記說明屬性會被當成讀寫的? 這也是默認的屬性
unsafe_unretained? ? ? ? ? 跟weak類似,聲明一個弱引用,但是當引用計數為0時,變量不會自動設置為nil(ios5加入的 我基本沒用過)
3.1、屬性關鍵字對比
copy : strong? ? ??
1.copy建立一個同樣的對象 比如一個NSString 地址為0x1212 內容 @“121”? copy到另一個NSString上? 地址改變 而內容不變 新對象retain +1 就對象不變? 也就是說copy時內容拷貝? 而 strong不是他只是單純的生命一個變量 retain為1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?2.strong的set方法時淺拷貝? copy的set為深拷貝
assign : weak? ??
?在MRC環境下使用使用assign實現基本類型.? ? ? ? ? 在ARC環境下,weak相當于assign? 個人感覺weak比assign要強大的地方在 weak可以避免循環引用 , 同時當對象不存在時候可以將其置為nil
4、sql語句常用的增刪改查
5、KVO的內部實現
KVO是基于runtime機制實現的
當某個類的屬性對象第一次被觀察時,系統就會在運行期動態地創建該類的一個派生類,在這個派生類中重寫基類中任何被觀察屬性的setter 方法。派生類在被重寫的setter方法內實現真正的通知機制
如果原類為Person,那么生成的派生類名為NSKVONotifying_Person
每個類對象中都有一個isa指針指向當前類,當一個類對象的第一次被觀察,那么系統會偷偷將isa指針指向動態生成的派生類,從而在給被監控屬性賦值時執行的是派生類的setter方法
鍵值觀察通知依賴于NSObject 的兩個方法: willChangeValueForKey: 和 didChangevlueForKey:;在一個被觀察屬性發生改變之前, willChangeValueForKey:一定會被調用,這就 會記錄舊的值。而當改變發生后,didChangeValueForKey:會被調用,繼而 observeValueForKey:ofObject:change:context: 也會被調用。
補充:KVO的這套實現機制中蘋果還偷偷重寫了class方法,讓我們誤認為還是使用的當前類,從而達到隱藏生成的派生類
KVC是OC特有的,本質是在運行時動態的給對象發送setValue:forKey 消息,設置數值 -調用super.init 保證對象已經被創建完成 .當給對象發送setValue:forKey 消息時要判斷對象是否存在key所對應的屬性,直接賦值 如果沒有就調用undefinedKey(默認崩潰,需要重寫)? ? setValue:forKey的調用順序首先會尋找set方法,如果沒有就去找__isis順序尋找,如何還沒找到就調用undefinedKey(默認崩潰,需要重寫). ValueForKey的調用順序? 按照get,is順序尋找,如果沒有找到按照__isis順序尋找,如何還沒找到就調用undefinedKey(默認崩潰,需要重寫).
6、category 和 extension 的區別
分類有名字,類擴展沒有分類名字,是一種特殊的分類
分類只能擴展方法(屬性僅僅是聲明,并沒真正實現),類擴展可以擴展屬性、成員變量和方法
7、define 和 const常量有什么區別?
define在預處理階段進行替換,const常量在編譯階段使用
宏不做類型檢查,僅僅進行替換,const常量有數據類型,會執行類型檢查
define不能調試,const常量可以調試
define定義的常量在替換后運行過程中會不斷地占用內存,而const定義的常量存儲在數據段只有一份copy,效率更高
define可以定義一些簡單的函數,const不可以
8、block和weak修飾符的區別?
__block不管是ARC還是MRC模式下都可以使用,可以修飾對象,也可以修飾基本數據類型
__weak只能在ARC模式下使用,只能修飾對象(NSString),不能修飾基本數據類型
block修飾的對象可以在block中被重新賦值,weak修飾的對象不可以
9、static關鍵字的作用
函數(方法)體內 static 變量的作用范圍為該函數體,該變量的內存只被分配一次,因此其值在下次調用時仍維持上次的值;
在模塊內的 static 全局變量可以被模塊內所用函數訪問,但不能被模塊外其它函數訪問;
在模塊內的 static 函數只可被這一模塊內的其它函數調用,這個函數的使用范圍被限制在聲明 它的模塊內;
在類中的 static 成員變量屬于整個類所擁有,對類的所有對象只有一份拷貝;
在類中的 static 成員函數屬于整個類所擁有,這個函數不接收 this 指針,因而只能訪問類的static 成員變量
10、堆和棧的區別
從管理方式來講
對于棧來講,是由編譯器自動管理,無需我們手工控制;
對于堆來說,釋放工作由程序員控制,容易產生內存泄露(memory leak)
從申請大小大小方面講
棧空間比較小
堆控件比較大
從數據存儲方面來講
棧空間中一般存儲基本類型,對象的地址
堆空間一般存放對象本身,block的copy等
11、進程和線程的區別和聯系
進程是具有一定獨立功能的程序關于某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位. 線程是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位.線程自己基本上不擁有系統資源,只擁有一點在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源.
一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間可以并發執行.
12、談談instancetype和id的異同
1、相同點
都可以作為方法的返回類型
2、不同點
①instancetype可以返回和方法所在類相同類型的對象,id只能返回未知類型的對象;②instancetype只能作為返回值,不能像id那樣作為參數
13、isKindOfClass和isMemberOfClass的區別
isKindOfClass來確定一個對象是否是一個類的成員,或者是派生自該類的成員
14、Core Data是數據庫么?有哪些重要的類?
Core Data確實不是一個數據庫,只是把表和OC對象進行的映射,當時并不是進進映射那么簡單,底層還是用的Sqlite3進行存儲的,所以Core Data不是數據庫。
有以下6個重要的類:
(1)NSManagedObjectContext(被管理的數據上下文)
操作實際內容(操作持久層)
作用:插入數據,查詢數據,刪除數據
(2)NSManagedObjectModel(被管理的數據模型)
數據庫所有表格或數據結構,包含各實體的定義信息
作用:添加實體的屬性,建立屬性之間的關系
操作方法:視圖編輯器,或代碼
(3)NSPersistentStoreCoordinator(持久化存儲助理)
相當于數據庫的連接器
作用:設置數據存儲的名字,位置,存儲方式,和存儲時機
(4)NSManagedObject(被管理的數據記錄)
相當于數據庫中的表格記錄
(5)NSFetchRequest(獲取數據的請求)
相當于查詢語句
(6)NSEntityDescription(實體結構)
相當于表格結構
15、算法題
二分查找 θ(logn)
遞歸方法
int binarySearch1(int a[] , int low , int high , int findNum)
{
int mid = ( low + high ) / 2;
if (low > high)
return -1;
else
{
if (a[mid] > findNum)
return binarySearch1(a, low, mid - 1, findNum);
else if (a[mid] < findNum)
return binarySearch1(a, mid + 1, high, findNum);
else
return mid;
}
}
非遞歸方法
int binarySearch2(int a[] , int low , int high , int findNum)
{
while (low <= high)
{
int mid = ( low + high) / 2;? //此處一定要放在while里面
if (a[mid] < findNum)
low = mid + 1;
else if (a[mid] > findNum)
high = mid - 1;
else
return mid;
}
return? -1;
}
冒泡排序? θ(n^2)
void bubble_sort(int a[], int n)
{
int i, j, temp;
for (j = 0; j < n - 1; j++)
for (i = 0; i < n - 1 - j; i++) //外層循環每循環一次就能確定出一個泡泡(最大或者最小),所以內層循環不用再計算已經排好的部分
{
if(a[i] > a[i + 1])
{
temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
}
}
}
快速排序? 調用方法? quickSort(a,0,n);? θ(nlogn)
void quickSort (int a[] , int low , int high)
{
if (high < low + 2)
return;
int start = low;
int end = high;
int temp;
while (start < end)
{
while ( ++start < high && a[start] <= a[low]);//找到第一個比a[low]數值大的位子start
while ( --end? > low? && a[end]? >= a[low]);//找到第一個比a[low]數值小的位子end
//進行到此,a[end] < a[low] < a[start],但是物理位置上還是low < start < end,因此接下來交換a[start]和a[end],于是[low,start]這個區間里面全部比a[low]小的,[end,hight]這個區間里面全部都是比a[low]大的
if (start < end)
{
temp = a[start];
a[start]=a[end];
a[end]=temp;
}
//在GCC編譯器下,該寫法無法達到交換的目的,a[start] ^= a[end] ^= a[start] ^= a[end];編譯器的問題
}
//進行到此,[low,end]區間里面的數都比a[low]小的,[end,higt]區間里面都是比a[low]大的,把a[low]放到中間即可
//在GCC編譯器下,該寫法無法達到交換的目的,a[low] ^= a[end] ^= a[low] ^= a[end];編譯器的問題
temp = a[low];
a[low]=a[end];
a[end]=temp;
//現在就分成了3段了,由最初的a[low]樞紐分開的
quickSort(a, low, end);
quickSort(a, start, high);
}