Objective-C 30分鐘入門教程

我第一次看OC以爲這個語言的語法有些怪異,爲何充滿了@符號,[]符號,函數調用沒有()這個,可是面向對象的高級語言也不外乎類,接口,多態,封裝,繼承等概念。下面會把OC裏面的一些定義與Java,C++做對比,讓有其餘面嚮對象語言的同窗能夠快速的瞭解OC是個神馬語言。html

1.類定義

類用@interface定義,而不是@class,至關於Java中的class了。而Object-C中接口(Java中的接口)是用@protocol(下面有介紹)表示。java

頭文件,與c++的頭文件相似ios

複製代碼
 1 #import <Foundation/Foundation.h>
 2 @interface Fraction : NSObject
 3 //成員變量
 4 {
 5 @protected
 6     int numerator;
 7     int denominator;
 8 }
 9 //類方法
10 -(void) print;
11 //多參數函數
12 -(id)initSetNum:(int) n over:(int) d;
13 -(id) init;
14 @end
複製代碼

實現.m文件(至關於c中的.cpp)c++

複製代碼
 1 #import "Fraction.h"
 2 
 3 @implementation Fraction
 4 
 5 -(void) print {
 6     NSLog(@"print");
 7 }
 8 
 9 -(id)init{
10     self = [super init];
11     if (self != nil) {
12         self->denominator = 1;
13         self->numerator = 1;
14     }
15     return self;
16 }
17 -(void)set:(int)n over:(int)d {
18     self->denominator = d;
19     self->numerator = n;
20 }
21 
22 @end
複製代碼

init模板

複製代碼
1 -(id)init{
2     self = [super init];
3     if (self) {
4         //do init 
5     }
6     return self;
7 }
複製代碼

2.訪問權限

實例變量的做用域

  • @protected: 實例變量可被該類和子類中定義的方法直接訪問。接口部分定義的實例變量是此做用域
  • @private: 只能被定義在此類中的方法直接訪問。定義在實現部分的實例變量默認爲此做用域
  • @public: 可被此類中的方法、子類或其餘類直接方法(訪問方法見下面點語法)
  • @package: 對於64位鏡像,能夠在實現改類的鏡像中的任何地方訪問此實例變量(不瞭解,沒用過)

@property做用域

@property只在@interface中使用,是默認的@protected權限數組

方法的做用域xcode

@protected,@private,@public,@package不適用實例方法,在@interface中定義的方法都是@public方法多線程

私有方法

1.不在@interface中聲明,直接寫到@implemention裏。
2.寫在空分類中。

3.@property和@synthesize

語法app

@property(attribute1, attribute2, ...) type name;框架

做用1:生成成員變量的get和set方法
1 @interface Fraction : NSObject
2 @property int numerator, denominator;
3 -(void)print;
4 @end
複製代碼
1 @implementation Fraction
2 @synthesize numerator = _abc, denominator = _def;
3 
4 -(void) print {
5     self->_abc = 12;
6     self->_def = 30;
7 }
8 @end
複製代碼
複製代碼
 1 #import <Foundation/Foundation.h>
 2 #import "Fraction.h"
 3 
 4 int main(int argc, const char * argv[]) {
 5     @autoreleasepool {
 6         // insert code here...
 7         Fraction * fraction = [[Fraction alloc]init];
 8         [fraction setNumerator:10];
 9         NSLog(@"numerator is %d", [fraction numerator]);
10         
11         fraction.numerator = 20;
12         NSLog(@"numerator is %d", fraction.numerator);
13     }
14     return 0;
15 }
複製代碼

@property int numerator, denominator;函數

@synthesize numerator = _abc, denominator = _def;

兩句話爲咱們生成了(暫時不考慮內存管理)

複製代碼
 1 (void) setNumerator:(int) n {
 2     //@synthesize numerator, denominator; 如果這樣則
 3     //self->numerator = n;
 4     self->_abc = n;
 5 }
 6 
 7 (void) setDenominator:(int) n {
 8     self->_def = n;
 9 }
10 
11 (int) numerator {
12     return self->_abc;
13 }
14 
15 (int) denominator {
16     return self->_abc;
17 }
複製代碼
若是不寫@synthesize,編譯器會自動生成@ synthesize name = _name

若寫@synthesize name,則至關於寫了@synthesize name = name

點語法

oc的點語法比較特殊,c++或java定義一個實例變量,則能夠this->num或instance.num就能夠取得次變量了,可是oc不行!點至關於調用set和get方法,而且oc中的實例方法調用也不能用點(get set不算),好比instance.print()是不行的,要[instance print]才行

做用2:協助內存管理

