iOS開發核心語言Objective C —— 所有知識點總結 – iPhone手機開發 iPhone軟體開發教學課程

本分享是面向有意向從事iOS開發的夥伴及蘋果產品的發燒友,亦或是已經從事瞭iOS的開發者,想進一步提升者。如果您對iOS開發有極高的興趣,可以與我一起探討iOS開發,一起學習,共同進步。如果您是零基礎,建議您先翻閱我之前分享的iOS開發分分鐘搞定C語言系列,然後在開始Objective C語言的學習,如果您遇到問題也可以與我探討,另外將無償分享自己整理出來的大概400G iOS學習視頻及學習資料,都是幹貨哦!可以新浪微博私信?關註極客James,期待與您的共同學習和探討!!由於時間有限,每天在工作之餘整理的學習分享,難免有不足之處,也希望各路大神指正!

本次整理的內容涵蓋Objective C 語言很多重要問題及細節,非常重要哦!
made by 極客James
這裡寫圖片描述

C和OC對比

OC中主要開發在什麼平臺上的應用程序?
答:可以使用OC開發Mac OS X平臺和iOS平臺的應用程序

OC中新增關鍵字大部分是以什麼開頭?
答:OC中新增關鍵字大部分是以@開頭

OC中新增加瞭那些數據類型?
答:Block類型
指針類型(Class, id類型)
空類型
特殊類型(SEL, nil)

面向對象特性是什麼?
答:繼承性,封裝性,多態性

import和#include有什麼區別?

答:import 的功能和 include一樣, 是將右邊的文件拷貝到當前import的位置.為瞭降低程序員的負擔, 防止重復導入, 避免程序員去書寫 頭文件衛士, 那麼OC給出來一個新的預處理指令import
import優點: 會自動防止重復拷貝

printf和NSLog有什麼區別?
答: NSLog會自動換行
NSLog在輸出內容時會附加一些系統信息
NSLog和printf接收的參數不一樣

Foundation有什麼作用?
答:Foundation.h我們稱之為主頭文件, 主頭文件中又拷貝瞭該工具箱中所有工具的頭文件, 我們隻需要導入主頭文件就可以使用該工具箱中所有的工具, 避免瞭每次使用都要導入一個對應的頭文件

面向對象基本概念

什麼是面向對象?
答:對象是人們要進行研究的任何事物,從最簡單的整數到復雜的飛機等均可看作對象,它不僅能表示具體的事物,還能表示抽象的規則、計劃或事件。

面向對象和面向過程的區別?
答:
1>面向對象是相對面向過程而言
2>面向對象和面向過程都是一種思想
面向過程
強調的是功能行為
關註的是解決問題需要哪些步驟
面向對象
將功能封裝進對象,強調具備瞭功能的對象
關註的是解決問題需要哪些對象

類與對象

什麼是對象?
答:對象是人們要進行研究的任何事物,從最簡單的整數到復雜的飛機等均可看作對象,它不僅能表示具體的事物,還能表示抽象的規則、計劃或事件。

什麼是類?
答:具有相同特性(數據元素)和行為(功能)的對象的抽象就是類。因此,對象的抽象是類,類的具體化就是對象,也可以說類的實例是對象,類實際上就是一種數據類型。

類由幾部分組成?
答: 類(Class) 一個類由3個部分構成
類的名稱:類名
類的屬性:一組包含數據的屬性
類的方法:允許對屬性中包含的數據進行操作的方法

怎麼來定義一個類?書寫類的格式
答:定義類要分為兩部分: 聲明和實現

類的聲明格式
@interface 類名 : 父類名(NSObject)
{
定義實例變量(成員變量,屬性)
}
方法的聲明

@end

類的實現格式
@implementation 類名
方法的具體實現
@end;

5.OC中屬性寫在類中哪個位置?
答:OC類聲明中屬性隻能在寫@interface和@end之間的{}中

6.如何通過類創建對象?書寫創建對象格式
答: 創建對象格式:
類名 *指針名 = [類名 new];

7.實例化對象調用哪個方法?實例化對象做瞭哪3件事?
答:實例化對象調用類方法new
1.給對象分配存儲空間
2.初始化類中的實力變量
3.返回對象內存地址

8.如何訪問對象中的屬性?
答:使用指針訪問
格式: 指針名->_屬性名;

OC方法

方法和函數的區別?
答:
1)OC中的行為和C語言中的函數一樣, 都是用來保存一段特定功能的代碼
C語言中定義一個函數, 分為聲明和實現, 聲明寫在.h中, 實現寫在.c中
OC中定義一個方法, 也分為聲明和實現, 聲明寫在@interface中, 實現寫在@implementation

C語言的函數分為兩種: 內部函數和外部函數
OC中的方法也分為兩種; 類方法和對象方法

怎麼聲明和實現無參無返回值方法的?調用方法的格式?(書寫格式)
答:
方法的聲明格式:

(返回值類型)方法名;
方法的實現格式:

(返回值類型)方法名{
}
調用方法格式:
[對象名 方法名];
或者 [類名 方法名];

小括號在OC方法中有什麼用法?
答:OC方法中的()有特殊的用途, OC方法中的()是用來擴住數據類型的

有參數方法格式是怎樣?
帶一個參數
方法聲明
·- (返回值類型)方法名:(參數類型)參數名;

方法實現
– (返回值類型)方法名:(參數類型)參數名{

}

帶多個參數
方法聲明
– (返回值類型)方法名1:(參數類型)參數名1 方法名2:(參數類型)參數名2;
– (返回值類型)方法名1:(參數類型)參數名1 and方法名2:(參數類型)參數名
– (返回值類型)方法名1:(參數類型)參數名1 :(參數類型)參數名2;
方法實現
– (返回值類型)方法名1:(參數類型)參數名1 方法名2:(參數類型)參數名2{
}

OC類方法

類方法和對象方法的區別?
答:
0). 對象方法以-開頭
類方法以+開頭
1). 對象方法必須用對象調用
類方法必須用類來調用
2).對象方法中可以直接訪問屬性(成員變量)
類方法中不可以直接訪問屬性(成員變量)
3). 類方法和對象方法可以進行相互調用(展示代碼)

類方法的應用場景?
答:
類方法一般用於定義工具方法
字符串查找
文件操作
數據庫操作

isa是什麼數據類型?
答: 類的第0個屬性並不是我們編寫的_age, 而是一個叫做isa的屬性
isa是對象中的隱藏指針,指向創建這個對象的類,占8個字節

方法和函數的區別

函數和方法的區別?
答:
1).函數屬於整個文件, 方法屬於某一個類
方法如果離開類就不行
2).函數可以直接調用, 方法必須用對象或者類來調用
註意: 雖然函數屬於整個文件, 但是如果把函數寫在類的聲明中會不識別
3).不能把函數當做方法來調用, 也不能把方法當做函數來調用

方法有哪些的註意點?
答:

方法可以沒有聲明隻有實現
方法可以隻有聲明沒有實現, 編譯不會報錯, 但是運行會報錯
如果方法隻有聲明沒有實現, 那麼運行時會報:
reason: ‘+[Person demo]: unrecognized selector sent to class 0x100001140’
發送瞭一個不能識別的消息, 在Person類中沒有+開頭的demo方法
reason: ‘-[Person test]: unrecognized selector sent to instance 0x100400000’

常見的錯誤有哪些?
1.隻有類的聲明,沒有類的實現
2.漏瞭@end

@interface和@implementation嵌套
4.成員變量沒有寫在括號裡面
5.方法的聲明寫在瞭大括號裡面
6.成員變量不能在{}中進行初始化、不能被直接拿出去訪問
7.方法不能當做函數一樣調用
8.OC方法隻能聲明在@interface和@end之間,隻能實現在@implementation和@end之間。也就是說OC方法不能獨立於類存在
9.C函數不屬於類,跟類沒有聯系,C函數隻歸定義函數的文件所有
10.C函數不能訪問OC對象的成員
11.低級錯誤:方法有聲明,但是實現的時候寫成瞭函數
12.OC可以沒有@interface同樣可以定義一個類

多文件開發

為什麼要使用多文件?
答:
一個iOS項目可能會有多個人開發,如果多個人同時修改一個文件,那麼就很可能會產生沖突,比如這個增加一個方法,那個人把這方法刪掉瞭。另外就是當把多個人寫功能合並起來的時候,也非常困難,寫到一個文件中,無法順暢的進行團隊合作

OC中如何進行多文件開發?
答:
在工作中,通常把不同的類放到不同的文件中,每個類的聲明和實現分開
聲明寫在.h頭文件中,
實現寫在相應的.m文件中去,
類名是什麼,文件名就是什麼

