上一篇已經介紹了App Delegate、View Controller的基本概念,除此以外,分別利用storyboard和純代碼建立了第一個Xcode的工程,並對不一樣方式搭建項目進行了比較。這一篇文章,我準備爲你們介紹一下奇葩的Objective-C語言的語法和使用。這篇文章主要講Objective-C的理論概念。ios
與C++類比學習,聲明定義一個MyObject類,並建立這個類的實例。ajax
介紹類,方法,分類,擴展,協議,消息機制,動態特性selector,block,ARC等概念編程
本文關於Objective-C整理總結的內容比較多,不須要徹底掌握,混個眼熟就成。 網絡
1)對於已經有開發經驗的開發者而言,初次接觸Objective-C的時候以爲根本不能接受,甚至有種畏懼,oc奇葩的語法簡直顛覆了本身的世界觀,由於出現了莫名其妙的符號,如, + - [ ]。可是,不要怕,咱們慢慢來了解這究竟是毛線。從名字便可看出,Objective-C是一個面向對象的編程語言,也就是它具備繼承、封裝、多態的語言特性。閉包
2)那對於沒有任何編程語言的童鞋,如何理解面向對象的編程呢?框架
對於沒有任何編程經驗的童鞋,我想這樣解釋,要弄清楚兩個問題:i)編程到底在作什麼?ii)什麼是面向對象的編程?異步
i)通俗的語言講,編程就是在和計算機說話,用計算機明白的語言跟他交流,讓他幫你作事。(就好像你跟外國人交流同樣,你想跟人家交朋友,總得用人家懂得語言吧~)編程語言
ii)「面向對象編程」,首先只是一個名詞,實質是一種抽象的概念,主要是將一類待處理的數據及數據對應的操做集合化,寫(封裝)在一塊兒。好比,一我的的屬性有,身高、體重、年齡、性別,人能夠作的事情有吃飯、睡覺、打豆豆~全部具備這些特徵的均可以稱之爲人這一類。這即是面向對象的編程。(若是看到這裏還不明白,那仍是要多寫程序,慢慢接受了新的概念有了固化的思惟模式,就能理解並應用了)函數
學習的時候能夠多種語言比較學習。我選擇用C++和Objective-C進行類比,來聲明定義一個MyObject類,比較異同點,瞭解各自面向對象編程的方法。(爲什麼選擇C++?由於,1.C++有指針的概念;2.C++是面向對象的語言。另,指針就是內存的地址。)學習
#include <iostream> using namespace std; class MyObject { public: MyObject(); ~MyObject(); void display(); void setValue(int x); int getIndex(); int getKey(); static void classMethod(); private: int index; int key; }; MyObject::MyObject() { cout<<"construct"<<endl; } MyObject::~MyObject() { cout<<"destruct"<<endl; } void MyObject::setValue(int x) { this->index = x; this->key = 1<<(x+2); } void MyObject::display() { cout<<"index == "<<this->index<<endl; cout<<"key == "<<this->key<<endl; } int MyObject::getKey() { return this->key; } int MyObject::getIndex() { return this->index; } void MyObject::classMethod() { cout<<"this is static (or class) method"<<endl; } int main(int argc, const char * argv[]) { // insert code here... std::cout << "Hello, World!\n"; MyObject *object = new MyObject(); MyObject::classMethod(); object->setValue(3); object->display(); int c = object->getIndex() + object->getKey(); object->MyObject::~MyObject(); printf("c = %d\n", c); MyObject object2; object2.setValue(2); object2.display(); return 0; }
Hello, World!
construct
this is static (or class) method
index == 3
key == 32
destruct
c = 35
construct
index == 2
key == 16
destruct
Program ended with exit code: 0
以上代碼利用C++聲明定義了MyObject類
1)定義了公有方法方法:
2)定義了私有成員變量:
選擇OS X中的Command Line Tool,建立好工程後,按住command+N鍵建立Cocoa Touch Class,建立一個名爲MyObject的NSObject的子類。
這樣就建立了OS X的命令行程序,以用於簡單演示如何聲明定義Objective-C的類
1)main.m文件:
#import <Foundation/Foundation.h> #import "MyObject.h" int main(int argc, const char * argv[]) { @autoreleasepool { // insert code here... NSLog(@"Hello, World!"); MyObject *object = [[MyObject alloc] initWithIndex:3]; [object display]; // object = nil; } return 0; }
2) MyObject.h
#import <Foundation/Foundation.h> @interface MyObject : NSObject - (instancetype)initWithIndex:(NSInteger)index; - (void)display; + (void)classMethod; @end
3) .m文件
#import "MyObject.h" @interface MyObject() @property (assign, nonatomic) NSInteger index; @property (assign, nonatomic) NSInteger key; @end @implementation MyObject @synthesize index = _index; @synthesize key = _key; - (instancetype)initWithIndex:(NSInteger)index { self = [super init]; if (self) { NSLog(@"init"); self.index = index; } return self; } - (void)setIndex:(NSInteger)index { _index = index; self.key = 1<<(index+2); } - (NSInteger)index { return _index; } - (NSInteger)key { return _key; } - (void)display { NSLog(@"index == %ld \n key == %ld", (long)_index, (long)_key); } + (void)classMethod { NSLog(@"this is static (or class) method"); } - (void)dealloc { NSLog(@"dealloc"); } @end
2016-01-10 17:55:50.401 CompileOC[20792:1052939] Hello, World!
2016-01-10 17:55:50.402 CompileOC[20792:1052939] init
2016-01-10 17:55:50.402 CompileOC[20792:1052939] index == 3
key == 32
2016-01-10 17:55:50.402 CompileOC[20792:1052939] dealloc
Program ended with exit code: 0
3.2.4 代碼解釋
1) 在main.m文件中建立了MyObject的實例並調用display方法。
2)在頭文件中聲明瞭三個公有方法,
- (instancetype)initWithIndex:(NSInteger)index;
- (void)display;
+ (void)classMethod;
3).m文件中
- (void)display
+ (void)classMethod;
4)與C++代碼作對比
@interface
@end
之間就能夠了,而私有方法不須要在頭文件中聲明。
@implementation {
@private
int index;
int key;
}
@end
注意實例變量和類的屬性並非一回事,屬性和實例變量的本質區別是,屬性沒法直接訪問對象的內部狀態,可是能夠利用setter和getter方法進行訪問,而在setter和getter方法中還能夠包含其餘邏輯,好比,本文章中
- (void)setIndex:(NSInteger)index
方法,不單爲實例變量_index賦值,還用setter的簡潔方式
self.key = 1<<(index+2);
爲實例變量_key賦值。
那_index和_key實例變量是誰聲明的呢?這是Xcode編譯器本身生成的:
@synthesize index = _index;
@synthesize key = _key;
上面的代碼使用了 @synthesize 編譯指令,讓編譯器分別爲屬性index和key自動建立實例變量_index和_key。即,自動爲屬性建立對應實例變量的方法是
@synthesize 屬性名 = 實例變量名;
事實上,當沒有實現setter方法時,@synthesize指令不寫,編譯器也能夠爲屬性自動建立實例變量,編譯器自動爲屬性建立的變量名默認爲_屬性名,在調試的時候能夠設置變量觀察。
-fno-objc-arc
便可聲明方法:
@implementation {
//聲明實例變量
}
@end
實例變量是是類封裝的數據
@property (特性) 類型 屬性名;
屬性是Objective-C提供的訪問對象共享狀態的機制,編譯器能夠自動生成訪問實例變量的方法。Xcode自動建立的實例變量默認變量名爲「_屬性名」
@interface MyObject : NSObject
@end
通用的以下:
@interface 類名 : 父類名
@end
說明:
@implementation {
//實例變量的聲明
}
//屬性和方法的定義
@end
說明:
//code here
return 返回值;
}
說明:
「不一樣的類能夠擁有相同的 selector,這個沒有問題,由於不一樣類的實例對象performSelector相同的 selector 時,會在各自的消息選標(selector)/實現地址(address) 方法鏈表中根據 selector 去查找具體的方法實現IMP, 而後用這個方法實現去執行具體的實現代碼。這是一個動態綁定的過程,在編譯的時候,咱們不知道最終會執行哪一些代碼,只有在執行的時候,經過selector去查詢,咱們才能肯定具體的執行代碼。」
多參數的聲明、實現和調用。例如,我在MyObject中定義一個多參數的請求方法:
- (void)requestDataWithIndex:(NSInteger)index forKey:(NSInteger)key completion:(void(^)(NSError *error, id response))completion { //code here NSError *responseError = nil;//assume it is responsed from server NSDictionary *responseData = @{@"message": @"OK"}; if (completion != nil) { if (responseError != nil) { completion(responseError, nil); } else { completion(nil, responseData); } } }
說明:
其實就是寫在類.m文件中的接口,只不過與類.h中接口相比,在.m文件中聲明的實例變量、屬性、方法外部不能訪問,即實現了方法、屬性的私有化。例如MyObject.m文件中
@interface MyObject()
@property (assign, nonatomic) NSInteger index;
@property (assign, nonatomic) NSInteger key;
@end
這段代碼就是擴展,而且聲明的index和key屬性外部不能訪問,只能在類的內部訪問。
分類的目的主要是爲了擴展類的方法,好比MyObject類我添加一個NY的分類,建立方法以下:
#import "MyObject.h" @interface MyObject (NY) @end
#import "MyObject+NY.h" @implementation MyObject (NY) @end
說明:
/Users/.../CompileOC/CompileOC/MyObject+NY.m:10:1: Duplicate interface definition for class 'MyObject'
@protocol NYProtocol <NSObject>
@optional
- (void)nyOptionalProtocalMethod;
@required
- (void)nyRequiredProtocalMethod;
@end
通用:
@protocol 協議名 <NSObject>
@optional
//可選擇實現的方法
@required
//必須實現的方法
@end
@interface MyObject() <NYProtocol>
@property (assign, nonatomic) NSInteger index;
@property (assign, nonatomic) NSInteger key;
@end
說明:
ARC是Objective-C提供的內存管理方式,系統根據對象被引用的次數計次,當引用計數爲零時,自動釋放該對象所佔有的內存。而非系統自動管理內存的方式,稱爲MRR(Manual Retain Release),老的項目代碼中仍會有手動管理內存的代碼。你會看到 retain 、 release、 autorelease 、dealloc這樣的消息(方法)代碼,以用來管理內存。可是在ARC模式下並不能手動編寫這些代碼,當引用一個對象時,即這個對象引用計數加一,當這個對象中某個指針,例如,本文中的 object = nil 時,引用計數減一,引用計數爲零時,系統自動釋放對象所佔用的內存。
但在Xcode5以後,建立項目時沒法限定非ARC模式,並且「基本如今開發的項目都使用ARC」,因此,對於初學者來講,手動內存管理就暫時不須要更深刻的瞭解了。但若是,但願能實現ARC與MRR的混編譯,那麼就須要在Targets的Build Phases選項下Compile Sources下選擇要不使用ARC編譯的文件,雙擊它,輸入-fno-objc-arc
便可實現ARC和MRR混編。
本篇文章主要介紹了 Objective-C 的基本語法,但願初學者讀完以後能對 Objective-C 編程語言有一點基本的瞭解,打消一部分 Objective-C 這種陌生的編程語言的畏懼感,從而能繼續往下學。
關於學習的方法,我還想說幾句。我認爲,人接觸新鮮事物總會有種恐懼感,適當的恐懼感反而會更有意思,恐懼感太強烈會阻礙接受新的概念。接受新觀念確定是須要必定時間,由於原有的觀念已經給思惟產生一個定式,新觀念可能和舊觀念有衝突的地方,但確定二者之間也存在必定聯繫。找出二者的共同點,能快速理解新概念。因此,我以爲學習一種新事物,首先要接受,慢慢的就適應了,不急~咱還年輕~
http://blog.csdn.net/kesalin/article/details/8155245
十分感謝萌萌噠樂樂(https://medium.com/@HiSuneBear)給我提的排版建議及文章評價,讓我有更強烈的動力把文章寫好(這篇文章寫的太長,截至2016-01-11 17:41:55 我寫了快三天。因此,最後有點累,不想寫了,可是樂樂童鞋讓個人小宇宙又從新燃了😂 決心要把這篇文章拉回正軌~~)。另外,也十分感謝 @朱不鳴 @D 兩位小童鞋對文章的批評建議~我會努力把文章寫好,但願能給更多的人幫助,謝謝!
最後,預告一下接下來的文章內容:
敬請期待吧😉 ~