attribute主要分三類:

  • 讀寫屬性:(readwrite/readonly)決定是否生成set訪問器,默認爲readwrite
  • setter語義:(assign/retain/copy/strong/weak/unsafe_unretained)set訪問器的語義,決定已何種方式對數據成員賦予新值,默認爲assign
  • 原子性:(atomic/nonatomic)是不是原子性訪問,默認爲nonatomic

readwrite: 生成setter/gettter方法(默認)

readonly: 只生成getter。@synthesize不會生成setter方法,因此不能和copy/retain/assign同時使用

assign: 簡單賦值,不更改索引計數

retain: 釋放舊的對象,將舊對象的值賦予輸入對象,在增長輸入對象的引用計數(+1)。此屬性只能用於Objective-c對象類型,不能用於基本類型和Core Foundation對象(Core Foundation?此乃何物),由於他們沒有引用計數

strong/weak/unsafe_unretained: xcode5加入的新屬性,strong = retain,unsafe_unretained = assign,weak ~= assign,在引用計數爲0時,對吧對象賦值爲nil

copy: 創建一個引用計數爲1的對象,而後釋放舊對象。此屬性只對實現了NSCopying的對象類型有效

atomic/nonatomic: setter和getter是否是原子操做,若是是atomic則在多線程狀況下,setter和getter中不會被阻塞(切換線程)

4.分類(category)、擴展(extension)和協議(protocol)

分類

這個概念在c++和java我找不到對應的概念,算是oc特性了

在一個類已經定義好了的狀況下,又想向類中增長一些新方法,可是有不想改原來的實現文件,或是找不到實現文件,這就是分類發揮做用的時候了,好比想在Fraction類中增長-(void)double方法,用分類能夠這麼搞

MathOps.h文件

1 #import "Fraction.h"
2 @interface Fraction(MathOps)
3 -(void)double;
4 @end

MathOps.m文件

1 #import "Fraction.h"
2 @implementation Fraction(MathOps)
3 -(void)double {
4     [self numerator] = [self numerator] * 2;
5 }
6 @end

這樣就能夠在Fraction的實例上使用[fraction double];了

類實例變量的擴展(extension)

類擴展(extension)是category的一個特例,有時候也被稱爲匿名分類。他的做用是爲一個類添加一些私有的成員變量和方法。

類實例的擴展只能在未命名分類中定義,在命名分類中是不容許的,而且要寫在響應的.m文件中

複製代碼
1 #import "Fraction.h"
2 @interface Fraction() //括號裏是空就是了
3 {
4     int MaxNum;
5 }
6 
7 @property int minNum;
8 
9 @end
複製代碼

Objective-C第229頁說,未命名分類是很是有用的,由於他們的方法都是私有的,若是要謝一個類,並且數據和方法僅供這個類自己使用,未命名分類比較合適,可是使用@selector依然能夠訪問,例如[A performSelector: @selector(privateTest)];

協議@protocol

協議有點像java中的接口,只提供方法的聲明,實現由使用此協議的類來實現

1 @protocol NSCopying
2 -(id)copyWithZone:(NSZone *)zone;
3 @end

採用協議的類用<protocolName1,protocolName,...>來聲明採用了protocolName協議

@interface className: NSObject

協議中的方法類中不用所有實現,@optional後的方法不必定要實現,@required或默認的方法必定要實現

複製代碼
1 @protocol Drawing
2 -(void)paint;   //採用的類中必須實現
3 -(void)erase;   //採用的類中必須實現
4 @optional
5 -(void)outline; //採用的類中不必定實現
6 @required
7 -(void)showDetail; //採用的類中必須實現
8 @end
複製代碼

能夠在聲明對象時候指明它採用的協議,這樣在賦值時由編譯器檢查被複制對象是否採用了協議,若沒有則發出警告

id<Drawing> currentOBject;

協議自身也能夠擴展其餘的協議 @protocol Drawing3D<Drawing>

分類也能夠採用協議 @interface Fraction(Stuff)這是啥??

5.Foundation框架

Foundation框架,Application Kit框架,Cocoa

框架是由許多類、方法、函數和文檔按照必定的邏輯組合起來的集合,在Mac OS X系統下大約有90多個框架。

爲全部的程序開發奠基基礎的框架稱爲Foundation框架,它容許使用一些結拜的對象,如數字和字符串,一些對象集合,如數字、字典和集合。其餘功能包括處理日期和時間、自動化的內存管理、文件系統等。

Application Kit框架包含普遍的類和方法,它們用來開發交互式的圖形應用程序,使得開發文本、菜單、工具欄、表、窗口之類的過程變得十分簡便(Application Kit開發Mac app,UIKit開發手持IOS ap)。術語Cocoa Touch是指Foundation、Core Data和UIKit框架。術語Cocoa是指Foundation、Core Data、Application Kit框架。

  • NSNumber: 把int、float、char等基本類型搞成對象,以即可以放到NSArray等必須存儲對象的容器。
  • NSString/NSMutableString: 字符串類,一個不可變,一個可變
  • NSArray/NSMutableArray: 數組類,一個不可變,一個可變