使用多文件開發有什麼好處?
答:
顯著提高團隊協作的效率
提高程序的開發速度
提高程序的可維護性
提高代碼的可讀性

面向對象特性

:面向對象三大特性有哪些?
答:繼承性,封裝性,多態性

什麼是封裝?封裝的好處?封裝的規范?
答:
封裝: 屏蔽內部實現的細節, 僅僅對外提供共有的方法/接口
好處: 保證數據的安全性,將變化隔離
規范: 一般情況下不會對外直接暴露成員變量, 都會提供一些共有的方法進行賦值
成員變量都需要封裝起來

為什麼要進行封裝?
答:一個類把自己的成員變量暴露給外部的時候,那麼該類就失去對該成員變量的管理權,別人可以任意的修改你的成員變量。

geeter-setter方法

什麼是setter方法?sett方法的書寫格式?
答:setter方法就是給成員變量賦值的方法
格式:
(1) setter方法一定是對象方法
(2) 一定沒有返回值
(3) 一定以set開頭, 並且set後面跟上需要設置的成員變量的名稱去掉下劃線, 並且首字母大寫
(4) 一定有參數, 參數類型一定和需要設置的成員變量的類型一致, 並且參數名稱就是成員變量的名稱去掉下劃線

getter方法就是獲取成員變量值的方法
格式:
(1) getter方法一定是對象方法
(2)一定有返回值, 而且返回值一定和獲取的成員變量的類型一致
(3)方法名稱就是獲取的成員變量的名稱去掉下劃線
(4) 一定沒有參數

成員變量以下劃線開頭有什麼好處?
答:
1.用於區分局部變量/全局變量/形參
2.方便程序編碼, 提高編碼效率

解釋一下什麼是隻讀屬性?什麼是隻寫屬性?可讀可寫的屬性?私有屬性?
答:
一個屬性可以隻有getter方法, 沒有setter方法, 這種屬性我們稱之為隻讀屬性
一個屬性也可以隻有setter方法, 沒有getter方法, 這種屬性我們稱之為隻寫屬性
如果既有setter方法又有getter方法, 那麼這種屬性我們稱之為可讀可寫的屬性
一個屬性也可以沒有getter和setter, 這種屬性我們稱之為私有屬性

點語法和self關鍵字

什麼是點語法?點語法的本質?
答:如果給屬性提供瞭getter和setter方法, 那麼訪問屬性就又多瞭一種訪問方式 , 點語法.
點語法的本質是調用瞭一個類的setter和getter方法

如何使用點語法?
答:
點語法是一個編譯器的特性, 會在程序翻譯成二進制的時候將.語法自動轉換為setter和getter方法
如果點語法在=號的左邊, 那麼編譯器會自動轉換為setter方法
如果點語法在=號的右邊, 或者沒有等號, 那麼編譯器就會自動轉換為getter方法

點語法註意事項?
答:點語法一般用於給成員變量賦值, 如果不是給成員變量賦值一般情況下不建議使用, 但是也可以使用

什麼是成員變量?什麼是對象方法?什麼是類方法?
答:
成員變量:
成員變量是一個實例對象的具體狀態特征,並且這些狀態特征是可以改變的,如張三的年齡,身高,體重等

對象方法:
一個實例對象的行為,比如張三具有吃的行為,張三做出這樣行為的時候,有可能會影響,自身的某些狀態特征,比如張三吃可能會增加張三體重和身高。

類方法:
類方法是某個類的行為,可以直接通過類名調用;如果在類方法中需要使用某些數據,必須通過參數傳入;類方法不能訪問成員變量。

如何使用self?
如果self在對象方法中, 那麼self就代表調用當前對象方法的那個對象
如果self在類方法中, 那麼self就代表調用當前類方法的那個類
總結:
我們隻用關註self在哪一個方法中 , 如果在類方法那麼就代表當前類, 如果在對象方法那麼就代表”當前調用該方法的對象”

self有哪些註意事項?
答:
(1)self會自動區分類方法和對象方法, 如果在類方法中使用self調用對象方法, 那麼會直接報錯
(2)不能在對象方法或者類方法中利用self調用當前self所在的方法

self的有哪些使用場景?
答:
可以用於在對象方法之間進行相互調用
可以用於在類方法之間進行相互調用
可以用於區分成員變量和局部變量同名的情況

繼承基本概念

什麼是繼承?什麼是父類?什麼是子類?如何實現繼承?
答:
1)子類獲得父類的特性就是繼承
2)被繼承的這個類我們稱之為父類/ 超類
3)繼承瞭某個類的類我們稱之為子類
4)在聲明子類的時候,在子類名稱後面通過:父類名稱方式來實現繼承
@interface 子類名稱 : 父類名稱

@end類

當B類繼承A類, 那麼B類就擁有A類所有的屬性和方法(類方法/對象方法)

2.什麼叫方法重寫?重寫後是以什麼順序調用方法的?
答:
(1)如果子類中有和父類中同名的方法, 那麼我們稱之為方法重寫
註意: 繼承中的方法調用順序, 如果自己有就調用自己的, 如果自己沒有就調用父類的
“方法的調用順序, 先自己再父類, 如果父類中沒有再爺爺類, 如果爺爺類再沒有就找爺爺的爸爸類
如果一直找到NSObject類都沒有找到, 那麼就會報錯
reason: ‘-[Iphone signalWithNumber:]: unrecognized selector sent to instance 0x1003043c0’
註意:在繼承中方法可以重寫, 但是屬性(成員變量)不能重寫

3.方法重寫的使用場景?
答:使用場景:當從父類繼承的某個方法不適合子類,可以在子類中重寫父類的這個方法。

4.繼承的條件是什麼?
答:
不要以為繼承可以提高代碼的復用性, 以後但凡發現多個類當中有重復代碼就抽取一個父類
隻要滿足一定的條件我們才能使用繼承
條件: XXXX 是 XXX / 某某某 is a 某某某

5.繼承的優點是什麼?
答:
提高代碼的復用性
可以讓類與類之間產生關系, 正是因為繼承讓類與類之間產生瞭關系所以才有瞭多態

6.繼承的缺點是什麼?
答:
耦合性太強(依賴性太強)

super關鍵字

什麼是super?
super是個編譯器的指令符號,隻是告訴編譯器在執行的時候,去調誰的方法.

怎麼使用super?
答:
super在類方法中, 一定會調用父類的類方法
super在對象方法中, 一定會調用父類的對象方法
可以利用super在任意方法中調用父類中的方法

super使用場景?
答:
子類重寫父類的方法時想保留父類的一些行為

多態

什麼是多態?程序中是怎麼體現多態的?
答:
多態就是某一類事物的多種形態
在程序中如何表現:
父類指針指向子類對象

多態的條件是什麼?
答:
1)有繼承關系
2)子類重寫父類方法
3)父類指針指向子類對象

多態的優點是什麼?
答:提高瞭代碼的擴展性,復用性

多態的註意點?
答:如果父類指針指向子類對象, 需要調用子類特有的方法, 必須先強制類型轉換為子類才能調用

description方法

使用%@瞭打印一個對象,輸出的是什麼內容?%@的原理是什麼?
答:%@是用來打印對象的, description方法默認返回對象的描述信息(默認實現是返回類名和對象的內存地址).
其實%@的本質是用於打印字符串.
隻要利用%@打印某個對象, 系統內部默認就會調用父類的description方法
調用該方法, 該方法會返回一個字符串, 字符串的默認格式 <類的名稱: 對象的地址>

重寫description方法註意點?
答:如果在description方法中利用%@輸出self會造成死循環
建議: 在description方法中盡量不要使用self來獲取成員變量
因為如果你經常在description方法中使用self, 可能已不小心就寫成瞭 %@, self

私有變量和私有方法

什麼是私有變量?什麼是私有方法?
答:
實例變量(成員變量)既可以在@interface中定義, 也可以在@implementation中定義
私有變量:
寫在@implementation中的成員變量, 默認就是私有的成員變量, 並且和利用@private修飾的不太一樣, 在@implementation中定義的成員變量在其它類中無法查看, 也無法訪問

私有方法:
在@implementation中定義的私有變量隻能在本類中訪問

property和synthesize基本使用

@porperty是一個編譯器指令
在Xocde4.4之前, 可以使用@porperty來代替getter/setter方法的聲明
也就是說我們隻需要寫上@porperty就不用寫getter/setter方法的聲明

編譯器隻要看到@property,就知道我們要生成某一個屬性的
getter/setter方法的聲明

@propertyde格式?
答:@property 數據類型 變量名;

@synthesize是什麼指令?作用是什麼?
答:
synthesize是一個編譯器指令, 它可以簡化我們getter/setter方法的實現

