黑馬程序員-OC的核心語法

------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------
一.關鍵語法
1.點語法
點語法的本質還是方法調用
比如 p.age=10; 就是轉換爲 [p setAge:10];
 int a = p.age 轉換爲 int a = [p age];

2.成員變量作用域
    1.基本概念
        局部變量、全局變量都有自己的作用域,成員變量也不例外
2.類型
    >@private:只能在當前類的實現@implementation中直接訪問
    >@protected:可以在當前類以及子類的實現@implementation中直接訪問
    >@public:任何地方都可直接訪問
    >@package:同一個“體系內”(框架)可以訪問,介於@private@public之間
3.繼承補充
    >專業術語 父類\超類 superclass 子類 subclass\subclasses 單繼承
4.@implementation補充
    沒有@interface,只有@implementaton,也可以開發一個類,在.m文件進行聲明
    在聲明裏寫的成員變量,默認是private
    實現裏面也能寫成員變量 默認是私有,因爲不會被其他文件包含,無法改設置就算寫上@public也沒用
    (@interface)聲明和(@implementation)實現裏面不能定義同名的變量
5.成員變量的作用域
    @public:在作何地方都能直接方問對象的成員變量
    @private:只能在當前類的對象方法中直接訪問(@implementation默認)
    @protected:可以在當前類及其子類的對象方法中直接訪問(@interface默認)
    @package:只要處在同一個框架中,就能直接方問對象的成員變量
    @interface與@implementation中的成員變量不能同名
    子類與父類的成員變量不能同名
    
二.關鍵字
1.@property
    在@interface和@end之間
    編譯器特性,當遇到@property int age自動生成某個成員變量的setter和getter聲明,不能重複聲明
    如果使用了@property,但是沒有成員變量,則自動生成private類型的成員變量
    缺點,成員變量是死的,無法設置public或protected

2.@synthesize
    在@implementation和@end之間
    自動生用age的setter和getter的實現,並且會訪問_age這個成員變量
    @synthesize age = _age;也可以@synthesize age = _age,name = _name;
    如果@synthesize age沒有指定,那麼默認訪問和age一樣的成員變量

3.@property新特性
    自從Xcode4.4以後,@property就獨攬了@synthesize的功能,也不是說,@property可以同時聲明成員變量的聲明和實現
    @property(nonatomic,retain) UIWindow *window;  

    其中參數主要分爲三類:
    讀寫屬性: (readwrite/readonly)
    setter語意:(assign/retain/copy)
    原子性: (atomicity/nonatomic)

4.各參數意義如下:

    readwrite: 產生setter\getter方法
    readonly: 只產生簡單的getter,沒有setter。
    assign: 默認類型,setter方法直接賦值,而不進行retain操作
    retain: setter方法對參數進行release舊值,再retain新值。
    copy: setter方法進行Copy操作,與retain一樣,不對舊值release
    nonatomic: 禁止多線程,變量保護,提高性能

5.id
    id是一種類似如 id d 所以變量名不能叫id,id是關鍵字
    id是萬能指針,能指向\操作任何OC對象
    //id == NSObject *
    typedef struct objc_object{
        Class isa;
    }*id;
    //id後面不加*
    用id調用不存在的方法會報錯

三.類的構造方法

1.new的用處
 完整地創建一個可用的對象
 1.分配存儲空間 + alloc
 2.初始化 - init
 3.釋放 - dealloc
Person *p3 = [[Person alloc] init];
 
2.構造方法:是用來初始化對象的方法,是對象方法 -開頭
    重寫構造方法的目的:爲了讓對象創建出來,成員變量就會有一些固定的值
    重寫構造方法注意點
        1.先調用父類的構造方法([super init])
        2.再進行子類內部成員變量的初始化

    重寫-init方法 - (id)init
        1.一定要調用回super的init方法:初始化父類中聲明的一些成員變量和其他屬性 self = [super init];//當前對象 self = [父類將isa初始化爲當前類]
        2.當前對象指針指向父類構造出來的對象
        3.當前對象指針 self = [父類將isa初始化爲當前類]

    init的執行過程,運行原理
    //子類實例被創建的時候會先創建父類實例(調用父類的無參數構造方法),然後再創建子類實例
    
    重寫構造方法的執行順序
     student init super init
     person init super init
     nsobject init ....被封閉了
     返回一個class

3.自定義構造函數規範
 1.一定是對象方法,一定以 - 開頭
 2.返回值一般以id類型
 3.方法名一般以initWith開頭
 
四.類的擴展
Category分類 、類別、類目
    使用分類擴展類,並且不修改類原來的代碼
    1.分類只能增加方法,不能增加成員變量,添加成員變量可以使用繼承。
    2.分類的方法實現中可以使用成員變量
    3.分類的優先級最高,先去分類中找,再去原來的類中找,最後到父類中去找
    4.分類可以重新實現原來類中的方法,但是會覆蓋掉原來的方法,會有警告
    5.多個分類實現的方法,最後一個編譯的有效

    //聲明
    @interface 類名(分類名稱)
    @end

    //實現
    @implementation 類名(分類名稱)
    @end
    xcode添加分類->項目右鍵-NewFile OS X->Cocoa->Objective-C category(在Xcode6中已移除,如想使用需要手動添加模版文件)
    xcode6 想要添加分類需要 項目右鍵-NewFile OS X->Cocoa->Objective-C File 然後在彈出窗口中的 File Type:Category然後輸入其它之後添加。

