++ 概述 ++
目前來說,Objective-C(簡稱OC)是iOS開發的核心語言,在開發過程中也會配合着使用C語言、C++,OC主要負責UI界面,C語言、C++可用于圖形處理。
* 基于C語言:C語言是一門面向過程的語言,OC是在C語言的基礎上,增加了一層最小的面向對象文法,為什麼說是最小的面向對象文法呢?因為OC把一些比較複雜的面向對象文法都去掉了,剩下的都是面向對象的精華,是以OC是一門面向對象的語言,而且會比C++簡單很多。因為OC是基于C語言的,是以完全相容C語言,也就是說我們在開發iOS程式過程中,可以在OC代碼中混入C語言代碼,甚至是C++代碼。
文法概述:
1.沒有包名(命名空間)的概念
在Java中,為了防止兩個類名相同的類沖突,你可以将這2個類放在不同的包裡面。OC中并沒有”包”的概念,也就是沒有命名空間機制,取而代之的是開發人員給類名加上字首,使用字首可以有效的防止類名沖突。比如NSString(OC中的字元串類)、NSArray(OC的數組類),它們的字首都是NS
2.關鍵字都以@開頭
OC代碼中是可以混入C語言、C++代碼的,而C語言和C++作為一門程式設計語言,都有自己的關鍵字。為了防止跟C語言、C++關鍵字沖突,OC的關鍵字都以@開頭。
甚至字元串都是以@開頭的,比如@“Hello”是OC中的字元串,而”Hello”則是C語言中的字元串。
文法要點:
Oc沒有垃圾回收;
源檔案字尾為.m;入口程式同c,也是main()
導包使用 #import 也不用使用條件編譯加入頭檔案;#import會自動判斷是否已經添加過該頭檔案。
++ 面向對象文法+
類 *
一般用2個檔案來描述一個類;
1> .h:類的聲明檔案,用于聲明成員變量、方法。類的聲明使用關鍵字@interface和@end。
[注意:.h中的方法隻是做一個聲明,并不對方法進行實作。也就是說,隻是說明一下方法名、方法的傳回值類型、方法接收的參數類型而已,并不會編寫方法内部的代碼。]
.m:類的實作檔案,用于實作.h中聲明的方法。類的實作使用關鍵字@implementation和@end。
.h
//用于聲明Student這個類由哪些成員變量和方法(面對對象稱方法,面向過程稱函數)
//導包,Foundation包含了常用的類,(類似java中的java.lang類)
#import <Foundation/Foundation.h>
//@interface表示聲明一個類,後是類名;必須要指定繼承的父類(java中是自動繼承object)
// : 即是繼承
//@end表示一個類的結束
@interface Student : NSObject{
//成員變量要定義在大括号中;
int age;
int no;
}
//OC在.h中聲明的方法都是公用方法
//Oc中凡是方法類型都用括号括起來(int)
//成員變量age的get方法
// - 代表動态方法,就是對象内部方法;+ 代表靜态方法
- (int)getAge;//OC中不建議使用get*寫法,建議直接與變量名一樣
-(int)age;
//age的set方法;一個冒号對應一個參數
- (void)setAge:(int)newAge;
//同時設定兩個參數的set方法
-(void)setAge:(int)newAge andNo:(int)newNo;
-(int)no;
@end
使用:
int main(int argc, const char * argv[]) {
@autoreleasepool {
//建立對象
//1.調用一個靜态方法alloc來配置設定記憶體
//2.建立一個該對象的指針指向剛建立的記憶體空間
Student *stu = [Student alloc];
//3.調用一個動态方法進行初始化;
//相當于調用了Student對象的init方法;
stu = [stu init];
[stu setAge:];
[stu getAge];
[stu age];
//上面三步可合并為
Student *stu1 = [[Student alloc] init];
[stu1 setAge: andNo:];
NSLog(@"age :%d,no %d:",[stu1 age],[stu1 no]);
//釋放對象,但若選擇了ARC編譯器會自動添加
[stu release];
}
return ;
}
++ 點文法 ++
為了友善其他程式員熟悉而做的處理;其本質還是方法調用
Person *person = [[Person alloc] init];
//點文法,為了友善其他程式員熟悉而做的處理
// [person setAge:10];
// 注意:不是通路成員變量;為了防止混淆,OC規範成員變量以_開頭
person.age = ;//等效于[person setAge:10];(
// int age = [person age];
int age = person.age;//等效于 int age = [person age];
方法名:
//方法也是方法名的一部分;故該方法的方法名是setAge:
-(void)setAge:(int)newAge;
//故該方法的方法名是setAge:andNo:
//-(void)setAge:(int)newAge andNo:(int)newNo;
//方法名是age;
-(int)age;
注意:
@implementation Person
-(void)setAge:(int)newAge{
_age = newAge;
//方法相當于[self setAge:newAge],即又調用了自身,則會無限循環調用自己
// self.age = newAge;
}
-(int)age{
//相當于[self age],也會調用自身,會無限調用自己
// return self.age;
return _age;
}
@end
stu->age;是直接通路成員變量,但隻能通路@public修飾的變量;
stu.age=18;是調用setAge方法。
++ 構造方法 ++
.h中
//自定義一個構造方法,是一個動态方法,内部方法
//由于系統的構造方法傳回都是id,為保持一緻,也傳回id;(id可代表所有OC對象指針)
-(id)initWithSize:(int)size andPrice:(double)price;
.m中
//實作構造方法
-(id)initWithSize:(int)size andPrice:(double)price{
//首先要調用父類的實作方法
// self= [super init];
//再進行指派
//父類傳回的對象可能會為空
//相當于if (self!=nil)
// if (self){
// _size = size; //或 self._size = size;
// _price = price;
// }
//或者上面的可簡化為
if (self = [super init]) {
_size = size;
_price = price;
}
return self;
}
//重寫,類似于java中對象的toString
//...同java,代表多個參數
//NSString *str = @"str";是OC中的字元串,為差別C,都加 @;
- (NSString *)description
{
return [NSString stringWithFormat:@"size:%i,price:%f", _size,_price];
}
//%@表示列印一個OC對象,需重寫(NSString *)description方法(同java的toString);
NSLog(@” to string %@“,car);
…同java,代表多個參數
[所有傳回*的地方都可以用id代替,且id是關鍵字,不能直接做變量名]
++ 變量的使用域:
類的成員變量預設是protected的,一般使用預設的即可,不需要添加修飾符
@public :全局都可通路,成員變量可用->直接通路;
@protected:隻能在類内部和子類通路
@private :隻能在類内部通路
(OC中沒有包的的概念,故沒有default)
- 代表動态方法,就是對象内部方法;
+ 代表靜态方法
[靜态方法同java,也可使用self,但不同的是在靜态方法中的self意思是指向的類名,而不是self對象]
(即 誰調用方法,self就指向誰)
靜态方法不能通路成員變量;
在頭檔案中聲明的方法都是public的;
若直接寫在.m檔案中的方法,沒有在.h檔案中進行聲明,那麼這個方法是私有方法
++ 記憶體釋放
系統自帶的靜态方法建立的對象都會自動釋放;
1.在定義時自動釋放:
Car *car = [[[Car alloc] initWithSize:10 andPrice:23.0f] autorelease];
2.手動釋放
[person release];
autorelease 是在适當的時機釋放,而不是馬上釋放.
++new ++
Student *stu= [Student new];//相當于Student *stu = [[Student alloc] init]
但很少用new,這是新版本才添加的關鍵字;
++ @property++ 生成set/get的聲明
為了解決set/get方法的備援的麻煩;
隻用在.h檔案裡,用于聲明方法(set/get)
@property int age;//編譯器遇到@property時,會生動生成set/get方法的聲明
++ @synthesize++ 生成set/get的實作[同@property是編譯器的特性]
為了解決set/get的實作
@synthesize age,_no,height;//相當于三個成員變量的實作
[若用synthesize了,即可在.h檔案中不寫成員變量age,_no,height,會預設去通路與age同名的變量,若找不到同名的變量,會自動生成一個同名變量,并且若自己定義的成員變量的名字與@synthesize不一樣時,會預設建立自動生成的]
[但為了統一風格,成員變量以_開頭,需要指定@synthesize預設生成的變量名,如:@synthesize age=_age,no=_no,height=_height;]
**故在定義類的成員變量時,一般需聲明變量名;直接在頭檔案使用@property,.m檔案中使用@synthesize;
[Xcode在4.5後添加了新特性:.m檔案中的@synthesize都可省略(會自動生成@synthesize age=_age,no=_no,height=_height;這句代碼,預設自帶下劃線),也就是直接在.h檔案中用@property聲明即可]
[但自己寫的set/get會優先使用;若自己手動實作了get/set方法,Xcode就不會自成生成@synthesize,也不會生成set/get方法]
++ 記憶體管理 ++
管理範圍:任何繼承了NSObject的對象,對基本的資料類型不需要;
原理:每個對象内部都儲存了一個與之有關的整數,稱為引用計數器;每當使用alloc,new,copy建立一個對象時,對象的引用計數器被設定為1;給對象發送一條retain消息,可以引用計數器值+1;給對象發送一條release消息,可使引用計數器值-1;當一個對象的引用計數器值為0時,那麼它将被銷毀,其占用的記憶體被系統回收,OC也會自動向對象發送一條dealloc消息.一般會重寫dealloc方法,在這裡釋放相關資源.[但一定不要直接調用dealloc方法,是系統自動調用該方法]
— 可用retainCount消息獲得目前對象的引用計數器值;
[java中new了一個對象後若沒有變量引用,則會自己銷毀;但在OC中,若建立了一個對象,沒有變量引用,計數器值會為1,若沒有手動回收或關閉app,則永不會被回收,]
- (void)dealloc
{
NSLog(@"系統調用回收方法");
//一定要調用super的dealloc方法,而且最好放在最後面調用
[super dealloc];
}
[stu release];方法隻能調用一次,若調用多次,會發生野指針錯誤(通路了不屬于你的記憶體)
— “誰建立,誰釋放”;若用alloc,new,copy的建立的對象,就必須調用release或autorelease來釋放;不是你建立的,就不用你去釋放(一般來說,除了alloc,new,copy,一般都是autorelease的);
—“誰retain,誰release”隻要調用retain,無論這個對象是誰建立的,都需要release釋放;
ARC特性(auto reference count):4.5後的新特性,由編譯器自動進行記憶體釋放;
++ 對象之間的記憶體管理 ++
//直接調用set的一個對象,對象沒有被回收,會造成記憶體洩露
[stu setBook:[[Book alloc] initWithID:100]];
對象的set方法也會建立一個對象,對象的計數+1;需要對原對象釋放;
-(void)setBook:(Book *)book{
if(_book != book){//傳進來的變量可能已經釋放,為了正确,需判斷是否為同一個,不是同一個才進行釋放和引用;也能保證在多次調用時引用的計數器值不會增加,不會出現記憶體洩露的情況;
[_book relase];//先釋放舊的成員變量,且不用擔心空指針;
_book = [book retain];//再retain傳進來的對象
}
}
[//可在頭檔案中用 @property (retain )Book *book;代替上面的set方法 ]
[**OC中若對象為nil,調用其方法不能出現空指針異常]
[stu release];/若stu已經釋放過了再釋放,是野指針會出錯
[nil release];//是空指針,再釋放,不會報錯;
//野指針;在記憶體中指針仍保留原位址,但現在該塊記憶體的内容已不在原來的内容,也不于屬于原内容,故會報錯;為避免報錯,需要清空原指針(相當于java中的置null)
stu = nil;//清空指針中的位址;
++ 若類中有成員變量是自定義的對象,要先釋放:
- (void)dealloc
{
NSLog(@"系統調用回收方法");
//一定要調用super的dealloc方法,而且最好放在最後面調用
//成員變量要釋放
[_book release];
// NSLog(@"内部對象book計數值:%i",[_book retasinCount]);
[super dealloc];
}
++ 通常引用一個類的兩種方法:#import;@class;
++ @class ++用于聲明一個類,不知道實作,在使用時才用#import
**若在.h檔案中隻是要用到某個類,如定義一個成員變量,沒必要用#import “Book.h”;這樣是把.h檔案的内容拷貝到此處,影響性能(若有上百個類用#import一個類A,A中使用一點改動,則所有子類都會重新編譯;而@class則不會);
若隻是聲明一個成員變量,隻用使用@class Book;即可,聲明Book這個類即可,提高效率;
[對自定義的對象互相持有的情況下必須用 @class;如A中有B,B中有A;就不能使用#import,會造成遞歸導入;編譯錯誤]
[對于繼承的父類,不能使用@class,須使用#import,用于将父類的頭檔案拷貝到此處,讓子類知道哪些方法已經定義過。]
但在.m要用到這個類下的方法,還是需要#import “Book.h”
++ @property 記憶體管理 ++
@(參數1,參數2)類型 名字;
參數分類:
讀寫屬性:readwrite/readonly;//預設是readwrite,并生成set/get;readonly代表隻生成get方法
setter屬性:assign/retain/copy;//預設是assign,直接指派;retain,引用+1;
原子性:atomic/nonatomic;//預設atomic,加鎖,提供了多線程安全;nonatomic,禁止多線程,變量保護,可提高性能;[對于在iPone這個小型裝置上,記憶體很小,預設情況下不需要考慮太多的多線程,以提高性能]
(在做IOS開發時,盡量多使用nonatomic)
如:
@property (nonatomic,assign) int ID;
@property (nonatomic,retain) Book *book;
@property (nonatomic,getter=isEnable) BOOL enable;//指定get的方法名;
@property (retain)Card *card;//就相當于上面手動判斷,釋放再retain的set方法;(若是基礎類型不需要添加,否則要添加retain)
++autorelease pool ++自動釋放池
OC中的一種記憶體自己回收機制,一般可将一些臨時變量添加到自動釋放池中,統一回收釋放;
當自動釋放池銷毀時,池裡面的所有對象都會調用一次release方法;
使用:OC對象隻需要發送一條autorelease消息,就會把這個對象添加到最近的自動釋放池中(棧頂的釋放池);autorelese實際上是把對release的調用延遲了,對于每一次autorelease,系統隻是把該對象放入了autorelease pool中,當pool被釋放時,該pool會調用一次所有的對象relase方法。
[若使用autorelease 後就不需手動釋放]
[autorelease pool會在程式執行完成後銷毀]
//代表建立一個自動釋放池;
@autoreleasepool {
// testMemoeryReales();
Student *stu = [[Student alloc] init];
//隻是把對象放到autorelease pool中;當autoreleasepool被銷毀時,會自動調用一次池裡所有的對象的release方法,
[stu autorelease];
//則上面可簡化成
Student *stu1= [[[Student alloc] init] autorelease];
}
*[IOS5.0之前: NSAutoreleasePool *pool = [[NSAutorelease] alloc]init]; [pool release];(在ARC下,不能使用這種方法,隻能使用@autoreleasepool;ARC本質上就是一個釋放池的操作)]
[NOTE:*不要在一個autoreleasepool中放入大量循環操作(for,while等,應使用手動release);盡量以免對大記憶體使用方法,對于這種延遲釋放機制,盡少使用;SDK中一般利用靜态方法建立并傳回的對象都是已經autorelease的,不需要再release操作;]
自定義一個快速建立的構造方法:
+(id)student{
return [[[Student alloc] init] autorelease];
}
[規範:靜态方法傳回的對象都是自己負責釋放的]
感謝李明傑老師@M了個J的講解及時詳細的課件(http://www.cnblogs.com/mjios)
部落格位址:IOS學習筆記之Object-C(一)