@synthesize age = _age; 在給age賦值時,編譯器做瞭哪些事?
@synthesize age = _age;
(1)在@synthesize後面的age,告訴編譯器, 需要實現哪個@property生成的聲明
(2)告訴@synthesize, 需要將傳入的值賦值給誰和返回誰的值給調用者
如果在@synthesize後面沒有告訴系統將傳入的值賦值給誰, 系統默認會賦值給和@synthesize後面寫得名稱相同的成員變量
@synthesize age;

property增強做瞭哪些事?
答:
(1)從Xcode4.4以後,對@property進行瞭增強, 以後隻要利用一個@property就可以同時生成setter/getter方法的聲明和實現

(2)如果沒有告訴@property要將傳入的參數賦值給誰, 默認@property會將傳入的屬性賦值給_開頭的成員變量

7.@property的使用場景?
答:
如果不想對傳入的數據進行過濾, 僅僅是提供方法給外界操作成員變量, 那麼就可以使用@property,並且系統會自動給我們生成一個_開頭的成員變量

8.使用property增強後,什麼時候要重寫getter/setter方法?
答:使用property增強,隻會生成最簡單的getter/setter方法的聲明和實現, 並不會對傳入的數據進行過濾
如果想對傳入的數據進行過濾, 那麼我們就必須重寫getter/setter方法

9.重寫getter/setter方法有哪些註意點?
答:
如果重寫瞭setter方法, 那麼property就隻會生成getter方法
如果重寫瞭getter方法, 那麼property就隻會生成setter方法
如果同時重寫瞭getter/setter方法, 那麼property就不會自動幫我們生成私有的成員變量

property修飾符

增強@property使用修飾符後的的格式是什麼?
答:
格式:
@property(屬性修飾符) 數據類型 變量名稱;

@property 有哪些修飾符?各有什麼作用?
答:readwrite: 代表既生成getter方法 , 也生成setter方法
默認情況下 @property就是readwrite的
@property(readwrite) int age;
‘readonly: 代表隻生成getter方法不生成setter方法’
可以給setter方法起別名@property(setter=tiZhong:) double weight;
可以給getter方法起別名@property(getter=isMarried) BOOL married;

靜態數據類型和動態數據類型

靜態數據類型的特點:
在編譯時就知道變量的類型,
知道變量中有哪些屬性和方法
在編譯的時候就可以訪問這些屬性和方法,
並且如果是通過靜態數據類型定義變量, 如果訪問瞭不屬於靜態數據類型的屬性和方法, 那麼編譯器就會報錯

動態數據類型的特點:
在編譯的時候編譯器並不知道變量的真實類型, 隻有在運行的時候才知道它的真實類型
並且如果通過動態數據類型定義變量, 如果訪問瞭不屬於動態數據類型的屬性和方法, 編譯器不會報錯

id和NSObject * 的區別?
答:
NSObject *是一個靜態數據類型
id 是一個動態數據類型

動態數據類型的應用場景?
答:動態類型主要用在多態, 可以減少代碼量, 避免調用子類特有的方法需要強制類型轉換

動態數據類型的弊端是什麼?
答:由於動態數據類型可以調用任意方法, 所以有可能調用到不屬於自己的方法, 而編譯時又不會報錯, 所以可能導致運行時的錯誤

判斷數據類型的有哪些方法?(變量 修改為 對象)
答:為瞭避免動態數據類型引發的運行時的錯誤, 一般情況下如果使用動態數據類型保存一個對象, 在調用這個變量的方法之前會進行一次判斷, 判斷當前對象是否能夠調用這個方法

構造方法

什麼是構造方法?
答:
在OC中init開頭的方法, 我們稱之為構造方法

構造方法的用途?
答:
構造方法的用途: 用於初始化一個對象, 讓某個對象一創建出來就擁有某些屬性和值

如何實現構造方法?
答:
重寫init方法, 在init方法中初始化成員變量

如何重寫init方法?
答:重寫init方法必須按照蘋果規定的格式重寫, 如果不按照規定會引發一些未知的錯誤
(1)必須先初始化父類, 再初始化子類
(2)必須判斷父類是否初始化成功, 隻有父類初始化成功才能繼續初始化子類
(3)返回當前對象的地址

- (instancetype)init
{
    // 初始化父類
    // 隻要父類初始化成功 , 就會返回對應的地址, 如果初始化失敗, 就會返回nil
    // nil == 0 == 假 == 沒有初始化成功
    self = [super init];
    // 判斷父類是否初始化成功
    if (self != nil) {
      // 初始化子類
      // 設置屬性的值
        _age = 6;
    }
    // 返回地址
    return self;
}

自定義構造方法

什麼是自定義構造方法?為什麼要自定義構造方法?
(1)自定義構造方法就是自定義一個init方法
(2)有時候我們需要在創建某個對象的時候,讓對象的某些屬性就具有值,這時候就需要傳入一些參數給對象的屬性,為瞭滿足這個需求,就需要自定義構造方法

自定義構造方法的格式?
答:
(1)一定是對象方法
(2)一定返回id/instancetype
(3)方法名稱一定以init開頭
-(instancetype)initWithAge:(int)age;

自定義構造方法在繼承中有一個原則?
答:自己的事情自己做,屬於誰的屬性就由誰來進行操作
父類的屬性交給父類的方法來處理,子類的方法處理子類自己獨有的屬性

自定義構造方法在子類,如何調用的父類構造方法的?
答:子類在重寫自定構造方法時,一般使用super 調用父類的構造方法,先讓父類將父類的屬性進行初始化

- (instancetype)initWithAge:(int)age andName:(NSString *)name andNo:(int)no
{
    if (self = [super initWithAge:age andName:name]) {
        _no = no;
    }
    return self;
}

instancetype和id區別

instancetype和id區別?
答:
(1)id在編譯的時候不能判斷對象的真實類型
instancetype在編譯的時候可以判斷對象的真實類型

(2)如果init方法的返回值是instancetype, 那麼將返回值賦值給一個其它的對象會報一個警告
如果是在以前, init的返回值是id, 那麼將init返回的對象地址賦值給其它對象是不會報錯的

(3)id可以用來定義變量, 可以作為返回值, 可以作為形參
instancetype隻能用於作為返回值

instancetype 應用場景?
答:以後但凡自定義構造方法, 返回值盡量使用instancetype, 不要使用id

類工廠方法

什麼是類工廠方法?
答:用於快速創建對象的類方法, 我們稱之為類工廠方法

類工廠方法應用場景?
答:類工廠方法中主要用於 給對象分配存儲空間和初始化這塊存儲空間

類工廠方法使用規范?
答:規范:
1.一定是類方法 +
2.方法名稱以類的名稱開頭, 首字母小寫
3.一定有返回值, 返回值是id/instancetype
4.在類工廠方法實現中,調用本類的構造方法,創建實例對象,並返回實例對象

自定義類工廠方法是蘋果的一個規范, 一般情況下, 我們會給一個類提供自定義構造方法和自定義類工廠方法用於創建一個對象。

類工廠方法在繼承中的註意點
以後但凡自定義類工廠方法, 在類工廠方法中創建對象一定要使用self來創建,一定不要使用類名來創建。

類的本質及存儲細節

類的本質是什麼?
答:
(1)類其實也是一個對象, 這個對象會在這個類第一次被使用的時候創建
(2)隻要有瞭類對象, 將來就可以通過類對象來創建實例對象
(3)實例對象中有一個isa指針, 指向創建自己的類對象
(4)類對象中保存瞭當前對象所有的對象方法
(5)當給一個實例對象發送消息的時候, 會根據實例對象中的isa指針去對應的類對象中查找
(6)所有類對象的繼承關系就是元類對象的繼承關系

類的啟動過程

1.load方法
“load方法調用時間:”
隻要程序啟動就會將所有類的代碼加載到內存中, 放到代碼區
“調用次數”
load方法會在當前類被加載到內存的時候調用, 有且僅會調用一次

2.initialize方法
“initialize方法調用時間:”
當當前類第一次被使用的時候就會調用(創建類對象的時候)
“調用次數”

SEL類型

SEL是什麼類型?
答:
SEL類型代表著方法的簽名,在類對象的方法列表中存儲著該簽名與方法代碼的對應關系

SEL有什麼作用?
答:
(1)SEL類型的第一個作用, 配合對象/類來檢查對象/類中有沒有實現某一個方法
(2)SEL類型的第二個作用, 配合對象/類來調用某一個SEL方法
(3)配合對象將SEL類型作為方法的形參

哪個方法是用來檢驗對象是否實現瞭某個方法?
判斷實例是否實現某個對象方法
(BOOL)respondsToSelector: (SEL)selector
判斷類是否實現某個類方法
(BOOL)instancesRespondToSelector:(SEL)aSelector;