擴展
Extension
    作用:定義私有方法。可以隱藏不對外公佈的方法。多用於隱藏一些中間步驟的方法。
    寫法:在.m文件中 @implementation 前實現
    例如在 @implementation之前加上
    @interface ViewController ()
    {
        int a;//默認私有
    }
    @end

協議
protocol
    可以實現類似多繼承的方法。一個類遵守多個協議<...,...>
    在協議裏聲明方法來讓類遵守
     @required //默認是必須實現的
    - (void)method1;
    - (void)method2;
    @optional //可以選擇實現



五.類的深入研究
    1.利用類需要先創建類類型對象
    2.類需要佔據存儲空間。
    3.每個類對象,佔據不同的存儲空間
    4.類本身也是一個對像,是Class類型的對象

Class類型的定義
    typedef struct objc_class *Class;
    類名就代表着類對象,每個類只有一個類對象

內存中的類對象
    Person * p = [[Person alloc] init];

獲取內存中的類對象
    1.Class c = [p class];
    2.Class c2 = [Person class];

    NSLog(@"c=%p,c2=%p",c,c2);
    
    //類對象 == 類
    Class c = [p class];
    [c test];
    
    Person *p2 = [[c new] init];

類的加載
    1.當程序啓動時,就會加載項目中所有的類和分類,而且加載後會調用每個類和分類的+load方法,只會調用一次.
    2.當第一次使用某個類時,就會調用當前類的+initialize方法,但是會先找分類的,因爲有優先級
    3.加載優先級 順序 先初始化父類-初始化子類
    4.initialize調用優先級 先最後編譯的分類-本類-父類

    @implementation Person
    + (void)test
    {
        NSLog(@"test");
    }
    //當程序啓動的時候,就會加載一次項目中所有的類。類加載完畢後就會調用+load方法,加載順序是先父類後子類
    + (void)load
    {
        NSLog(@"load");
    }
    //當第一次使用這個類的時候,就會調用一次initialize方法
    //當分類和類都有initialize方法時,只會調用分類的initialize方法
    + (void)initialize
    {
        NSLog(@"initialize");
    }


NSLog函數的工作原理
    Person *p = [[Person alloc] init];
    //默認情況下,利用NSLog和%@輸出對象時,結果是:<類名:內存地址>
    //1.首先調用對象的-description方法
    //2.拿到-description方法的返回值(NSString *)顯示到屏幕上
    //3.-description方法默認返回的是"類名+內存地址"
    //子類會繼承重寫的方法
    NSLog(@"%@",p);


Class c = [Person class];
    //1.首先調用類的+description方法
    //2.拿到+description方法的返回值(NSString *)顯示到屏幕上
    //3.+description方法默認返回的是"類名"
    NSLog(@"%@",c);
    重寫-description方法

NSLog的其它功能
    __func__ %s  Current function signature.
    __LINE__ %d  Current line number in the source code file.
    __FILE__ %s Full path to the source code file.
    __PRETTY_FUNCTION__ %s Like__func__,but includes verbose type information in C++ code.s

SEL
    每個SEL對應一個方法地址
    每個類的方法列表都存儲在類對象中
    根據一個SEL對象就可以找到方法的地址,進而調用方法
    SEL類型的定義
    typedef struct objc_selector *SEL

SEL對象的創建
    [p test:@"123"];
    SEL s = @selector(test:);
    NSString *name = @"test";
    SEL s2 = NSSelectorFromString(@"test");
    [p performSelector:s withObject:@"456"];

SEL對象的其他用法
    //將 SEL對象轉爲NSString對象
    NSString *str  =NSStringFromSelector(@selector(test));

    Person *p = [Person new]
    //調用對象p的test方法
    [p performSelector:@selector(test)];

_cmd
    //每個方法內部都有一個_cmd,_cmd代表當前方法
    用法
    NSString *str = NSStringFromSelector(_cmd);
    NSLog(@"調用了方法%@",str);
    //死循環

    [self performSelector:_cmd];


1.點語法
點語法的本質還是方法調用
比如 p.age=10; 就是轉換爲 [p setAge:10];
     int a = p.age 轉換爲 int a = [p age];

xcode - Create a new Xcode project - OS X- Application - Command Line Tool - create

添加類
OS X - Cocoa(Source) - Objective-C class -> Class:Person ->Subclass of :NSObject -> Language:Objective-C - Create
生成Person.h與.m

command+r 運行

xcode6 需要點 右下角的[ |]圖標(Hide the Console)才能看到控制檯


Person.h->

//
//  person.h
//  oc06核心語法
//
//  Created by Whome on 14-10-27.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int _age;
    NSString * _name;
}

- (void) setAge:(int)age;
- (int) age;
- (void) setName:(NSString *)name;
- (NSString *) name;

@end



Person.m->
//
//  person.m
//  oc06核心語法
//
//  Created by Whome on 14-10-27.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person

- (void) setAge:(int)age
{
    //self.age = 10; 是死循環
    _age = age;
    NSLog(@"setAge:%d",self->_age);
}
- (int) age
{
    NSLog(@"age:%d",self->_age);
    return self->_age;
}
- (void) setName:(NSString *)name
{
    _name = name;
    NSLog(@"setName:%@",self->_name);
}
- (NSString *) name
{
    NSLog(@"name:%@",self->_name);
    return self->_name;
}

