];
p->_size = 3.5;
p->_color = 0;
p->_model = 4;
p->_cpu = 1;
####類
創建對象的時候返回的地址其實就是對象的第0個屬性的地址
但是需要注意的是: 對象的第0個屬性并不是我們編寫的屬性, 而是一個叫做isa的屬性
isa是一個指針, 占8個字節
其實類也是一個對象, 也就意味著Person也是一個對象
平時我們所說的創建對象其實就是通過一個 類對象 來創建一個 新的對象
類對象是系統自動幫我們創建的, 里面保存了當前對象的所有方法
而實例對象是程序自己手動通過new來創建的, 而實例對象中有一個isa指針就指向了創建它的那個類對象
如下圖:

#####成員變量,局部變量,全局變量
寫在類聲明的大括號中的變量, 我們稱之為 成員變量(屬性, 實例變量)
成員變量只能通過對象來訪問
注意: 成員變量不能離開類, 離開類之后就不是成員變量
成員變量不能在定義的同時進行初始化
存儲: 堆(當前對象對應的堆的存儲空間中)
存儲在堆中的數據, 不會被自動釋放, 只能程序員手動釋放
寫在函數和大括號外部的變量, 我們稱之為全局變量
作用域: 從定義的那一行開始, 一直到文件末尾
局部變量可以先定義在初始化, 也可以定義的同時初始化
存儲: 靜態區
程序一啟動就會分配存儲空間, 直到程序結束才會釋放
寫在函數或者代碼塊中的變量, 我們稱之為局部變量
作用域: 從定義的那一行開始, 一直到遇到大括號或者return
局部變量可以先定義再初始化, 也可以定義的同時初始化
存儲 : 棧
存儲在棧中的數據有一個特點, 系統會自動給我們釋放
#####點語法
如果給屬性提供了getter和setter方法, 那么訪問屬性就又多了一種訪問方式 , 點語法
點語法其實它的本質是調用了我們的setter和getter方法
點語法是一個編譯器的特性, 會在程序翻譯成二進制的時候將.語法自動轉換為setter和getter方法
如果點語法在=號的左邊, 那么編譯器會自動轉換為setter方法
如果點語法在=號的右邊, 或者沒有等號, 那么編譯器就會自動轉換為getter方法
點語法的注意點:
點語法一般用于給成員變量賦值, 如果不是給成員
變量賦值一般情況下不建議使用, 但是也可以使用
如調用test方法,可以寫成p.test,相當于[p test]
#####多態
多態是事物的多種表現形態
在程序中如何表現:
父類指針指向子類對象
優點:
提高了代碼的擴展性
注意點:
如果父類指針指向子類對象, 如果需要調用子類特有的方法, 必須先強制類型轉換為子類才能調用
動態類型: 在編譯的時候編譯器只會檢查當前類型 對應的類中有沒有需要調用的方法
在運行時,系統會自動判斷a1的真實類型
例如:
Animal:動物類
import <Foundation/Foundation.h>
@interface Animal : NSObject
{
int _age;
}
- (void)eat;
@end
import "Animal.h"
@implementation Animal
- (void)eat
{
NSLog(@"吃東西");
}
@end
Dog狗類,繼承動物類:
import <Foundation/Foundation.h>
import "Animal.h"
@interface Dog : Animal
- (void)kanJia;
@end
import "Dog.h"
@implementation Dog
(void)eat
{
NSLog(@"啃骨頭");
}(void)kanJia
{
NSLog(@"看家, 旺旺叫");
}
@end
Animal *a1 = [Dog new];
[a1 eat];
編譯時因為動物有eat方法,不報錯。但是運行時判斷為dog對象,調用dog對象的eat方法
#####實例變量修飾符
@public 就是實例變量修飾符
@public
>可以在其它類中訪問被public修飾的成員變量
>也可以在本類中訪問被public修飾的成員變量
>可以在子類中訪問父類中被public修飾的成員變量
@private
>不可以在其它類中訪問被private修飾的成員變量
>可以在本類中訪問被private修飾的成員變量
>不可以在子類中訪問父類中被private修飾的成員變量
@protected
>不可以在其它類中訪問被protected修飾的成員變量
>可以在本類中訪問被protected修飾的成員變量
>可以在子類中訪問父類中被protected修飾的成員變量
注意: 默認情況下所有的實例變量都是protected
@package
>介于public和private之間的
如果是在其它包中訪問那么就是private的
如果是在當前代碼所在的包種訪問就是public的
#####description
NSlog(@"",moumoumou)
%@是用來打印對象的, 其實%@的本質是用于打印字符串
只要利用%@打印某個對象, 系統內部默認就會調用父類的description方法
調用該方法, 該方法會返回一個字符串, 字符串的默認格式 <類的名稱: 對象的地址>
可以重寫description方法, 返回我們需要打印的內容
只要利用%@打印對象, 就會調用description
如果通過%@打印對象就會調用-號開頭的
如果通過%@打印類對象就會調用+號開頭的
建議: 在description方法中盡量不要使用self來獲取成員變量
因為如果你經常在description方法中使用self, 可能已不小心就寫成了 %@, self
如果在description方法中利用%@輸出self會造成死循環,例如下面:
- (NSString *)description
{
return [NSString stringWithFormat:@"%@", self];
}
####@porperty
在Xocde4.4之前, 可以使用@porperty來代替getter/setter方法的聲明
也就是說我們只需要寫上@porperty就不用寫getter/setter方法的聲明
@synthesize是一個編譯器指令, 它可以簡化我們getter/setter方法的實現
什么是實現:
在聲明后面寫上大括號就代表著實現
(1)在@synthesize后面告訴編譯器, 需要實現哪個@property生成的聲明
(2)告訴@synthesize, 需要將傳入的值賦值給誰和返回誰的值給調用者
如果在@synthesize后面沒有告訴系統將傳入的值賦值給誰, 系統默認會賦值給和@synthesize后面寫得名稱相同的成員變量
例如:
@synthesize age;就代表實現age成員變量的get, set,不是_age.
從Xcode4.4以后apple對@property進行了一個增強, 以后只要利用一個@property就可以同時生成setter/getter方法的聲明和實現
沒有告訴@property要將傳入的參數賦值給誰, 默認@property會將傳入的屬性賦值給_開頭的成員變量
@property有一個弊端: 它只會生成最簡單的getter/setter方法的聲明和實現, 并不會對傳入的數據進行過濾
如果想對傳入的數據進行過濾, 那么我們就必須重寫getter/setter方法
如果不想對傳入的數據進行過濾, 僅僅是提供一個方法給外界操作成員變量, 那么就可以使用@property
如果利用@property來生成getter/setter方法, 那么我們可以不寫成員變量, 系統會自動給我們生成一個_開頭的成員變量
注意: @property自動幫我們生成的成員變量是一個私有的成員變量, 也就是說是在.m文件中生成的, 而不是在.h文件中生成的
如果重寫了setter方法, 那么property就只會生成getter方法
如果重寫了getter方法, 那么property就只會生成setter方法
如果同時重寫了getter/setter方法, 那么property就不會自動幫我們生成私有的成員變量
####id類型
id是一個數據類型, 并且是一個動態數據類型
默認情況下所有的數據類型都是靜態數據類型
靜態數據類型的特點:
在編譯時就知道變量的類型,
知道變量中有哪些屬性和方法
在編譯的時候就可以訪問這些屬性和方法,
并且如果是通過靜態數據類型定義變量, 如果訪問了不屬于靜態數據類型的屬性和方法, 那么編譯器就會報錯
動態數據類型的特點:
在編譯的時候編譯器并不知道變量的真實類型, 只有在運行的時候才知道它的真實類型
并且如果通過動態數據類型定義變量, 如果訪問了不屬于動態數據類型的屬性和方法, 編譯器不會報錯
#####類的本質
類其實也是一個對象, 這個對象會在這個類第一次被使用的時候創建
只要有了類對象, 將來就可以通過類對象來創建實例對象
實例對象中有一個isa指針, 指向創建自己的類對象
類對象中保存了當前對象所有的對象方法
當給一個實例對象發送消息的時候, 會根據實例對象中的isa指針去對應的類對象中查找