哪些方法是用來調用對象中SEL類型對應的方法?
答:
讓對象執行某個方法

- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

內存管理

什麼是堆?什麼是棧?
答:
棧(操作系統):由操作系統自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧(先進後出);
堆(操作系統):一般由程序員分配釋放,若程序員不釋放,程序結束時可能由系統回收,分配方式類似於鏈表。

什麼是內存管理?
答:
所謂內存管理, 就是對內存進行管理, 涉及的操作有
分配內存 : 比如創建一個對象, 會增加內存占用
清除內存 : 比如銷毀一個對象, 能減小內存占用

內存管理的本質是什麼?
答:
OC對象存放於堆裡面
非OC對象一般放在棧裡面(棧內存會被系統自動回收)

MRC內存管理

什麼是引用計數器?
答:每個OC對象都有自己的引用計數器,它是一個整數,表示有多少人正在用這個對象

引用計數器的作用?
答:
(1)當使用alloc、new或者copy創建一個對象時,對象的引用計數器默認就是1
(2)當對象的引用計數器為0時,對象占用的內存就會被系統回收
如果對象的計數器不為0,那麼在整個程序運行過程,它占用的內存就不可能被回收(除非整個程序已經退出 )

怎麼操作引用計數器?
答:
給對象發送一條retain消息,可以使引用計數器值+1(retain方法返回對象本身)
給對象發送一條release消息, 可以使引用計數器值-1
給對象發送retainCount消息, 可以獲得當前的引用計數器值
需要註意的是: release並不代表銷毀回收對象, 僅僅是計數器-1

dealloc 方法的作用?
答:對象即將被銷毀時系統會自動給對象發送一條dealloc消息 (因此, 從dealloc方法有沒有被調用,就可以判斷出對象是否被銷毀)

重寫dealloc方法有什麼註意點?
答:重寫dealloc方法, [super dealloc]一定要寫到所有代碼的最後

內存管理的原則?
答:
(1)誰創建誰release :
如果你通過alloc、new、copy或mutableCopy來創建一個對象,那麼你必須調用release或autorelease

(2)誰retain誰release:
隻要你調用瞭retain,就必須調用一次release

(3)總結:
有加就有減,曾經讓對象的計數器+1,就必須在最後讓對象的計數器-1

setter方法的內存管理
實現set方法內存管理有哪幾步?
答:
(1)retain需要使用的對象
(2)release之前的對象
(3)隻有傳入的對象和之前的不同才需要release和retain

- (void)setRoom:(Room *)room
{
    // 隻有房間不同才需用release和retain
    if (_room != room) {
    // 0ffe1 != 0ffe1
        // 2.將以前的房間釋放掉 -1
        [_room release];
        // retain不僅僅會對引用計數器+1, 而且還會返回當前對象
        _room = [room retain];
    }
}

property修飾符
1.readonly: 隻會生成getter方法
readwrite: 既會生成getter也會生成setter, 默認什麼都不寫就是readwrite

2.getter: 可以給生成的getter方法起一個名稱
setter: 可以給生成的setter方法起一個名稱

3.retain: 就會自動幫我們生成getter/setter方法內存管理的代碼
assign: 不會幫我們生成set方法內存管理的代碼, 僅僅隻會生成普通的getter/setter方法, 默認什麼都不寫就是assign

4.多線程
atomic :性能低(默認)
nonatomic :性能高
在iOS開發中99.99%都是寫nonatomic

property修飾符 有拿幾點需要註意的問題?
答:
1.相同類型的property修飾符不能同時使用
2.不同類型的property修飾符可以多個結合在一起使用, 多個之間用,號隔開
3.iOS開發中隻要寫上property, 那麼就立刻寫上nonatomic

什麼是循環retain?
答:
如果A對用要擁有B對象, 而B對應又要擁有A對象, 此時會形成循環retain
解決循環retain的方法,一邊用retain一邊用assign

autorelease 自動釋放池

什麼是自動釋放池?
答:
autorelease是一種支持引用計數的內存管理方式,隻要給對象發送一條autorelease消息,會將對象放到一個自動釋放池中,當自動釋放池被銷毀時,會對池子裡面的所有對象做一次release操作

自動釋放池的優點是什麼?
答:
不用再關心對象釋放的時間
不用再關心什麼時候調用release

簡述自動釋放池的原理?
答:
autorelease實際上隻是把對release的調用延遲瞭,對於每一個autorelease,系統隻是把該 Object放入瞭當前的autorelease pool中,當該pool被釋放時,該pool中的所有Object會被調用Release。

自動釋放池有哪些註意事項?
答:
(1)在自動釋放池中創建瞭對象, 一定要調用autorelease,才會將對象放入自動釋放池中
(2)一個程序中可以創建N個自動釋放池, 並且自動釋放池還可以嵌套
(3)不要再自動釋放池中使用比較消耗內存的對象, 占用內存比較大的對象
(4)盡量不要再自動釋放池中使用循環, 特別是循環的次數非常多, 並且還非常占用內存
(5)千萬不要寫多次autorelease
(6)一個alloc/new對應一個autorelease或者release

自動釋放池是以什麼形式存儲的?
答: 如果存在多個自動釋放池的時候, 自動釋放池是以 “棧” 的形式存儲在堆區
棧的特點: 先進後出

ARC內存管理

問題1:ARC的原理是什麼?
答:當ARC開啟時,編譯器將自動在代碼合適的地方插入retain, release和autorelease,而作為程序猿,完全不需要擔心編譯器會做錯(除非開發者自己錯用ARC瞭)。

ARC有什麼優點?
答:
1.完全消除瞭手動管理內存的煩瑣, 讓程序猿更加專註於app的業務
2.基本上能夠避免內存泄露
3.有時還能更加快速,因為編譯器還可以執行某些優化

ARC的原則是什麼?什麼是強指針?什麼是弱指針?
答:隻要還有一個強指針變量指向對象,對象就會保持在內存中
(1)強指針
默認所有指針變量都是強指針
被__strong修飾的指針
(2)弱指針
被__weak修飾的指針

ARC下@property修飾符有哪些?
答:
strong : 用於OC對象, 相當於MRC中的retain
weak : 用於OC對象, 相當於MRC中的assign
assign : 用於基本數據類型, 跟MRC中的assign一樣

ARC中是怎麼對對象進行內存管理的?
答:
(1)ARC下單對象內存管理
(2)ARC下,所有的指針都是強指針
(3)ARC, A對象想擁有B對象, 那麼就需要用一個強指針指向B對象
(4)A對象不用B對象瞭, 什麼都不需要做, 編譯器會自動幫我們做

ARC怎麼解決循環引用問題?
答:
ARC和MRC一樣, 如果A擁有B, B也擁有A, 那麼必須一方使用弱指針
也就是說 一端用strong ,一端用weak

Category 分類

書寫Category的格式?
答:
// 分類的聲明
@interface ClassName (CategoryName)
NewMethod; //在類別中添加方法
//不允許在類別中添加變量
@end

ClassName: 需要給哪個類擴充方法
CategoryName: 分類的名稱
NewMethod: 擴充的方法

// 分類的實現
@implementation ClassName(CategoryName)

NewMethod
… …
@end

ClassName: 需要給哪個類擴充方法
CategoryName: 分類的名稱
NewMethod: 擴充的方法

Category的作用?
答:
(1)在不改變原來的類內容的基礎上,為類增加一些方法。
(2)一個龐大的類可以分模塊開發,由多個人來編寫,更有利於團隊合作

分類,原來類或者父類中的方法調用的順序?
答:先調用分類中的方法(最後參與編譯的分類優先),再調用原來類中的方法,最後掉用父類中的方法

Extension 匿名擴展

什麼是類擴展?
答:延展類別又稱為擴展(Extension),Extension是Category的一個特例

類擴展格式?
答:
類擴展書寫格式
@interface 類名 ()
@end

類擴展的作用是什麼?
答:寫在.m文件中,可以為某個類擴充一些私有的成員變量和方法

Block

什麼是Block?
答:Block是iOS中一種比較特殊的數據類型,用來保存某一段代碼

Block的作用?
答:Block用來保存某一段代碼, 可以在恰當的時間再取出來調用
功能類似於函數和方法

Block的格式?
答:Block的格式:
返回值類型 (^block變量名)(形參列表) = ^(形參列表) {
};

協議

什麼是協議?
答:其他語言有接口的概念,接口就是一堆方法的聲明沒有實現.
OC中沒有接口的概念,OC中的接口就是協議.
協議Protocol是由一系列的方法聲明組成的

書寫協議的格式?
答:
格式:
@protocol 協議名稱
// 方法聲明列表
@end

一個類怎麼遵循協議?
答:類遵守協議格式:
@interface 類名 : 父類 <協議名稱1, 協議名稱2,…>
@end