@end



main.m->
//
//  main.m
//  oc06核心語法
//
//  Created by Whome on 14-10-27.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
/*
 點語法的本質還是方法調用
 比如 p.age=10; 就是轉換爲 [p setAge:10];
 int a = p.age 轉換爲 int a = [p age];
 */

int main() {
    
    Person *p = [Person new];
    
    p.age = 10;
    int a = p.age;
    NSLog(@"a:%d",a);
    p.name = @"is name";
    NSString *s = p.name;
    
    NSLog(@"s:%@",s);
    
    return 0;
}



控制檯輸出
2014-10-27 06:42:57.278 oc06核心語法[502:303] setAge:10
2014-10-27 06:42:57.287 oc06核心語法[502:303] age:10
2014-10-27 06:42:57.288 oc06核心語法[502:303] a:10
2014-10-27 06:42:57.294 oc06核心語法[502:303] setName:is name
2014-10-27 06:42:57.302 oc06核心語法[502:303] name:is name
2014-10-27 06:42:57.303 oc06核心語法[502:303] s:is name
Program ended with exit code: 0

2.成員變量作用域
1.基本概念
局部變量、全局變量都有自己的作用域,成員變量也不例外
2.類型
>@private:只能在當前類的實現@implementation中直接訪問
>@protected:可以在當前類以及子類的實現@implementation中直接訪問
>@public:任何地方都可直接訪問
>@package:同一個“體系內”(框架)可以訪問,介於@private@public之間
3.繼承補充
>專業術語 父類\超類 superclass 子類 subclass\subclasses 單繼承
4.@implementation補充
沒有@interface,只有@implementaton,也可以開發一個類,在.m文件進行聲明
在聲明裏寫的成員變量,默認是private
實現裏面也能寫成員變量 默認是私有,因爲不會被其他文件包含,無法改設置就算寫上@public也沒用
(@interface)聲明和(@implementation)實現裏面不能定義同名的變量

添加類
OS X - Cocoa(Source) - Objective-C class -> Class:Person ->Subclass of :NSObject -> Language:Objective-C - Create
生成Person.h與.m

Person.h->
//
//  Person.h
//  02成員變量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//


#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    int _no;
    
    @public //在作何地方都能直接方問對象的成員變量
    int _age;
    
    @private//只能在當前類的對象方法中直接訪問
    int _height;
    
    @protected //可以在當前類及其子類的對象方法中直接訪問
    int _weight;
}
- (void)setHeight:(int) height;
- (int)height;
- (void)test;
@end



Person.m->
//
//  Person.m
//  02成員變量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person
{
    int _aaa;//默認就是私有
    
    @public
    int _bbb;
    
}
- (void)test
{
    _age = 19;
    _height = 20;
    _weight = 50;
    _aaa = 10;
}
- (void)setHeight:(int)height{
    _height = height;
}
- (int)height
{
    return _height;
}
@end

Student.h->
//
//  Student.h
//  02成員變量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@interface Student : Person
- (void)study;
@end

Student.m->
//
//  Student.m
//  02成員變量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Student.h"

@implementation Student
- (void)study
{
    //_height = 10;
    [self setHeight:10];
    
    int h = [self height];
    
    _weight = 100;
    
    NSLog(@"h:%d",h);
}
@end

Car.m->

//
//  <pre name="code" class="objc">Car .m
//  02成員變量的作用域
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//
#import "Person.h"
#import "Student.h"
@implementation Car : NSObject
{
    @public
    int _speed;
}
- (void)setSpeed:(int)speed
{
    _speed = speed;
}
- (int)speed
{
    return _speed;
}
- (void) test{
    NSLog(@"speed:%d",_speed);
}
@end




main.m->
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Student *stu = [Student new];
        
        [stu setHeight:10];
        
        NSLog(@"%d",[stu height]);
        
        Car *c = [Car new];
        c->_speed = 250;
        c.speed = 10;
        
        NSLog(@"speed:%d",c.speed);
        
        Person *p = [Person new];
        //私有的private
      //  p->_bbb = 10;
        p->_age = 100;
        //私有的private
     //   p->_height = 20;
        
    }
    return 0;
}

控制檯:
2014-10-28 07:55:13.150 02成員變量的作用域[630:303] 10
2014-10-28 07:55:13.153 02成員變量的作用域[630:303] speed:10
Program ended with exit code: 0


1.@property
在@interface和@end之間
編譯器特性,當遇到@property int age自動生成某個成員變量的setter和getter聲明,不能重複聲明
如果使用了@property,但是沒有成員變量,則自動生成private類型的成員變量
缺點,成員變量是死的,無法設置public或protected


2.@synthesize
在@implementation和@end之間
自動生用age的setter和getter的實現,並且會訪問_age這個成員變量
@synthesize age = _age;也可以@synthesize age = _age,name = _name;
如果@synthesize age沒有指定,那麼默認訪問和age一樣的成員變量

@property新特性
自從Xcode4.4以後,@property就獨攬了@synthesize的功能,也不是說,@property可以同時聲明成員變量的聲明和實現

@property(nonatomic,retain) UIWindow *window;  

其中參數主要分爲三類:

讀寫屬性: (readwrite/readonly)
setter語意:(assign/retain/copy)
原子性: (atomicity/nonatomic)

 

各參數意義如下:

readwrite: 產生setter\getter方法
readonly: 只產生簡單的getter,沒有setter。
assign: 默認類型,setter方法直接賦值,而不進行retain操作
retain: setter方法對參數進行release舊值,再retain新值。
copy: setter方法進行Copy操作,與retain一樣,不對舊值release
nonatomic: 禁止多線程,變量保護,提高性能

3.id
id是一種類似如 id d 所以變量名不能叫id,id是關鍵字
id是萬能指針,能指向\操作任何OC對象
//id == NSObject *
typedef struct objc_object{
    Class isa;
}*id;
//id後面不加*
用id調用不存在的方法會報錯

Person.h->

//
//  Person.h
//  03關鍵字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
   
    int _age;
     @private
    int _width;
}
//自動生成getter和setter及private類型的成員變量
@property int height;
@property NSString* name;
//自動生成getter和setter
@property int age;

- (void)setWidth:(int)width;
- (int)width;

@end




Person.m->

//
//  Person.m
//  03關鍵字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person

//自動實現setter和getter
@synthesize height = _height;

//沒有@property int width會報錯
//@synthesize width = _widht;

- (void)setWidth:(int)width{
    _width = width;
}

- (int)width{
    return _width;
}

@end



Student.h->
//
//  Student.h
//  03關鍵字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@interface Student : Person

@end



Student.m->

//
//  Student.m
//  03關鍵字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Student.h"

@implementation Student

@end



main.m->

//
//  main.m
//  03關鍵字
//
//  Created by Whome on 14-10-28.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        Person *p = [Person new];
        
        //隻手動聲明瞭成員變量
        p.age = 10;
        //純@property
        p.height=10;
        //純@property
        p.name = @"is name";
        //純手動
        p.width = 10;
        
        NSLog(@"p.age:%d",p.age);
        NSLog(@"p.height:%d",p.height);
        NSLog(@"p.name:%@",p.name);
        NSLog(@"p.width:%d",p.width);
        
        Student *s = [Student new];
        
        
        //父類的成員變量是私有的無法->調用,但是setter/getter可以用
        //隻手動聲明瞭成員變量
        s.age = 10;
        //純@property
        s.height=10;
        //純@property
        s.name = @"is name";
        //純手動
        s.width = 10;
        
        
        NSLog(@"s.age:%d",s.age);
        NSLog(@"s.height:%d",s.height);
        NSLog(@"s.name:%@",s.name);
        NSLog(@"s.width:%d",s.width);

        
        //id是一種類似如 id d 所以變量名不能叫id,id是關鍵字
        //id是萬能指針,能指向\操作任何OC對象
        
        id d = [Student new];
        //無法直接用.語法來調用
        //d.age = 10;
        [d setAge:10];
        NSLog(@"d.age:%d",[d age]);
        
    }
    return 0;
}

控制檯輸出:
2014-10-29 00:10:15.692 03關鍵字[690:303] Hello, World!
2014-10-29 00:10:15.695 03關鍵字[690:303] p.age:10
2014-10-29 00:10:15.696 03關鍵字[690:303] p.height:10
2014-10-29 00:10:15.697 03關鍵字[690:303] p.name:is name
2014-10-29 00:10:15.698 03關鍵字[690:303] p.width:10
2014-10-29 00:10:15.699 03關鍵字[690:303] s.age:10
2014-10-29 00:10:15.700 03關鍵字[690:303] s.height:10
2014-10-29 00:10:15.701 03關鍵字[690:303] s.name:is name
2014-10-29 00:10:15.706 03關鍵字[690:303] s.width:10
2014-10-29 00:10:15.706 03關鍵字[690:303] d.age:10


1.new的用處
 完整地創建一個可用的對象
 1.分配存儲空間 +alloc
 2.初始化 -init
 3.釋放 -dealloc
Person *p3 = [[Person alloc] init];
 
//構造方法:是用來初始化對象的方法,是對象方法 -開頭
//重寫構造方法的目的:爲了讓對象創建出來,成員變量就會有一些固定的值
重寫構造方法注意點
1.先調用父類的構造方法([super init])
2.再進行子類內部成員變量的初始化

//重寫-init方法 - (id)init
//1.一定要調用回super的init方法:初始化父類中聲明的一些成員變量和其他屬性 self = [super init];//當前對象 self = [父類將isa初始化爲當前類]

init的執行過程,運行原理
//子類實例被創建的時候會先創建父類實例(調用父類的無參數構造方法),然後再創建子類實例


 自定義構造函數規範
 1.一定是對象方法,一定以 - 開頭
 2.返回值一般以id類型
 3.方法名一般以initWith開頭



Person.h->

//
//  Person.h
//  04構造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
   // int _age;
   // NSString* _name;
}
@property int age;
@property NSString* name;
- (id)init;
/*
 自定義構造函數規範
 1.一定是對象方法,一定以 - 開頭
 2.返回值一般以id類型
 3.方法名一般以initWith開頭
 */
- (id)initWithName:(NSString *) name andAge:(int) age;
@end



Person.m->
//
//  Person.m
//  04構造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person
//重寫重構方法
- (id)init
{
    //當前對象指針指向父類構造出來的對象
    //當前對象指針 self = [父類將isa初始化爲當前類]
    self = [super init];
    
    //如果self不爲0
    if(self){
        //初始化成員變量
        _age = 10;
    }
    return self;
}
- (id)initWithName:(NSString *)name andAge:(int)age
{
    if(self = [super init])
    {
        _name = name;
        _age = age;
    }
    return self;
}
@end