1 NSArray * name = [NSArray arrayWithObjects:@"zhangsan", @"lisi", @"dawang", nil];
2 
3 NSMutableArray * nameMutable = [NSMutableArray array];
4 for (int i = 0; i < 10; i++) {
5     nameMutable = [NSNumber numberWithInteger: i];
6 }
  • NSValue: 把Foundation集合中的非對象(int、float等用NSNumber)好比C中結構體CGPoint包裝(wrapping)成對象,使用時再把對象展開(unwrapping)獲得CGPoint。
複製代碼
 1 CGPonit myPonit;
 2 NSValue * ponitObj;
 3 NSMutableArray * touchPoints = [NSMutableArray array];
 4 
 5 myPonit.x = 100;
 6 myPoint.y = 200;
 7 
 8 pointObj = [NSValue valueWithPoint:myPint];
 9 [touchPoints addObject: pointObj];
10 
11 myPoint = [[touchPoints lastObject]pointValue];
複製代碼
  • NSDictionary/NSMutableDictionary: 字典,keyValue結構
複製代碼
 1 NSMutableDictionary * glossary = [NSMutableDictionary dictionary];
 2 
 3 [glossary setObject:@"zhangSan" forKey:@"zhang"];
 4 [glossary setObject:@"zhaoSi" forKey:@"zhao"];
 5 
 6 NSLog(@"name zhang is: %@", [glossary objectForKey:@"zhang"]);
 7 
 8 NSDictionary * glossaryDic = 
 9 [NSDictionary dictionaryWithObjectsAndKeys:
10 @"zhangSan", @"zhang",
11 @"zhaoSi", @"zhao",
12 nil];
13 
14 for (NSString * key in glossaryDic) {
15     NSLog(@"%@:%@", key, [glossary objectForKey: key]);
16 }
複製代碼
  • NSSet/NSMutableSet/NSIndexSet: 集合類,可用的操做包括搜索、添加、刪除、比較、計算交集、計算並集等操做。

6.ARC內存管理

ARC(Automatic Reference Counting)自動引用計數(神馬是引用計數自行腦補)。Xcode 4.2版本以後加入的新特性。Xcode4.2以前的內存管理要內存要當心的處理引用計數,retain,release,autorelease在代碼中隨處可見。

XCode4.2以後的ARC是在編譯的時候由編譯器在代碼中添加retain,release,autorelease代碼,程序要要作的就是開啓ARC(默認開啓)功能,在@property屬性參數中聲明號strong,weak等屬性就好了(定義變量時也能夠用strong,weak等)。開啓ARC後不能使用retain,release,編譯不經過。

@autorealeasepool

任何在@autoreleasepool{}中定義的變量都是autorelease的,在出@autoreleasepool{}做用域時,會對其中的變量作一次release操做。

Cocoa和IOS應用程序中也有這個@autoreleasepool{},也就是說Cocoa和IOS中的變量都是autorelease的,每幀循環後會對autoreleasepool中的對象作一次pop操做,把對象從autoreleasepool中刪除,並作一次release。Objective-C Autorelease Pool 的實現原理這個介紹了ios中的autorealeasepool

7.雜項

NSLog(@"%@", object)

NSLog添加了%@這麼一個輸出格式,%@對應的對象在編譯後會被替換爲對descriptionWithLocal方法的調用,若是此方法不存在,則替換爲description方法的調用 。

8.selector

SEL 類成員方法的指針

能夠理解 @selector()就是取類方法的編號,他的行爲基本能夠等同C語言的中函數指針,只不過C語言中,能夠把函數名直接賦給一個函數指針,而Object-C的類不能直接應用函數指針,這樣只能作一個@selector語法來取.

它的結果是一個SEL類型。這個類型本質是類方法的編號(函數地址)

C/C++函數指針

 

int test(int val)

{
return val+1;

}

int (* c_func)(int val); //定義一個函數指針變量c_func = add ; //把函數addr地址直接賦給c_func

 

object-c的選擇器,

@interface foo
-(int)add:int val;

@end

SEL class_func ; //定義一個類方法指針class_func = @selector(add:int);

注意一、@selector是查找當前類(含子類)的方法。

舉例:

父類.h文件

複製代碼
 1 #import <Foundation/Foundation.h>  
 2   
 3 @interface SelectorDemo : NSObject  
 4 {  
 5     SEL _methodTest;  
 6 }  
 7   
 8 @property (nonatomic,assign) SEL methodTest;//這裏聲明爲屬性方便在於外部傳入。  
 9   