啟動過程:
只要程序啟動就會將所有類的代碼加載到內存中, 放到代碼區。load方法會在當前類被加載到內存的時候調用, 有且僅會調用一次。如果存在繼承關系, 會先調用父類的load方法, 再調用子類的load方法。當當前類第一次被使用的時候就會調用(創建類對象的時候)。initialize方法在整個程序的運行過程中只會被調用一次, 無論你使用多少次這個類都只會調用一次。initialize用于對某一個類進行一次性的初始化。initialize和load一樣, 如果存在繼承關系, 會先調用父類的initialize再調用子類的initialize。
#####內存管理
野指針:
只要一個對象被釋放了, 我們就稱這個對象為 "僵尸對象"。當一個指針指向一個僵尸對象, 我們就稱這個指針為野指針。只要給一個野指針發送消息就會報錯。為了避免給野指針發送消息會報錯, 一般情況下, 當一個對象被釋放后我們會將這個對象的指針設置為空指針。
#####@class
應用場景1:
聲明一個類
應用場景2:
防止循環拷貝,造成死循環。(import引入會拷貝文件內容,如果.h1引入.h2,.h2又引入.h1,會造成循環拷貝)
#####Block
MRC:
返回值 (^block名字 )(參數列表)
取別名
typedef (^bieblock)(int,int)
就可以用 bieblock來定義新block,類型為上面
如:
bieblock block1;
block1 = ^(int value1, int value2){
return value1 + value2;
};
// 1.block中可以訪問外面的變量
/*
int a = 10;
void (^myBlock)() = ^{
NSLog(@"a = %i", a);
};
myBlock();
打印a = 10
// 2.block中可以定義和外界同名的變量, 并且如果在block中定義了和外界同名的變量, 在block中訪問的是block中的變量
/*
int a = 10;
void (^myBlock)() = ^{
int a = 20;
NSLog(@"a = %i", a);
};
myBlock();
*/
打印a = 20;
//
// 3.默認情況下, 不可以在block中修改外界變量的值
// 因為block中的變量和外界的變量并不是同一個變量
// 如果block中訪問到了外界的變量, block會將外界的變量拷貝一份到堆內存中
// 因為block中使用的外界變量是copy的, 所以在調用之前修改外界變量的值, 不會影響到block中copy的值
/*
int a = 10;
NSLog(@"&a = %p", &a);
void (^myBlock)() = ^{
// a = 50;
NSLog(@"&a = %p", &a);
NSLog(@"a = %i", a);
};
a = 20;
myBlock();
*/
/*
// 如果想在block中修改外界變量的值, 必須在外界變量前面加上__block
// 如果在block中修改了外界變量的值, 會影響到外界變量的值
__block int a = 10;
NSLog(@"&a = %p", &a);
void (^myBlock)() = ^{
a = 50;
NSLog(@"&a = %p", &a);
NSLog(@"a = %i", a);
};
myBlock();
NSLog(@"a = %i", a);
*/
/*
// 默認情況下block存儲在棧中, 如果對block進行一個copy操作, block會轉移到堆中
// 如果block在棧中, block中訪問了外界的對象, 那么不會對對象進行retain操作
// 但是如果block在堆中, block中訪問了外界的對象, 那么會對外界的對象進行一次retain
// 如果在block中訪問了外界的對象, 一定要給對象加上__block, 只要加上了__block, 哪怕block在堆中, 也不會對外界的對象進行retain
// 如果是在ARC開發中就需要在前面加上__weak
內存管理:
MRC:管理block
總結:只要block沒有引用外部局部變量,block放在全局區
只要Block引用外部局部變量,block放在棧里面.
block只能使用copy,不能使用retain,使用retain,block還是在棧里面
只要block沒有引用外部局部變量,block放在全局區
ARC:管理block
只要block引用外部局部變量,block放在堆里面
block使用strong.最好不要使用copy
#####copy屬性
// 如果是通過不可變對象調用了copy方法, 那么不會生成一個新的對象
// 原因: 因為原來的對象是不能修改的, 拷貝出來的對象也是不能修改的
// 既然兩個都不能修改, 所以永遠不能影響到另外一個對象, 那么已經符合需求
// 所以: OC為了對內存進行優化, 就不會生成一個新的對象(比如nsstring->nsstring)
正是因為調用copy方法有時候會生成一個新的對象, 有時候不會生成一個新的對象
所以: 如果沒有生成新的對象, 我們稱之為淺拷貝, 本質就是指針拷貝
如果生成了新的對象, 我們稱之為深拷貝, 本質就是會創建一個新的對象
// 3.注意點: copy block之后引發循環引用(MRC中)
(
// 如果對象中的block又用到了對象自己, 那么為了避免內存泄露, 應該將對象修飾為__block
__block Person *p = [[Person alloc] init]; // 1
p.name = @"lnj";
NSLog(@"retainCount = %lu", [p retainCount]);
p.pBlock = ^{
NSLog(@"name = %@", p.name); // 2
};
NSLog(@"retainCount = %lu", [p retainCount]);
p.pBlock();
[p release]; // 1
)

![Uploading 屏幕快照 2017-06-22 上午12.15.06_880264.png . . .]