Student.h->

//
//  Student.h
//  04構造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@interface Student : Person
{
    int _no;
}
@property int no;
- (id)init;
- (id)initWithName:(NSString *) name andAge:(int) age andNo:(int) no;
@end



Student.m->

//
//  Student.m
//  04構造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Student.h"

@implementation Student
//重寫重構方法
- (id)init
{
    //當前對象指針指向父類構造出來的對象
    //當前對象指針 self = [父類將isa初始化爲當前類]
    //一定要調用父類的init方法,初始化一些父類聲明的成員變量和方法
    self = [super init];
    
    //如果self不爲0,如果對象初始化成功,能有必要進行接下來的初始化
    if(self){
        //初始化成員變量
        _no = 50;
    }
    //返回一個已初始化完畢的對象
    return self;
}
- (id)initWithName:(NSString *)name andAge:(int)age andNo:(int)no
{
    
    if(self = [super initWithName:name andAge:age ])
    {
        //如果_name是子類可繼隨的那麼
        //_name = name;
        //如果_name是私有的那麼
        //self.name = name;
        //如果想在父類構造時就初始化,而且並不關心父類的成員變量那麼
        //[super initWithName:name andAge:age ]
        
        _no = no;
    }
    return self;
}

@end



main.m->

//
//  main.m
//  04構造方法
//
//  Created by Whome on 14-10-29.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        /*
        1.new的用處
        完整地創建一個可用的對象
        1.分配存儲空間 +alloc
        2.初始化 -init
        */
        Student *s = [[Student alloc] init];
        NSLog(@"age:%d,no:%d",s.age,s.no);
        
        /*
         重寫構造方法的執行順序
         student init super init
         person init super init
         nsobject init ....被封閉了
         返回一個class
         */
        /*
         自定義構造函數規範
         1.一定是對象方法,一定以 - 開頭
         2.返回值一般以id類型
         3.方法名一般以initWith開頭
         */
         s = [[Student alloc] initWithName:@"is name" andAge:10 andNo: 20];
         NSLog(@"age:%d,no:%d,name:%@",s.age,s.no,s.name);
    }
    return 0;
}

控制檯->

2014-10-30 06:24:35.326 04構造方法[398:303] Hello, World!
2014-10-30 06:24:35.332 04構造方法[398:303] age:10,no:50
2014-10-30 06:24:35.336 04構造方法[398:303] age:10,no:20,name:is name


Category分類 、類別、類目
/*使用分類擴展類,並且不修改類原來的代碼
1.分類只能增加方法,不能增加成員變量,添加成員變量可以使用繼承。
2.分類的方法實現中可以使用成員變量
3.分類的優先級最高,先去分類中找,再去原來的類中找,最後到父類中去找
4.分類可以重新實現原來類中的方法,但是會覆蓋掉原來的方法,會有警告
5.多個分類實現的方法,最後一個編譯的有效
*/
//聲明
@interface 類名(分類名稱)
@end

//實現
@implementation 類名(分類名稱)
@end


xcode添加分類->項目右鍵-NewFile OS X->Cocoa->Objective-C category(在Xcode6中已移除,如想使用需要手動添加模版文件)
xcode6 想要添加分類需要 項目右鍵-NewFile OS X->Cocoa->Objective-C File 然後在彈出窗口中的 File Type:Category然後輸入其它之後添加。

擴展
Extension
作用:定義私有方法。可以隱藏不對外公佈的方法。多用於隱藏一些中間步驟的方法。
寫法:在.m文件中 @implementation 前實現
例如在 @implementation之前加上
@interface ViewController ()
{
    int a;//默認私有
}
@end

協議
protocol
可以實現類似多繼承的方法。一個類遵守多個協議<...,...>
在協議裏聲明方法來讓類遵守
 @required //默認是必須實現的
- (void)method1;
- (void)method2;
@optional //可以選擇實現

給系統自帶類添加分類
1.給NSString增加一個類方法:計算某個字符串中阿拉伯數字的個數
2.給NSString增加一個對象方法:計算當前字符串中阿拉伯數字的個數


Person.h->

#import <Foundation/Foundation.h>

@interface Person : NSObject
{
    //@private
    //int _age;
}
@property int age;
- (void)test;
@end

Person.m->
#import "Person.h"

@implementation Person
- (void)test
{
    NSLog(@"person");
}
@end

Person+sum.h->
#import "Person.h"

@interface Person (sum)
- (int)sumWithAge:(int)age1 andAge2:(int)age2;
- (void)test;
@end

Person+sum.m->
#import "Person+sum.h"

@implementation Person (sum)
- (int)sumWithAge:(int)age1 andAge2:(int)age2
{
    self.age = age2+age2;
    NSLog(@"self.age:%d",self.age);
    //出錯,因爲沒有在類聲明變量。
    //_age = 0;
    //age = 0;
    //self->_age=0;
    //self->age =0;
    /*
    self->age =age+age2;
    return self->_age;
     */
    return self.age;
}
- (void)test
{
    NSLog(@"person+sum");
}
@end

NSString+count.h->
#import <Foundation/Foundation.h>


/*
 給系統自帶類添加分類
 1.給NSString增加一個類方法:計算某個字符串中阿拉伯數字的個數
 2.給NSString增加一個對象方法:計算當前字符串中阿拉伯數字的個數
 */