註意:
(1)一個類可以遵守1個或多個協議
(2)任何類隻要遵守瞭Protocol,就相當於擁有瞭Protocol的所有方法聲明

4.協議和繼承有什麼區別?
答:
(1)繼承之後默認就有實現, 而protocol隻有聲明沒有實現
(2)相同類型的類可以使用繼承, 但是不同類型的類隻能使用protocol
(3)protocol可以用於存儲方法的聲明, 可以將多個類中共同的方法抽取出來, 以後讓這些類遵守協議即可

什麼是基協議?
答:基協議:是基協議,是最根本最基本的協議,其中聲明瞭很多最基本的方法。
註意:建議每個新的協議都要遵守NSObject協議

6.協議有哪些註意事項?
答:
(1)協議隻能聲明方法, 不能聲明屬性
(2)父類遵守瞭某個協議, 那麼子類也會自動遵守這個協議
(3)在OC中一個類可以遵守1個或多個協議
註意: OC中的類隻能有一個父類, 也就是說OC隻有單繼承
(4)OC中的協議又可以遵守其它協議, 隻要一個協議遵守瞭其它協議, 那麼這個協議中就會自動包含其它協議的聲明

7.協議中控制方法的能否實現的關鍵字是什麼?各有什麼作用?
(1)註意: 如果沒有使用任何關鍵字修飾協議中的方法, 那麼該方法默認就是required的
(2)註意:@required和@optional僅僅使用程序員之間交流, 並不能嚴格的控制某一個遵守該協議的類必須要實現該方法, 因為即便不是實現也不會報錯, 隻會報一個警告
(3)
@required
如果協議中的方法是@required的, 要求遵守協議的類實現@required所修飾的方法,如果沒有實現該方法, 那麼會報一個警告
(4)
@optional
如果協議中的方法是@optional的, 遵守協議的類可選擇實現@optional所修飾的方法,如果沒有實現該方法, 那麼不會報警告

類型限定

什麼是類型限定?
答:類型限定就是限定一個類必須遵守某個協議

類型限定的格式?
答:數據類型<協議名稱> 變量名
@property (nonatomic, strong) Wife *wife;

類型限定有什麼註意點?
答:
(1)類型限定是寫在數據類型的右邊的
(2)雖然在接受某一個對象的時候, 對這個對象進行瞭類型限定(限定它必須實現某個協議),
但是並不意味著這個對象就真正的實現瞭該方法. 所以每次在調用對象的協議方法時應該進行一次驗證

if ([self.wife respondsToSelector:@selector(cooking)]) {
    [self.wife cooking];
}

代理設計模式

代理模式的應用場景?
(1)當A對象想監聽B對象的一些變化時, 可以使用代理設計模式
(2)當B對象發生一些事情, 想通知A對象的時候, 可以使用代理設計模式
(3)當對象A無法處理某些行為的時候,想讓對象B幫忙處理(讓對象B成為對象A的代理對象)

用什麼類型來接收遵守協議的代理對象?
答:使用id類型接收代理對象

簡述一下協議的編寫規范?
答:
(1)一般情況下, 當前協議屬於誰, 我們就將協議定義到誰的頭文件中
(2)協議的名稱一般以它屬於的那個類的類名開頭, 後面跟上protocol或者delegate
(3)協議中的方法名稱一般以協議的名稱protocol之前的作為開頭
(4)一般情況下協議中的方法會將觸發該協議的對象傳遞出去

5.一般情況下一個類中的代理屬於的名稱叫做 delegate

6.當某一個類要成為另外一個類的代理的時候,
一般情況下在.h中用@protocol 協議名稱;告訴當前類 這是一個協議.
在.m中用#import真正的導入一個協議的聲明

Foundation

什麼是框架?
答:
眾多功能API的集合.
框架是由許多類、方法、函數、文檔按照一定的邏輯組織起來的集合,以便使研發程序變得更容易,在OS X下的Mac操作系統中大約有80個框架為所有程序開發奠定基礎的框架稱為Foundation 框架

Foundation 框架有什麼作用?
答:
1.Foundation框架是MaciOS中其他框架的基礎
2.Foundation框架包含瞭很多開發中常用的數據類型:結構體,枚舉, 類

什麼是NSString?
答:一個NSString對象就代表一個字符串(文字內容)
一般稱NSString為字符串類

如何創建NSString對象?有幾種方法創建一個NSString字符串?
答:
(1)通過@”“直接創建
如果通過@”“創建字符串, 那麼會將字符串放到常量區中
如果是字符串常量, 那麼隻要內容相同 , 不會重復創建

NSString *str1 = @james;

(2)通過alloc或者類工廠方法創建
如果是通過alloc或者類工廠方法創建, 那麼會將字符串放到堆區中

    NSString *str2 = [[NSString alloc] initWithString:@james];
    NSString *str3 = [NSString stringWithFormat:@jack];

如何將字符串寫入到文件中?

NSString *str = @iOS;
NSString *path2 = @/Users/james/Desktop/abc.txt;
BOOL flag = [str writeToFile:path2 atomically:YES encoding:NSUTF8StringEncoding error:nil];
NSLog(@flag = %i, flag);

6.什麼是URL?
答:
(1)URL的全稱是Uniform Resource Locator(統一資源定位符)
(2)URL是互聯網上標準資源的地址
(3)互聯網上的每個資源都有一個唯一的URL,它包含的信息指出資源的位置
(4)根據一個URL就能找到唯一的一個資源

7.寫URL格式?
答: URL = 協議頭://主機地址/路徑

8.如何創建URL
答:
(1)通過alloc 或者類工廠方法創建

