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