@interface NSString (count)
+ (int) numberCountOfString:(NSString *)str;
- (int)numberCount;
@end

NSString+count.m->
#import "NSString+count.h"

@implementation NSString (count)
// 計算某個字符串中阿拉伯數字的個數
+ (int) numberCountOfString:(NSString *)str
{
    int count=0;
    //獲取長度並循環
    for(int i=0;i<str.length;i++)
    {
        //獲取字符
        unichar c = [str characterAtIndex:i];
        //將數字挑選出來
        if(c>'0' && c<'9')
        {
            count++;
            NSLog(@"%c",c);
        }
    }
    return count;
}
//計算當前字符串中阿拉伯數字的個數
- (int)numberCount
{
    int count=0;
    for(int i=0;i<self.length;i++)
    {
        unichar c = [self characterAtIndex:i];
        if(c>'0' && c<'9')
        {
            count++;
            NSLog(@"%c",c);
        }
    }
    return count;
}
@end

main.m->
#import <Foundation/Foundation.h>

#import "Person.h"
#import "Person+sum.h"
#import "NSString+count.h"

/*
 Category分類 、類別、類目
 使用分類擴展類,並且不修改類原來的代碼
 1.分類只能增加方法,不能增加成員變量,添加成員變量可以使用繼承。
 2.分類的方法實現中可以使用成員變量
 3.分類的優先級最高,先去分類中找,再去原來的類中找,最後到父類中去找
 4.分類可以重新實現原來類中的方法,但是會覆蓋掉原來的方法,會有警告
 5.多個分類實現的方法,最後一個編譯的有效
 */
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        Person *p = [[Person alloc]init];
        
        int age = [p sumWithAge:10 andAge2:20];
        NSLog(@"age:%d",age);
        
        [p test];
        
       
        
        int count = [NSString numberCountOfString:@"a12d5x778" ];
        NSLog(@"count:%d",count);

        NSString *s = @"ab234x278";
        count = [s numberCount];
        NSLog(@"count:%d",count);

        count = [@"asdf2ssdf2" numberCount];
        NSLog(@"count:%d",count);


    }
    
    return 0;
}


控制檯:
2014-11-09 19:43:05.706 05類的分類[852:303] Hello, World!
2014-11-09 19:43:05.709 05類的分類[852:303] self.age:40
2014-11-09 19:43:05.710 05類的分類[852:303] age:40
2014-11-09 19:43:05.710 05類的分類[852:303] person+sum
2014-11-09 19:43:05.711 05類的分類[852:303] 1
2014-11-09 19:43:05.711 05類的分類[852:303] 2
2014-11-09 19:43:05.712 05類的分類[852:303] 5
2014-11-09 19:43:05.712 05類的分類[852:303] 7
2014-11-09 19:43:05.714 05類的分類[852:303] 7
2014-11-09 19:43:05.714 05類的分類[852:303] 8
2014-11-09 19:43:05.715 05類的分類[852:303] count:6
2014-11-09 19:43:05.717 05類的分類[852:303] 2
2014-11-09 19:43:05.718 05類的分類[852:303] 3
2014-11-09 19:43:05.719 05類的分類[852:303] 4
2014-11-09 19:43:05.719 05類的分類[852:303] 2
2014-11-09 19:43:05.720 05類的分類[852:303] 7
2014-11-09 19:43:05.721 05類的分類[852:303] 8
2014-11-09 19:43:05.721 05類的分類[852:303] count:6
2014-11-09 19:43:05.722 05類的分類[852:303] 2
2014-11-09 19:43:05.723 05類的分類[852:303] 2
2014-11-09 19:43:05.727 05類的分類[852:303] count:2

可能性
我覺得跟權限沒關係應該是分類在調用這個變量的時候property還沒有生成
那麼就只有一個原因,  分類可以重寫setAge和(get)age方法.
又因爲set get 這兩個方法一旦重寫 那property 就不在會生成_age變量;

所以OC爲了避免這種情況  直接限制在有分類的情況 必須自己書寫變量 不能用property 這樣就不會導致重寫set get會讓property失效了
你可以在正常情況下 寫了property  然後在重寫set get方法  你會發現找不到變量


類的深入研究
1.利用類需要先創建類類型對象
2.類需要佔據存儲空間。
3.每個類對象,佔據不同的存儲空間
4.類本身也是一個對像,是Class類型的對象

Class類型的定義
typedef struct objc_class *Class;
類名就代表着類對象,每個類只有一個類對象

內存中的類對象
Person * p = [[Person alloc] init];

獲取內存中的類對象
1.Class c = [p class];
2.Class c2 = [Person class];

NSLog(@"c=%p,c2=%p",c,c2);

//類對象 == 類
Class c = [p class];
[c test];

Person *p2 = [[c new] init];

類的加載
1.當程序啓動時,就會加載項目中所有的類和分類,而且加載後會調用每個類和分類的+load方法,只會調用一次.
2.當第一次使用某個類時,就會調用當前類的+initialize方法,但是會先找分類的,因爲有優先級
3.加載優先級 順序 先初始化父類-初始化子類
4.initialize調用優先級 先最後編譯的分類-本類-父類