NSURL *url = [NSURL URLWithString:@file:///Users/james/Desktop/str.txt];
NSURL *url = [[NSURL alloc] initWithString:@file:///Users/james/Desktop/str.txt];

(2)通過文件路徑創建(默認就是file協議的)

NSURL *url = [NSURL fileURLWithPath:@/Users/james/Desktop/str.txt];

9.如何獲取本地路徑的信息?獲取本地路徑信息的方法有什麼註意點?
答:獲取本地路徑信息–fileURLWithPath
方法一:
(1)字符串保存路徑

NSString *path = @file://192.168.13.10/Users/james/Desktop/note/ja.txt;
    NSLog(@url編碼前: %@, path);

(2)將路徑中中文轉換為UTF-8編碼格式

path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@url編碼後: %@, path);

方法二:
(1)字符串保存路徑,如果訪問本機的文件, 可以省略主機地址
NSString *path = @”file:///Users/james/Desktop/note/ja.txt”;
NSLog(@”url編碼前: %@”, path);

(2)將路徑中中文轉換為UTF-8編碼格式
path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSLog(@”url編碼後: %@”, path);
NSURL *url = [NSURL URLWithString:path];

10.獲取本地路徑的信息

NSURL *url = [NSURL fileURLWithPath:@/Users/james/Desktop/note/ja.txt];
NSError *error = nil;
NSString *str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (error == nil) {
NSLog(@str = %@, str);
    }else{
        NSLog(@error = %@, [error localizedDescription]);
    }

註意點:
URLWithString: 方法不支持中文,所以無法成功創建URL,必須先對路徑字符串進行編碼

fileURLWithPath: 方法支持中文,並且省略協議頭,但是隻能獲取本地方法

11.如何獲取網絡路徑的信息?
答:
獲取網絡路徑的信息–URLWithString

NSURL *url = [NSURL URLWithString:@https://www.baidu.com];
NSString *str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSLog(@str = %@, str);

12.如何將信息寫入到指定文件?
答:
方法一:

NSString *str = @james;
NSString *path = @file:///Users/james/Desktop/未命名文件夾/abc.txt;
path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:path];
 [str writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];

方法二:

NSString *str = @james;
NSString *path = @/Users/james/Desktop/未命名文件夾/abc.txt;
NSURL *url = [NSURL fileURLWithPath:path];
[str writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];

總結:
1.如果多次往同一個文件中寫入內容,那麼後一次的會覆蓋前一次的
2.方法名中沒有file,路徑中要添加上file協議頭,如果方法名中有file,路徑中就不需要file協議頭

NSString

如何比較兩個字符串的”內容”是否相同?
答:
BOOL flag = [str1 isEqualToString:str2];
NSLog(@”flag = %i”, flag);

如何比較兩個字符串的”地址”是否相同?
flag = (str1 == str2);
NSLog(@”flag = %i”, flag);

如何比較字符串的大小?
答:使用方法compare:
NSOrderedAscending 前面的小於後面的
NSOrderedSame, 兩個字符串相等
NSOrderedDescending 前面的大於後面的

如何忽略大小寫進行比較?
[str1 caseInsensitiveCompare:str2];

如何判斷字符串是否以什麼結尾的?本質是什麼?
答:
本質就是從字符串的最後一個字符開始匹配, 隻要不匹配就返回NO

if ([str hasSuffix:@.gif]) {
    NSLog(@動態圖片);
}else{
    NSLog(@不是動態圖片);
}

6.如何獲取指定范圍內的字符串?
答:
(1)動態獲取截取的起始位置
NSUInteger location = [str rangeOfString:@”>”].location + 1;
(2)動態獲取截取的長度

NSUInteger length = [str rangeOfString:@<!--].location - location;
NSRange range = NSMakeRange(location, length);
NSString *newStr = [str substringWithRange:range];
NSLog(@str = %@, str);
NSLog(@newStr = %@, newStr);

7.如何替換字符串中的部分字符?
答:
需求: 將&符號替換為/

NSString *str = @http:&&www.weibo.iosjames.com&img&james.gif;
..OccurrencesOfString: 要替換誰
// withString: 用誰替換
NSString *newStr = [str stringByReplacingOccurrencesOfString:@& withString:@/];
NSLog(@newStr = %@, newStr);

8.如何對字符串首位進行處理?
答:

NSString *str = @HTTP://www.baidu.com/img/james.GIF;
NSCharacterSet *set = [NSCharacterSet uppercaseLetterCharacterSet];
NSString *newStr = [str stringByTrimmingCharactersInSet:set];
NSLog(@newStr = |%@|, newStr);

9.如何給文件路徑添加一個目錄?
答:
本質就是在字符串的末尾加上一個/ 和指定的內容
註意: 如果路徑後面已經有瞭/, 那麼就不會添加瞭
如果路徑後面有多個/, 那麼會自動刪除多餘的/, 隻保留一個

NSString *newStr = [str stringByAppendingPathComponent:@james];
NSLog(@%@, newStr);

10.如何獲取路徑中文件的擴展名?
答:
本質就是從字符串的末尾開始查找., 截取第一個.後面的內容

NSString *newStr = [str pathExtension];
NSLog(@%@, newStr);

11.如何刪除路徑中文件的擴展名?
答:
本質就是從字符串的末尾開始查找.,刪除第一個.和.後面的內容

NSString *newStr = [str stringByDeletingPathExtension];
NSLog(@%@, newStr);

12.如何給文件路徑添加一個擴展名?
答:
本質就是在字符串的末尾加上一個.和指定的內容

NSString *newStr = [str stringByAppendingPathExtension:@jpg];
NSLog(@%@, newStr);

13.如何將將字符串轉換為大寫?
答:

NSString *newStr = [str uppercaseString];
NSLog(@%@, newStr);

14.如何將字符串轉換為小寫?
答:

NSString *newStr2 = [newStr lowercaseString];
NSLog(@%@, newStr2);

15.如何將字符串的首字符轉換為大寫
答:

NSString *newStr = [str capitalizedString];
NSLog(@%@, newStr);

NSMutalbleString

NSMutableString和NSString的區別?
答:
(1)NSString是不可變的, 裡面的文字內容是不能進行修改的
(2)NSMutableString是可變的, 裡面的文字內容可以隨時更改
(3)NSMutableString能使用NSString的所有方法

什麼是可變字符串?什麼是不可變字符串?
答:
不可變字符串:指的是字符串在內存中占用的存儲空間固定,並且存儲的內容不能發生變化
可變字符串:指的是字符串在內存中占用的存儲空間可以不固定,並且存儲的內容可以被修改

在字符串後面添加一段字符串?
答:

[strM appendString:@/image];
NSLog(@strM = %@, strM);

4.如何刪除字符串中的字符?
技巧: 在開發中, 我們經常利用rangeOfString和deleteCharactersInRange方法配合起來刪除指定的字符串

NSRange range = [strM rangeOfString:@xx];
[strM deleteCharactersInRange:range];
NSLog(@strM = %@, strM);

5.如何在某個字符前面插入love這個單詞?
答:
insertString : 需要插入的字符串
atIndex: 從哪裡開始插入

NSRange range = [strM rangeOfString:@xx];
[strM insertString:@love atIndex:range.location];
NSLog(@strM = %@, strM);

NSArray

什麼是NSArray?
答:NSArray是OC中的數組類,開發中建議盡量使用NSArray替代C語言中的數組

NSArray有哪些使用註意?
答:
(1)隻能存放任意OC對象, 並且是有順序的
(2)不能存儲非OC對象, 比如intloatdoublecharenumstruct等
(3)它是不可變的,一旦初始化完畢後,它裡面的內容就永遠是固定的, 不能刪除裡面的元素, 也不能再往裡面添加元素
(4)NSArray使用NSLog()打印,輸出的是小括號的格式。
(5)NSArray中不能存儲nil,因為NSArray認為nil是數組的結束(nil是數組元素結束的標記)。nil就是0。0也是基本數據類型,不能存放到NSArray中。

NSArray有哪些常用方法?
答:

- (NSUInteger)count; 獲取集合元素個數
- (id)objectAtIndex:(NSUInteger)index; 獲得index位置的元素

- (BOOL)containsObject:(id)anObject; 是否包含某一個元素

- (id)lastObject; 返回最後一個元素

- (id)firstObject; 返回最後一個元素

- (NSUInteger)indexOfObject:(id)anObject; 查找anObject元素在數組中的位置(如果找不到,返回-1)

- (NSUInteger)indexOfObject:(id)anObject inRange:(NSRange)range;
在range范圍內查找anObject元素在數組中的位置

4.書寫NSArray簡寫形式?
答:

NSArray *arr = [NSArray arrayWithObjects:@ldda, @james, @jjj, nil];
NSArray *arr = @[@james, @jasc, @jjj];

獲取數組元素的簡寫

NSLog(@%@, [arr objectAtIndex:0]);
NSLog(@%@, arr[0]);

5.如何使用增強for循環,遍歷NSArray數組?
答:
逐個取出arr中的元素, 將取出的元素賦值給obj
註意: obj的類型可以根據數組中元素的類型來寫, 不一定要寫NSObject
for (NSString *obj in arr) {
NSLog(@”obj = %@”, obj);
}

6.如何使用OC數組的迭代器來遍歷數組?
答:
每取出一個元素就會調用一次block
每次調用block都會將當前取出的元素和元素對應的索引傳遞給我們
obj就是當前取出的元素, idx就是當前元素對應的索引
stop用於控制什麼時候停止遍歷

[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if (idx == 1) {
        *stop = YES;
    }
    NSLog(@obj = %@, idx = %lu, obj, idx);
}];

7.如何對數據進行排序?NSArray *arr = @[@10, @20, @5, @7, @15];
NSLog(@”排序前: %@”, arr);意:**
想使用compare方法對數組中的元素進行排序, 那麼數組中的元素必須是Foundation框架中的對象, 也就是說不能是自定義對象

NSArray *newArr = [arr sortedArrayUsingSelector:@selector(compare:)];
NSLog(@排序後: %@, newArr);

8.如何將數組寫入文件中?
答:

NSArray *arr = @[@eee, @aaa, @jjj];
BOOL flag = [arr writeToFile:@/Users/james/Desktop/abc.plist atomically:YES];
NSLog(@flag = %i, flag);

9.將數組寫入文件中,有什麼註意事項?
答:
註意(1):
如果將一個數組寫入到文件中之後, 本質是寫入瞭一個XML文件
在iOS開發中一般情況下我們會將XML文件的擴展名保存為plist

註意(2)
writeToFile隻能寫入數組中保存的元素都是Foundation框架中的類創建的對象, 如果保存的是自定義對象那麼不能寫入

10.如何從文件中讀取數據到NSArray中?
答:
從文件中讀取一個數組,此方法在字典轉模型中,經常用到

NSArray *newArray = [NSArray arrayWithContentsOfFile:@/Users/james/Desktop/abc.plist];
NSLog(@%@, newArray);

NSMutableArray

1.什麼是可變數組?和NSArray有什麼區別?
答:
(1)NSMutableArray是NSArray的子類
(2)NSArray是不可變的,一旦初始化完畢後,它裡面的內容就永遠是固定的, 不能刪除裡面的元素, 也不能再往裡面添加元素
(3)NSMutableArray是可變的,隨時可以往裡面添加更改刪除元素

2.如何創建一個空的數組?創建可變數組有什麼註意點?

NSMutableArray *arrM = [NSMutableArray array];
NSMutableArray *arrM = [[NSMutableArray alloc] init];

註意:
不能通過@[]來創建一個可變數組, 因為@[]創建出來的是一個不可變的數組

3.如何給可變數組增加內容?
答:
方法一:

[arrM addObject:@james];

