一、 面向對象特性之封裝
知識點
1.封裝說的是對成員變量的封裝和間接訪問
2.封裝涉及兩個對象方法:set方法和get方法
3.好處:①安全隱藏內部細節②set方法監聽成員變量的改變 一旦改變就做出相應處理行爲(**)
4.什麼情況下使用?只讀:只提供get方法 不要提供set或用@public,set方法一般都要寫。讀寫:兩者都要寫
5.封裝逐漸成爲一種編程規範
命名規範
set方法的命名規範:
1)方法名必須以set開頭
2)set後面跟上成員變量的名稱並且成員變量的首字母必須大寫
3)返回值一定是void
4)一定要接收參數,而且參數類型跟成員變量類型一致
5)形參的名稱不能和成員變量一樣
get方法的命名規範:
1)肯定有返回值,返回類型和成員變量類型一致
2)方法名和成員變量一樣
3)不需要接收參數
代碼舉例
#import<Foundation/Foundation.h>
typedef enum
{
SexMan,SexWoman
} Sex;
@interface Student:NSObject
{
//@public
int age;
//成員變量命名規範:一定要以下劃線 _開頭 和get方法的名稱區分開; 和局部變量也區分開來了
Sex _sex;
}
//提供一個方法給外界設置age的屬性值 引出set方法 對傳來的參數進行過濾
- (void)study;
- (void)setAge:(int)newAge;
-(int)age;
- (void)setSex:(Sex)sex;
- (Sex)sex;
@end
@impementation Student
- (void)study
{
NSLog(@“%d歲的學生在學習”,age);
}
//set方法的實現
- (void)setAge:(int)newAge
{
if(newAge<=0)
{
newAge=1;
}
age=newAge;
}
- (int)age
{
return age;
}
- (void)setSex:(Sex)sex
{
_sex=sex;
}
- (Sex)sex;
{
return _sex;
}
@end
int main()
{
Student *stu=[Student new];
//stu->age=20;//阻止不了公共類型的數據賦值,不能過濾不合理的數據 怎麼解決呢?(*1)
[stu setAge:-10];//因爲此時age不是公共類型的 所以通過方法間接訪問
[stu study];
//int age=stu->age;//age是公共類型的時候
int age=[stu age];
[stu setSex:SexMan];
}
//*1去掉public 在set方法裏去判斷過濾 成員變量儘量不要用@public 【成員變量封裝】但是訪問是個問題 所以引入get方法
二、 弱語法理解
知識點
1.基於C 編譯時只發出警告,不報錯 【以上程序都是.m文件】
2.讓對象調用不存在的方法(沒有經過聲明)編譯只有警告,但是鏈接時卻沒錯 ,不過運行時會報錯:不能識別消息到實例 (程序自動終結)
unrecognized selector sent to instance 。。。。。
3.有聲明,沒有實現 編譯只有警告,但是鏈接時卻沒錯 ,不過運行時會報錯:找不到實現方法
這表明:OC在運行過程中才會檢測對象的類裏有沒有實現相應的方法(由上2可知)
4.無聲明,但有實現 編譯只有警告,但是鏈接時卻沒錯 ,運行也OK [由上2可知] (方法和類 通用 前提是在main函數之前)
要是類 要這樣寫 @implementation Car:NSObject
@end
5.一旦程序運行時出錯,程序就會閃退。
代碼舉例
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)test;
@end
@implementation Person
- (void)test
{
NSLog(@"哈哈哈");
}
@end
/*
-[Person test]: unrecognized selector sent to instance 0x7fd2ea4097c0
給Person對象發送了一個不能識別的消息:test
*/
int main()
{
Person *p = [Person new];
// OC是在運行過程中才會檢測對象有沒有實現相應的方法
[p test];
return 0;
}
三、 類方法注意
知識點
1.類方法 通過類調用的方法 以加號 + 開頭
2.與對象方法的區別
1)用對象調用類的方法 可以編譯通過,報錯:方法未找到 因爲對象的方法都是減號 - 開頭的
2)用類調用對象的方法 可以編譯通過,報錯:方法未找到 因爲類的方法都是加號 + 開頭的
3.類方法和對象方法可以同名
4.類被加載到內存
5.對象方法:只能由對象調用 減號 開頭 類方法:只能由類調用 加號 開頭
6.類方法不用依賴於對象 所以就不存在成員變量(如果使用了該成員變量 編譯會報錯:實例變量不能在類方法裏被訪問)
7.成員變量是實例的變量 , 類裏面根本就沒有 ,只能被對象訪問
8.能用類方法就用類方法,這樣執行效率高。當方法內部不需要成員變量時,就可以改爲類方法。
9.使用場合:①基本沒有任何成員的類叫做工具類,裏面的方法基本都是類方法②方便在類中 用類相互調用③可以在對象方法裏 調用類的方法
代碼舉例
#import <Foundation/Foundation.h>
@interface Person:NSObject
+ (void) printClassName;
- (void) test;
@end
@implementation Person
+ (void) printClassName
{
NSLog(@“這個類叫做Person”);
}
- (void) test
{
NSLog(@“這個方法是對象的”);
}
@end
int main()
{
Person *p=[Person new];
[Person printClassName];//提高性能 沒創建對象 依然可以調用類的行爲方法 省了對象的內存
return 0;
}
四、 self的用法
知識點
1.語法:
1)self 指向當前方法調用者
2)可以利用“self->成員變量名”訪問當前對象內部的成員變量
3)[self 方法名]可以調用其他對象方法\類的方法
2.self使用注意
1)在一個方法裏使用self 調用自己 必會造成死循環
2)分析代碼 要從self當前指向的東西出發去判斷
3)函數和方法不一樣 函數不需要[]去調用
代碼舉例
#import<Foundation/Foundation.h>
@interface Person:NSObject
{
int _age;
}
- (void)setAge:(int) age;
- (int)age;
- (void)test;
- (void)test2;
@end
@implementation Person
- (void)setAge:(int) age
{
_age=age;//等效於 self->_age=age;
}
- (int)age
{
return _age;//等效於 self->_age;
}
- (void) test
{
int _age=33;/*語法上就近輸出它,但是我硬要輸出我的成員變量怎麼辦呢?1)先賦值給一個變量,用這個變量代替輸出
2)用self指針指向方法調用者 self->_age*/
NSLog(@“1Person的年齡%d歲”,_age);
}
- (void) test2
{
[self test];//
NSLog(@“2Person的年齡%d歲”,_age);
}
@end
int main()
{
Person *p=[Person new];
[p setAge:10];
[p test];
}
五、 面向對象特性之繼承(組合)
知識點
1.類B繼承類A,B就有了A的所有東西,這樣就抽取了重複代碼,建立了類之間的關係
2.子類可以擁有父類中的所有成員變量和方法
3.基本上所有類的根類都是NSObject
注意點
1.如果子類在父類之前聲明和實現 會報錯 因爲編譯器從上到下編譯的 所以父類要定義在子類之前
2.可以在父類的基礎上擴充自己成員變量和方法:
擴充自己成員變量時 1)不能有和父類有同名的成員變量
所以父類的方法可以只寫聲明不寫實現,實現交給子類(可以不再寫對應聲明)去實現就好了
3.當子類調用方法,首先在自己的類找,找不到再取去父類找,知道最高層類。
4.子類重新實現父類的某個方法,叫做重寫。於是就覆蓋了父類的所有行爲
5.創建子類的時候 子類和父類都已加載到內存了
6.每個類裏都有一個superclass 指針 用來指向父類
7.isa 和 superclass 指針 都是聲明在NSObject裏的 只有這樣 才能保證 每一個對象一旦創建就有一個isa指針
每個類一旦創建就有一個superclass指針
8.耦合性太強:類之間關係很緊密 (這使得 刪除一個都導致另一個不能用 弊端)
代碼舉例
#import<Foundation/Foundation.h>
@interface Animal:NSObject
{
int _age;
double _weight;
}
- (void) setAge:(int)age;
- (int) age;
- (void) setWeight:(int)weight;
- (int) weight;
@end
@implementation Animal
- (void) setAge:(int)age;
{
_age=age;
}
- (int) age
{
return age;
}
- (void) setWeight:(int)weight
{
_weight=weight;
}
- (int) weight
{
return _weight
}
@end
//狗
@interface Dog:Animal//Dog類繼承自Animal類
@end
@implemetation Dog
@end
//貓
@interface Cat:Animal//繼承了父類Animal所有成員變量和方法
@end
@implemetation Cat
@end
int main()
{
Dog *d=[Dog new];
[d setAge:10];//使用了父類的setAge
NSLog(@“狗的年齡%d”,[d age]);
return 0;
}
繼承和組合
1.當兩個類擁有相同屬性和方法的時候,就可以將相同的東西抽象到一個父類中
2.當A類擁有B類中的部分屬性和方法中,就可以考慮讓B類繼承A類,同時還得考慮A B類之間存在從屬關係
3.組合 :繼承不成 可以考慮組合 區別:繼承 xx 是 xxx ;組合 xxx擁有xxx
4.學生是個成績 X 學生擁有成績
繼承和組合簡單舉例
A
{
}
B:A//B繼承A
{
}
組合
A
{
}
B
{
A * _a;//B擁有A
}
六、 面向對象特性之多態
知識點
1.多態講的是 (父類)對象具有(多個子類)多態 (就是多種形態 要想多態 必須有繼承 沒有繼承 沒有多態)
【將多個方法合併成一個方法】
3.侷限性:Animal *aa=[Dog new]; [aa run];//編譯器會檢測Animal是否有run 沒有就會有警告 但是可以運行
(動態檢測出了真實類型)
4.父類類型的變量 不能調用子類特有的方法 ,必須要強制轉換下 轉換到子類類型
所以 Animal *aa=[Dog new]; [(Dog*)aa run];//強制轉換下 就OK了
5.Dog *dd=aa;//(不合理 動物是狗)可以等效於 Dog *dd=(Dog *)aa;//這樣就合法了
代碼舉例
#import<Foundation/Foundation.h>
@interface Animal:NSObject
- (void) eat;
@end
@implementation Animal
- (void) eat
{
NSLog(@“吃東西————”);
}
@end
@interface Dog:Animal
@end
@implementation Dog
@end
@interface Cat:Animal
@end
@implementation Cat
- (void) eat
{
NSLog(@“貓吃東西餓————”);
}
@end
void feed(Dog *d)/*如果也想用這個方法喂貓 直接傳貓對象顯然不合理 那麼怎麼辦呢??1)在寫一樣的方法 形參換下
2)直接 把形參 改爲 Animal *a */
{
[d eat];
}
int main()
{
//多種類型
Dog *d=[Dog new];//Dog 類型 狗以狗的形態存在
//多態:父類指針指向子類對象 狗以動物的形態存在
Animal *a=[Dog new];//OK
NSObject *n=[Animal new];//OK
NSObject *n2=[Dog new];//OK
[a eat];/*調用的eat是父類的還是子類的呢???真相是調用的是子類的 因爲調用時會自動檢測對象的真實類型
顯然這是a指向對象的真實類型是Dog*/
Cat *c=[Animal new];//動物是貓 但是OC這是弱語法(容錯能力強)所以不會報錯 但有警告 不提倡這樣寫
NSString *s=[Car new];//貓是字符串 但是OC這是弱語法 所以不會報錯 但有警告 不提倡這樣寫
feed(d);
}
七、 學習查缺補漏
1.super關鍵字作用
1.1.直接調用父類中的某個方法
1.2.super處在對象方法中,那麼就會調用父類的對象方法
super處在類方法中,那麼就會調用父類的類方法
1.3.使用場合:子類重寫父類的方法時想保留父類的一些行爲
#import <Foundation/Foundation.h>
// 殭屍
@interface Zoombie : NSObject
- (void)walk;
+ (void)test;
- (void)test;
@end
@implementation Zoombie
- (void)walk
{
NSLog(@"往前挪兩步******");
}
+ (void)test
{
NSLog(@"Zoombie+test");
}
- (void)test
{
NSLog(@"Zoombie-test");
}
@end
// 跳躍殭屍
@interface JumpZoombie : Zoombie
+ (void)haha;
- (void)haha2;
@end
@implementation JumpZoombie
+ (void)haha
{
[super test];
}
- (void)haha2
{
[super test];
}
- (void)walk
{
// 跳兩下
NSLog(@"跳兩下");
// 走兩下(直接調用父類的walk方法)
[super walk];
//NSLog(@"往前挪兩步----");
}
@end
int main()
{
//[JumpZoombie haha];
JumpZoombie *jz = [JumpZoombie new];
[jz haha2];
return 0;
}
2.NSString的使用
2.1.@“ddddddd”就是一個NSString類對象
2.2.NSString *str=@“dddd”;//好處 以面向對象的形式處理字符串 獲取長度 int size =[str length];
2.3.[str length]返回的是unsigned long 類型的 統計的是字數(包括空格)不是字符數了 一個漢字 一個字母 就是2個
2.4.char *str=“dddd”;//不建議使用
代碼舉例
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
//char *_name;
NSString *_name;
}
@end
int main()
{
/*
// 最簡單的創建字符串的方式
NSString *str = @"iloveios";
char *name = "iloveios";
NSLog(@"我在%@寫代碼", str);
//NSLog(@"%s", name);
*/
int age = 15;
int no = 5;
NSString *name = @"哈哈jack";
// length方法算的是字數
int size = [name length];
NSLog(@"%d", size);
// 創建OC字符串的另一種方式
NSString *newStr = [NSString stringWithFormat:@"My age is %d and no is %d
and name is %@", age, no, name];
NSLog(@"---- %ld", [newStr length]);
return 0;
}