@implementation Person
+ (void)test
{
    NSLog(@"test");
}
//當程序啓動的時候,就會加載一次項目中所有的類。類加載完畢後就會調用+load方法,加載順序是先父類後子類
+ (void)load
{
    NSLog(@"load");
}
//當第一次使用這個類的時候,就會調用一次initialize方法
//當分類和類都有initialize方法時,只會調用分類的initialize方法
+ (void)initialize
{
    NSLog(@"initialize");
}


NSLog函數的工作原理
Person *p = [[Person alloc] init];
//默認情況下,利用NSLog和%@輸出對象時,結果是:<類名:內存地址>
//1.首先調用對象的-description方法
//2.拿到-description方法的返回值(NSString *)顯示到屏幕上
//3.-description方法默認返回的是"類名+內存地址"
//子類會繼承重寫的方法
NSLog(@"%@",p);


Class c = [Person class];
//1.首先調用類的+description方法
//2.拿到+description方法的返回值(NSString *)顯示到屏幕上
//3.+description方法默認返回的是"類名"
NSLog(@"%@",c);
重寫-description方法

NSLog的其它功能
__func__ %s  Current function signature.
__LINE__ %d  Current line number in the source code file.
__FILE__ %s Full path to the source code file.
__PRETTY_FUNCTION__ %s Like__func__,but includes verbose type information in C++ code.s

SEL
每個SEL對應一個方法地址
每個類的方法列表都存儲在類對象中
根據一個SEL對象就可以找到方法的地址,進而調用方法
SEL類型的定義
typedef struct objc_selector *SEL

SEL對象的創建
[p test:@"123"];
SEL s = @selector(test:);
NSString *name = @"test";
SEL s2 = NSSelectorFromString(@"test");
[p performSelector:s withObject:@"456"];

SEL對象的其他用法
//將 SEL對象轉爲NSString對象
NSString *str  =NSStringFromSelector(@selector(test));

Person *p = [Person new]
//調用對象p的test方法
[p performSelector:@selector(test)];

_cmd
//每個方法內部都有一個_cmd,_cmd代表當前方法
用法
NSString *str = NSStringFromSelector(_cmd);
NSLog(@"調用了方法%@",str);
//死循環
[self performSelector:_cmd];


main.m->

//
//  main.m
//  06類的深入
//
//  Created by Whome on 14-11-7.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Person.h"


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
        /*
         Class類型的定義
         typedef struct objc_class *Class;
         類名就代表着類對象,每個類只有一個類對象
         */
        
        //獲取內存中的類對象
        Person *p = [[Person alloc]init];
        Class c = [p class];
        Class c1 = [Person class];
        
        NSLog(@"c=%p,c1=%p",c,c1);
        
        //類對象 == 類
        Class c2 = [p class];
        [c test];
        
        Person *p1 = [[c2 new] init];
        [p1 test];
        
        /*
         類的加載
         1.當程序啓動時,就會加載項目中所有的類和分類,而且加載後會調用每個類和分類的+load方法,只會調用一次.
         2.當第一次使用某個類時,就會調用當前類的+initialize方法,但是會先找分類的,因爲有優先級
         3.加載優先級 順序 先初始化父類-初始化子類
         4.initialize調用優先級 先最後編譯的分類-本類-父類
         */
        
        
        /*
         %@ 對象
         %d, %i 整數
         %u,%z 無符整形
         %f 浮點/雙字
         %x, %X 十六進制整數
         %o 八進制整數
         %zu size_t
         %p 指針
         %e 浮點/雙字 (科學計算)
         %g 浮點/雙字
         %s C字符串
         %.*s Pascal字符串
         %c 字符
         %C unichar
         %lld 64位長整數(long long)
         %llu 無符64位長整數
         %Lf 64位雙字
         %hhd    BOOL布爾類型
         __func__ %s  Current function signature.
         __LINE__ %d  Current line number in the source code file.
         __FILE__ %s Full path to the source code file.
         __PRETTY_FUNCTION__ %s Like__func__,but includes verbose type information in C++ code.s
         */
        NSLog(@"__func__:%s",__func__);
        NSLog(@"__LINE__:%d",__LINE__);
        NSLog(@"__FILE__:%s",__FILE__);
        NSLog(@"__PRETTY_FUNCTION__:%s",__PRETTY_FUNCTION__);
       // NSLog函數的工作原理
        Student *p2 = [[Student alloc] init];
        //默認情況下,利用NSLog和%@輸出對象時,結果是:<類名:內存地址>
        //1.首先調用對象的-description方法
        //2.拿到-description方法的返回值(NSString *)顯示到屏幕上
        //3.-description方法默認返回的是"類名+內存地址"
        NSLog(@"p2:%@",p2);
        
        
        Class c3 = [Student class];
        //1.首先調用類的+description方法
        //2.拿到+description方法的返回值(NSString *)顯示到屏幕上
        //3.+description方法默認返回的是"類名"
        NSLog(@"c3:%@",c3);
        //重寫-description方法

        /*
        SEL
        每個SEL對應一個方法地址
        每個類的方法列表都存儲在類對象中
        根據一個SEL對象就可以找到方法的地址,進而調用方法
        SEL類型的定義
        typedef struct objc_selector *SEL
        */
        //SEL對象的創建
        [p testStr:@"123"];
        SEL s = @selector(testStr:);
        NSString *name = @"testStr:";
        //SEL s2 = NSSelectorFromString(@"testStr");
        SEL s2 = NSSelectorFromString(name);
        
        [p performSelector:s withObject:@"456"];
        [p performSelector:s2 withObject:@"56"];
        
        
        //SEL對象的其他用法
        //將 SEL對象轉爲NSString對象
        NSString *str  =NSStringFromSelector(@selector(test));
        
        NSLog(@"str%@:",str);
        
        //間接調用對象p的test方法
        s = @selector(test);
        [p performSelector:s];
        //不知道爲什麼調用test報錯
    /*
    保留test對象方法在編輯時報Multiple methods named 'test' found with mismatched result,parameter type or attributes
    只保類test類方法在編譯時報*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person test]: unrecognized selector sent to instance 0x100104fd0'
    */
        [p performSelector:@selector(test2)];
       
    }
    return 0;
}