10 -(void)TestParentMethod;  
11   
12 -(void)TestSubMethod;  
13   
14   
15 @end  
複製代碼

.m文件

複製代碼
 1 #import "SelectorDemo.h"  
 2   
 3 @implementation SelectorDemo  
 4   
 5 @synthesize methodTest = _methodTest;  
 6   
 7 -(void)parentMethod  
 8 {  
 9     NSLog(@"parent method Call Success!");  
10 }  
11   
12 -(void)TestParentMethod  
13 {  
14     if (_methodTest)  
15     {  
16         [self performSelector:_methodTest withObject:nil];  
17     }  
18 }  
19   
20 -(void)TestSubMethod  
21 {  
22     if (_methodTest)  
23     {  
24         [self performSelector:_methodTest withObject:nil];  
25     }  
26 }  
27   
28 @end  
複製代碼

子類.h文件

1 #import <Foundation/Foundation.h>  
2 #import "SelectorDemo.h"  
3   
4 @interface SelectorSub : SelectorDemo  
5   
6 @end  

.m文件

複製代碼
#import "SelectorSub.h"  
  
@implementation SelectorSub  
  
-(void)SubMethod  
{  
    NSLog(@"Sub method Call Success!");  
}  
  
@end 
複製代碼

進行測試調用。

SelectorSub *ss = [[SelectorSub alloc]init];  
    ss.methodTest = @selector(parentMethod);  
    [ss TestParentMethod];  
    ss.methodTest = @selector(SubMethod);  
    [ss TestParentMethod];  
    [ss release]; 

ss.methodTest = @selector(parentMethod); 這句在運行期時,會尋找到父類中的方法進行調用。

ss.methodTest = @selector(SubMethod);//這句就在運行期時,會先尋找父類,若是父類沒有,則尋找子類。

若是這裏將ss.methodTest = @selector(test); 其中test即不是ss父類,也不是ss自己,也非SS子類,哪麼這個時候在使用

[self performSelector:_methodTest withObject:nil];就會出現地址尋找出錯 。

[friend performSelector:@selector(gossipAbout:) withObject:aNeighbor];

等價於:

[friend gossipAbout:aNeighbor]; 

經過這個原理,當把屬性設置爲SEL類型時,若是回調機制使用的不是SEL聲明的類或子類。想實現其它類的回調,必須傳入其它類的上下文句柄。 

複製代碼
#import <Foundation/Foundation.h>  
  
@interface SelectorDemo : NSObject  
{  
    SEL _methodTest;  
    id _handle;  
}  
  
@property (nonatomic,assign) SEL methodTest;  
@property (nonatomic,retain) id handle;        //添加其它類的實例句柄屬性。  
-(void)TestParentMethod;  
-(void)TestSubMethod;  
  
@end 
複製代碼
複製代碼
#import "SelectorDemo.h"  
  
@implementation SelectorDemo  
  
@synthesize methodTest = _methodTest;  
@synthesize handle = _handle;  
  
-(void)parentMethod  
{  
    NSLog(@"parent method Call Success!");  
}  
  
-(void)TestParentMethod  
{  
    if (_methodTest)  
    {  
        [_handle performSelector:_methodTest withObject:nil];//這裏面原來self屬爲相應的實例句柄  
    }  
}  
  
-(void)TestSubMethod  
{  
    if (_methodTest)  
    {  
        [_handle performSelector:_methodTest withObject:nil];  
    }  
}  
  
@end  
複製代碼

即可如此調用

C * c = [[SubS alloc]init];
        
c.methodTest = @selector(Show);
c.handle = [[AnotherC alloc]init];
        
[c handleTest]; 

9.Block

有參數有返回值的demo

複製代碼
 1 - (void)myThirdBlock
 2 {
 3     //1.定義block
 4     double (^myThirdBlock)(double,double) = ^ (double r1,double r2){
 5         return r1 + r2;
 6     };
 7     //2.調用block
 8      double r3 = myThirdBlock(1.1,2.2);
 9     NSLog(@"有參數有返回值:%f",r3);
10 }
複製代碼

block的注意點

1)Block內部能夠訪問外部變量;

2)默認狀況下,Block內部不能修改外部的局部變量

3)給局部變量加上__block關鍵字,則這個局部變量能夠在block內部進行修改

示例代碼以下: 

複製代碼
1 - (void)myFourBlock
2 {
3     int num = 5;
4     void (^myFourBlock)() = ^{
5     
6         num = 6;
7         NSLog(@"%d",num);
8     };
9 }
複製代碼

 

//發現須要的再加

結語

本博介紹了OC的核(pi)心(mao)概念,但願看完本博能夠對讓你對OC有一個大致的認識,學OC是學ios的第一步, 打下堅實的OC仍是很必要的。

參考

 
相關文章
相關標籤/搜索