方法二:
將指定數組中的元素都取出來, 放到arrM中
並不是將整個數組作為一個元素添加到arrM中

[arrM addObjectsFromArray:@[@james, @jjj]];

註意:
以下是將整個數組作為一個元素添加

 [arrM addObject:@[@ss, @jjj]];
NSLog(@%@, arrM);

4.如何給可變數組插入內容?
答:

[arrM insertObject:@xcq atIndex:1];
NSRange range = NSMakeRange(2, 2);
NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:range];

插入一組數據, 指定數組需要插入的位置, 和插入多少個
[arrM insertObjects:@[@”A”, @”B”] atIndexes:set];

5.如何刪除可變數組中的內容?
答:

刪除
[arrM removeObjectAtIndex:0]
刪除數組中最後一個元素
[arrM removeLastObject];
刪除index位置的元素
[arrM removeObject:@A];

6.如何替換可變數組中的內容?
答:

[arrM replaceObjectAtIndex:1 withObject:@M];

//簡寫:

arrM[0] = @ZS;
NSLog(@%@, arrM);

7.如何獲取可變數組中的內容?
答:

NSLog(@%@, [arrM objectAtIndex:0]);

NSDictionary

什麼是字典?
答:OC中的NSDictionary:根據key找到value,字典中存儲的東西都是鍵值對

如何創建字典?
答:

方法一:

NSDictionary *dict = [NSDictionary dictionaryWithObject:@james forKey:@name];
NSString *name = [dict objectForKey:@name];
NSLog(@name = %@, name);

方法二:
註意: key和value 是一一對應

NSDictionary *dict = [NSDictionary dictionaryWithObjects:@[@james, @22, @1.75] forKeys:@[@name, @age, @height]];
NSLog(@%@ %@ %@, [dict objectForKey:@name], [dict objectForKey:@age], [dict objectForKey:@height]);

方法三:簡寫:

NSDictionary *dict = @{key:value};
NSDictionary *dict = @{@name: @james};
NSLog(@%@, dict[@name]);
NSDictionary *dict = @{@name:@james, @age:@30, @height:@1.75};
NSLog(@%@ %@ %@, dict[@name], dict[@age], dict[@height]);

3.如何對字典進行遍歷?
答:

NSDictionary *dict = @{@name:@james, @age:@22, @height:@1.75};

//獲取字典中key和value的個數, 在字典中key稱之為鍵, value稱之為值

NSLog(@count = %lu, [dict count]);

方法一:老式for循環寫法

for (int i = 0; i < dict.count; ++i) {
    // 獲取字典中所有的key
    NSArray *keys = [dict allKeys];
    // 取出當前位置對應的key
    //        NSLog(@%@, keys[i]);
    NSString *key = keys[i];
    NSString *value = dict[key];
    NSLog(@key = %@, value = %@, key, value);
}

方法二:增強for循環寫法
如何通過forin遍歷字典, 會將所有的key賦值給前面的obj

for (NSString *key in dict) {
NSLog(@%@, key);
NSString *value = dict[key];
NSLog(@key = %@, value = %@, key, value);

}

方法三:OC字典的迭代器來遍歷

[dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    NSLog(@key = %@, value = %@, key, obj);
}];

4.如何對字典文件進行讀寫?
答:
(1)將字典數據寫入文件中

NSDictionary *dict = @{@name:@james, @age:@22, @height:@1.75};

[dict writeToFile:@/Users/james/Desktop/info.plist atomically:YES];

(2)從文件中讀取字典數據
註意: 字典和數組不同, 字典中保存的數據是無序的

NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:@/Users/james/Desktop/info.plist];
NSLog(@%@, newDict);
NSArray *arr = @[@10, @20, @30, @5];
[arr writeToFile:@/Users/james/Desktop/abc.plist atomically:YES];

NSMutableDictionary

如何創建一個空的可變字典?
答:
NSMutableDictionary *dictM = [NSMutableDictionary dictionary];

如何給可變字典添加鍵值對?
答:

[dictM setObject:@lnj forKey:@name];

簡寫:

dictM[@name] = @james;

會將傳入字典中所有的鍵值對取出來添加到dictM中

[dictM setValuesForKeysWithDictionary:@{@age:@30, @height:@1.75}];

3.如何刪除可變字典鍵值對?
答:

[dictM removeObjectForKey:@name];
[dictM removeObjectsForKeys:@[@age, @height]];

4.如何修改可變字典中的鍵值對?
答:利用setObject方法給同名的key賦值, 那麼新值會覆蓋舊值

[dictM setObject:@88 forKey:@age];

簡寫:

dictM[@age] = @88;

5.使用可變字典有什麼註意事項?
答:
(1)不能使用@{}來創建一個可變的字典
NSMutableDictionary *dictM = @{@”name”:@”james”};//編譯就會報錯
[dictM setObject:@”30” forKey:@”age”];

(2)
如果是不可變字典, 那麼key不能相同
如果是不可變字典出現瞭同名的key, 那麼後面的key對應的值不會被保存
如果是在可變數組中, 後面的會覆蓋前面的

NSDictionary *dict = @{@name:@lkl, @name:@lll};
NSLog(@dict = %@, dict);
NSMutableDictionary *dictM = [NSMutableDictionary dictionaryWithObjects:@[@lkl, @lll] forKeys:@[@name, @name]];
NSLog(@dict = %@, dictM);

6.NSArray和NSDictionary的區別?
答:
NSArray是有序的,NSDictionary是無序的
NSArray是通過下標訪問元素,NSDictionary是通過key訪問元素

NSNumber

1.NSNumber的應用場景?
答:
NSNumber可以將基本數據類型包裝成對象,這樣就可以間接將基本數據類型存進NSArrayNSDictionary中

2.如何將基本數據類型轉換為對象類型?
答:

int age = 10;
double number= 5.1;
int value =  6;
NSNumber *ageN = [NSNumber numberWithInt:age];
NSNumber *numberN = [NSNumber numberWithDouble:number];
NSNumber *valueN = [NSNumber numberWithInt:value];
NSArray *arr = @[ageN, numberN, valueN];
NSLog(@arr = %@, arr);

3.如何將對象類型轉換為基本數據類型?
答:

int temp = [ageN intValue];
double temp = [numberN doubleValue];

4.如何將基本數據類型轉換對象類型簡寫?有什麼註意點?
答:
註意: 如果傳入的是變量那麼必須在@後面寫上(), 如果傳入的常量, 那麼@後面的()可以省略

NSNumber *temp = @(number);
NSNumber *temp  =@10.10;
NSLog(@%@, temp);

NSValue

1.NSValue的應用場景?
答:
(1)NSNumber是NSValue的子類, 但NSNumber隻能包裝數字類型
(2)NSValue可以包裝任意值
因此, 可以用NSValue將結構體包裝後,加入NSArrayNSDictionary中

2.如何利用NSValue包裝常用的結構體?
答:

CGPoint point = NSMakePoint(10, 20);
NSValue *value = [NSValue valueWithPoint:point];
NSArray *arr = @[value];
NSLog(@%@, arr);

3.如何利用NSValue包裝自定義的結構體?
答:

typedef struct{
    int age;
    char *name;
    double height;
}Person;
Person p = {30, lld, 1.75};

NSDate

1.NSDate的應用場景?
答:NSDate可以用來表示時間, 可以進行一些常見的日期時間處理
[NSDate date]返回的就是當前0時區的時間

2.如何獲取當前時區的時間?
答:
(1) date方法創建的時間對象, 對象中就保存瞭當前的時間

NSDate *now = [NSDate date];

(2)獲取當前所處的時區

NSTimeZone *zone = [NSTimeZone systemTimeZone];

(3)獲取當前時區和指定時區時間的時間差

NSInteger seconds = [zone secondsFromGMTForDate:now];
//    NSLog(@seconds = %lu, seconds);

(4)計算出當前時區的時間

NSDate *newDate = [now dateByAddingTimeInterval:seconds];
NSLog(@newDate = %@, newDate);

3.如何格式化時間?
答:
NSDate 轉 NSString
(1)創建時間

NSDate *now = [NSDate date];

(2)創建時間格式化

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

(3)指定格式

formatter.dateFormat = @yyyy-MM-dd HH:mm:ss;

(4)格式化時間

NSString *str = [formatter stringFromDate:now];
NSLog(@%@, str);

NSString 轉 NSDate
(1)獲取時間

NSString *str = @2015-08-20 07:05:26 +0000;

2.創建時間格式化

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

註意:
如果是從NSString格式化為NSDate, 那麼dateFormat的格式, 必須和字符串中的時間格式一致, 否則可能轉換失敗
(3)指定格式

formatter.dateFormat = @yyyy-MM-dd HH:mm:ss Z;

4.格式化日期