Person.h->
//
//  Person.h
//  06類的深入
//
//  Created by Whome on 14-11-7.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject
+ (void)test;
- (void)test;
- (void)test2;
- (void)testStr:(NSString*)str;
@end



Person.m->
//
//  Person.m
//  06類的深入
//
//  Created by Whome on 14-11-7.
//  Copyright (c) 2014年 Whome. All rights reserved.
//

#import "Person.h"

@implementation Person
+ (void)test
{
    NSLog(@"Person test");
}
- (void)test
{
    NSLog(@"Person -test");
    /*
     _cmd
     每個方法內部都有一個_cmd,_cmd代表當前方法
     用法
     */
    NSString *str = NSStringFromSelector(_cmd);
    NSLog(@"調用了方法%@",str);
    //死循環
    //[self performSelector:_cmd];
}
//當程序啓動的時候,就會加載一次項目中所有的類。類加載完畢後就會調用+load方法,加載順序是先父類後子類
+ (void)load
{
    NSLog(@"Person load");
}
//當第一次使用這個類的時候,就會調用一次initialize方法
//當分類和類都有initialize方法時,只會調用分類的initialize方法
+ (void)initialize
{
    NSLog(@"Person initialize");
}
//默認情況下,利用NSLog和%@輸出對象時,結果是:<類名:內存地址>
//1.首先調用對象的-description方法
//2.拿到-description方法的返回值(NSString *)顯示到屏幕上
//3.-description方法默認返回的是"類名+內存地址"
//子類會繼承這個方法
- (NSString*)description
{
    return @"NSLog description 返回值";
}
- (void)testStr:(NSString*)str{
    NSLog(@"%@",str);
}
- (void)test2{
    NSLog(@"- test2");
    NSString *str = NSStringFromSelector(_cmd);
    NSLog(@"調用了方法%@",str);
}
+ (void)test2{
    NSLog(@"+ test2");
}
@end

Person+Mj.h->
#import "Person.h"

@interface Person (MJ)

@end

Person+Mj.m->
#import "Person+MJ.h"

@implementation Person (MJ)
//當程序啓動的時候,就會加載一次項目中所有的類。類加載完畢後就會調用+load方法,加載順序是先父類後子類
+ (void)load
{
    NSLog(@"Person+MJ load");
}
//當第一次使用這個類的時候,就會調用一次initialize方法
//當分類和類都有initialize方法時,只會調用分類的initialize方法
+ (void)initialize
{
    NSLog(@"Person+MJ initialize");
}
@end


Student.h->
#import "Person.h"

@interface Student : Person
+ (void)test;
@end


Student.m->

#import "Student.h"

@implementation Student
+ (void)test
{
    NSLog(@"Student test");
}
//當程序啓動的時候,就會加載一次項目中所有的類。類加載完畢後就會調用+load方法,加載順序是先父類後子類
+ (void)load
{
    NSLog(@"Student load");
}
//當第一次使用這個類的時候,就會調用一次initialize方法
//當分類和類都有initialize方法時,只會調用分類的initialize方法
+ (void)initialize
{
    NSLog(@"Student initialize");
}
@end



控制檯

2014-11-09 07:41:25.908 06類的深入[894:303] Person load
2014-11-09 07:41:25.911 06類的深入[894:303] Student load
2014-11-09 07:41:25.912 06類的深入[894:303] Person+MJ load
2014-11-09 07:41:25.913 06類的深入[894:303] Hello, World!
2014-11-09 07:41:25.913 06類的深入[894:303] Person+MJ initialize
2014-11-09 07:41:25.914 06類的深入[894:303] c=0x1000026d0,c1=0x1000026d0
2014-11-09 07:41:25.915 06類的深入[894:303] Person test
2014-11-09 07:41:25.916 06類的深入[894:303] - test2
2014-11-09 07:41:25.916 06類的深入[894:303] 調用了方法test2
2014-11-09 07:41:25.919 06類的深入[894:303] __func__:main
2014-11-09 07:41:25.919 06類的深入[894:303] __LINE__:73
2014-11-09 07:41:25.921 06類的深入[894:303] __FILE__:
2014-11-09 07:41:25.921 06類的深入[894:303] __PRETTY_FUNCTION__:int main(int, const char **)
2014-11-09 07:41:25.922 06類的深入[894:303] Student initialize
2014-11-09 07:41:25.923 06類的深入[894:303] p2:NSLog description 返回值
2014-11-09 07:41:25.924 06類的深入[894:303] c3:Student
2014-11-09 07:41:25.925 06類的深入[894:303] 123
2014-11-09 07:41:25.925 06類的深入[894:303] strtest:
Program ended with exit code: 0
------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章