NSDate *date = [formatter dateFromString:str];
NSLog(@%@, date);

NSCalendar

1.如何獲取當前時間的年月日時分秒?
答:
(1)獲取當前時間

NSDate *now = [NSDate date];
NSLog(@now = %@, now);

獲得NSCalendar 日歷對象

NSCalendar *calendar1 = [NSCalendar currentCalendar];
// 利用日歷類從當前時間對象中獲取 年月日時分秒(單獨獲取出來)
// components: 參數的含義是, 問你需要獲取什麼?
// 一般情況下如果一個方法接收一個參數, 這個參數是是一個枚舉 , 那麼可以通過|符號, 連接多個枚舉值
NSCalendarUnit type = NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond;
NSDateComponents *cmps = [calendar1 components:type fromDate:now];
NSLog(@year = %ld, cmps.year);
NSLog(@month = %ld, cmps.month);
NSLog(@day = %ld, cmps.day);
NSLog(@hour = %ld, cmps.hour);
NSLog(@minute = %ld, cmps.minute);
NSLog(@second = %ld, cmps.second);

2.如何獲取當前時間和指定時間的時間差?
答:

1.過去的一個時間
NSString *str = @2015-06-29 07:05:26 +0000;
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @yyyy-MM-dd HH:mm:ss Z;
NSDate *date = [formatter dateFromString:str];
2.當前的時間
NSDate *now = [NSDate date];

NSLog(@date = %@, date);
NSLog(@now = %@, now);

3.比較兩個時間
NSCalendar *calendar = [NSCalendar currentCalendar];
NSCalendarUnit type = NSCalendarUnitYear |
NSCalendarUnitMonth |
NSCalendarUnitDay |
NSCalendarUnitHour |
NSCalendarUnitMinute |
NSCalendarUnitSecond;
NSDateComponents *cmps = [calendar components:type fromDate:date toDate:now options:0];
NSLog(@%ld年%ld月%ld日%ld小時%ld分鐘%ld秒鐘, cmps.year, cmps.month, cmps.day, cmps.hour, cmps.minute, cmps.second);

NSFileManager

1.什麼是NSFileManager?如何獲取NSFileManager 對象?
答:
NSFileManager是用來管理文件系統的
它可以用來進行常見的文件文件夾操作

NSFileManager *manager = [NSFileManager defaultManager];

2.如何判斷一個文件或者文件夾是否存在?
答:

BOOL flag = [manager fileExistsAtPath:@/Users/james/Desktop/video/01-NSArray.text];
NSLog(@flag = %i, flag);

3.如何獲取文件或文件夾的屬性?
答:

NSDictionary *info = [manager attributesOfItemAtPath:@/Users/james/Desktop/video/acn.mp4 error:nil];
NSLog(@info = %@, info);

4.如何獲取文件夾中所有的文件?
答:
註意:

NSArray *res = [manager contentsOfDirectoryAtPath:@/Users/xiaomage/Desktop/video error:nil];
NSLog(@res = %@, res);

獲取當前文件夾下所有的文件, 能獲取子文件夾下面的文件

NSArray *res = [manager subpathsAtPath:@/Users/james/Desktop/video];
NSArray *res = [manager subpathsOfDirectoryAtPath:@/Users/james/Desktop/video error:nil];
NSLog(@res = %@, res);

5.如何創建文件夾?
答:
createDirectoryAtPath: 告訴系統文件夾需要創建到什麼位置
withIntermediateDirectories: 如果指定的文件中有一些文件夾不存在, 是否自動創建不存在的文件夾
attributes: 指定創建出來的文件夾的屬性
error: 是否創建成功, 如果失敗會給傳入的參數賦值
註意: 該方法隻能用於創建文件夾, 不能用於創建文件

BOOL flag = [manager createDirectoryAtPath:@/Users/james/Desktop/abc/llq withIntermediateDirectories:YES attributes:nil error:nil];
NSLog(@%i, flag);

6.如何創建文件?
createFileAtPath: 指定文件創建出來的位置
contents : 文件中的內容
attributes: 創建出來的文件的屬性
NSData : 二進制數據
註意: 該方法隻能用於創建文件, 不能用於創建文件夾

Copy

1.使用copy功能的前提是什麼?
答:
copy : 需要遵守NSCopying協議,實現copyWithZone:方法
使用mutableCopy的前提
需要遵守NSMutableCopying協議,實現mutableCopyWithZone:方法

2.如何使用copy功能?
答:
一個對象可以調用copy或mutableCopy方法來創建一個副本對象
copy : 創建的是不可變副本(如NSString、NSArray、NSDictionary)
mutableCopy :創建的是可變副本(如NSMutableString、NSMutableArray、NSMutableDictionary)

3.copy基本原則?
答:
修改源對象的屬性和行為,不會影響副本對象
修改副本對象的屬性和行為,不會影響源對象

4.為什麼通過不可變對象調用瞭copy方法, 不會生成一個新的對象?
答:
因為原來的對象是不能修改的, 拷貝出來的對象也是不能修改的
既然兩個都不能修改, 所以永遠不能影響到另外一個對象, 那麼已經符合需求
所以: OC為瞭對內存進行優化, 就不會生成一個新的對象

copy內存管理

1.淺復制(淺拷貝,指針拷貝,shallow copy)
源對象和副本對象是同一個對象
源對象(副本對象)引用計數器+1,相當於做一次retain操作
本質是:沒有產生新的對象

2.深復制(深拷貝,內容拷貝,deep copy)
源對象和副本對象是不同的兩個對象
源對象引用計數器不變,副本對象計數器為1(因為是新產生的)
本質是:產生瞭新的對象

copy和Property

1.@property中的copy的作用是什麼?
答:
(1)防止外界修改內部的數據
(2)可以使用copy保存block, 這樣可以保住block中使用的外界對象的命
block默認存儲在棧中, 棧中的block訪問到瞭外界的對象, 不會對對象進行retain

2.@property內存管理原則?
答:
MRC
1> copy : 隻用於NSStringlock
2> retain : 除NSStringlock以外的OC對象
3> assign :基本數據類型、枚舉、結構體(非OC對象),當2個對象相互引用,一端用retain,一端用assign

ARC
1> copy : 隻用於NSStringlock
2> strong : 除NSStringlock以外的OC對象
3> weak : 當2個對象相互引用,一端用strong,一端用weak
4> assgin : 基本數據類型、枚舉、結構體(非OC對象)

3.如何解決block中的循環引用?
答:如果對象中的block又用到瞭對象自己, 那麼為瞭避免內存泄露, 應該將對象修飾為__block

__block Person *p = [[Person alloc] init]; // 1
p.name = @james;
NSLog(@retainCount = %lu, [p retainCount]);
p.pBlock = ^{
    NSLog(@name = %@, p.name); // 2
};
NSLog(@retainCount = %lu, [p retainCount]);
p.pBlock();

自定義類實現Copy

1.自定義類如何實現copy操作?
答:
(1)以後想讓自定義的對象能夠被copy隻需要遵守NSCopying協議
(2)實現協議中的- (id)copyWithZone:(NSZone *)zone
(3)在- (id)copyWithZone:(NSZone *)zone方法中創建一個副本對象, 然後將當前對象的值賦值給副本對象即可

- (id)copyWithZone:(NSZone *)zone
{
    // 1.創建一個新的對象
    Person *p = [[[self class] allocWithZone:zone] init];
    // 2.設置當前對象的內容給新的對象
    p.age = _age;
    p.name = _name;
    // 3.返回新的對象
    return p;
}
- (id)mutableCopyWithZone:(NSZone *)zone
{
    // 1.創建一個新的對象
    Person *p = [[[self class] allocWithZone:zone] init];
    // 2.設置當前對象的內容給新的對象
    p.age = _age;
    p.name = _name;
    // 3.返回新的對象
    return p;
}

單例ARC和MRC寫法

1.什麼是單例模式?
答:類的對象成為系統中唯一的實例,提供一個訪問點,供客戶類 共享資源
單例就是無論怎麼創建都隻能有一個實例對象

2.什麼情況下使用單例?
答:
(1)類隻能有一個實例,而且必須從一個為人熟知的訪問點對其進行訪問,比如工廠方法。
(2)這個唯一的實例隻能通過子類化進行擴展,而且擴展的對象不會破壞客戶端代碼。

3.創建單例對象的方法一般以什麼開頭?
答:
(1)一般情況下創建一個單利對象都有一個與之對應的類方法
(2)一般情況下用於創建單利對象的方法名稱都以share開頭, 或者以default開頭
單例在多線程的應用?
答:多線程中的單例

+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
    // 以下代碼在多線程中也能保證隻執行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[super allocWithZone:zone] init];
    });
    return _instance;
}

 

 

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *