一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - IOS - 舉例講解Objective-C中@property屬性的用法

舉例講解Objective-C中@property屬性的用法

2021-01-12 16:07子龍山人 IOS

這篇文章主要介紹了Objective-C中@property屬性的用法,包括@property的屬性關鍵字的整理,需要的朋友可以參考下

學過c/c++的朋友都知道,我們定義struct/class的時候,如果把訪問限定符(public,protected,private)設置為public的話,那么我們是可以直接用.號來訪問它內部的數據成員的。比如

?
1
2
3
4
5
6
7
//in test.h
class test
{
public:
  int i;
  float f;
};

  我在main函數里面是可以通過下面的方式來使用這個類的:(注意,如果在main函數里面使用此類,除了要包含頭文件以外,最重要的是記得把main.m改成main.mm,否則會報一些奇怪的錯誤。所以,任何時候我們使用c++,如果報奇怪的錯誤,那就要提醒自己是不是把相應的源文件改成.mm后綴了。其它引用此類的文件有時候也要改成.mm文件)

?
1
2
3
4
5
6
//in main.mm
test test;
test.i =1;
test.f =2.4f;
 
nslog(@"test.i = %d, test.f = %f",test.i, test.f);

  但是,在objc里面,我們能不能這樣做呢?請看下面的代碼:(新建一個objc類,命名為baseclass)

復制代碼 代碼如下:

//in baseclass.h
@interface baseclass : nsobject{
@public
    nsstring *_name;
}


 接下來,我們在main.mm里面:

復制代碼 代碼如下:

    baseclass *base= [[baseclass alloc] init];
    base.name =@"set base name";
    nslog(@"base class's name = %@", base.name);
   


  不用等你編譯,xcode馬上提示錯誤,請看截圖:

 

舉例講解Objective-C中@property屬性的用法

請大家注意看出錯提示“property 'nam' not found on object of type baseclass*",意思是,baseclass這類沒有一個名為name的屬性。即使我們在頭文件中聲明了@public,我們仍然無法在使用baseclass的時候用.號來直接訪問其數據成員。而@public,@protected和@private只會影響繼承它的類的訪問權限,如果你使用@private聲明數據成員,那么在子類中是無法直接使用父類的私有成員的,這和c++,java是一樣的。

  既然有錯誤,那么我們就來想法解決啦,編譯器說沒有@property,那好,我們就定義property,請看代碼:

復制代碼 代碼如下:

//in baseclass.h
@interface baseclass : nsobject{
@public
    nsstring *_name;
}
@property(nonatomic,copy) nsstring *name;
//in baseclass.m
@synthesize name = _name;


  現在,編譯并運行,ok,很好。那你可能會問了@prperty是不是就是讓”."號合法了呀?只要定義了@property就可以使用.號來訪問類的數據成員了?先讓我們來看下面的例子:

復制代碼 代碼如下:


@interface baseclass : nsobject{
@public
    nsstring *_name;
}
//@property(nonatomic,copy) nsstring *name;

 

-(nsstring*) name;
-(void) setname:(nsstring*)newname;


  我把@property的定義注釋掉了,另外定義了兩個函數,name和setname,下面請看實現文件:

復制代碼 代碼如下:


//@synthesize name = _name;

 

-(nsstring*) name{
    return _name;
}

-(void) setname:(nsstring *)name{
    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}


  現在,你再編譯運行,一樣工作的很好。why?因為我剛剛做的工作和先前聲明@property所做的工作完全一樣。@prperty只不過是給編譯器看的一種指令,它可以編譯之后為你生成相應的getter和setter方法。而且,注意看到面property(nonatomic,copy)括號里面這copy參數了嗎?它所做的事就是

復制代碼 代碼如下:


_name = [name copy];
  如果你指定retain,或者assign,那么相應的代碼分別是:

 

//property(retain)nsstring* name;
_name = [name retain];

//property(assign)nsstring* name;
_name = name;


  其它講到這里,大家也可以看出來,@property并不只是可以生成getter和setter方法,它還可以做內存管理。不過這里我暫不討論?,F在,@property大概做了件什么事,想必大家已經知道了。但是,我們程序員都有一個坎,就是自己沒有完全吃透的東西,心里用起來不踏實,特別是我自己。所以,接下來,我們要詳細深挖@property的每一個細節。

 

  首先,我們看atomic 與nonatomic的區別與用法,講之前,我們先看下面這段代碼:

 

復制代碼 代碼如下:


@property(nonatomic, retain) uitextfield *username;    //1

 

@property(nonatomic, retain,readwrite) uitextfield *username;  //2

@property(atomic, retain) uitextfield *username;  //3

@property(retain) uitextfield *username;  //4

@property(atomic,assign) int i;         // 5

@property(atomic) int i;         //6
@property int i;               //7


  請讀者先停下來想一想,它們有什么區別呢?

 

  上面的代碼1和2是等價的,3和4是等價的,5,6,7是等價的。也就是說atomic是默認行為,assign是默認行為,readwrite是默認行為。但是,如果你寫上@property(nontomic)nsstring *name;那么將會報一個警告,如下圖:

舉例講解Objective-C中@property屬性的用法

 因為是非gc的對象,所以默認的assign修飾符是不行的。那么什么時候用assign、什么時候用retain和copy呢?推薦做法是nsstring用copy,delegate用assign(且一定要用assign,不要問為什么,只管去用就是了,以后你會明白的),非objc數據類型,比如int,float等基本數據類型用assign(默認就是assign),而其它objc類型,比如nsarray,nsdate用retain。

  在繼續之前,我還想補充幾個問題,就是如果我們自己定義某些變量的setter方法,但是想讓編譯器為我們生成getter方法,這樣子可以嗎?答案是當然可以。如果你自己在.m文件里面實現了setter/getter方法的話,那以翻譯器就不會為你再生成相應的getter/setter了。請看下面代碼:

復制代碼 代碼如下:


//代碼一:
@interface baseclass : nsobject{
@public
    nsstring *_name;
}
@property(nonatomic,copy,readonly) nsstring *name;  //這里使用的是readonly,所有會聲明geter方法

 

-(void) setname:(nsstring*)newname;

//代碼二:
@interface baseclass : nsobject{
@public
    nsstring *_name;
}
@property(nonatomic,copy,readonly) nsstring *name;   //這里雖然聲明了readonly,但是不會生成getter方法,因為你下面自己定義了getter方法。

-(nsstring*) name;   //getter方法是不是只能是name呢?不一定,你打開foundation.framework,找到uiview.h,看看里面的property就明白了)
-(void) setname:(nsstring*)newname;

//代碼三:
@interface baseclass : nsobject{
@public
    nsstring *_name;
}
@property(nonatomic,copy,readwrite) nsstring *name;  //這里編譯器會我們生成了getter和setter

//代碼四:
@interface baseclass : nsobject{
@public
    nsstring *_name;
}
@property(nonatomic,copy) nsstring *name;  //因為readwrite是默認行為,所以同代碼三


  上面四段代碼是等價的,接下來,請看下面四段代碼:  

 

 

復制代碼 代碼如下:


//代碼一:
@synthesize name = _name;  //這句話,編譯器發現你沒有定義任何getter和setter,所以會同時會你生成getter和setter

 

//代碼二:
@synthesize name = _name;  //因為你定義了name,也就是getter方法,所以編譯器只會為生成setter方法,也就是setname方法。

-(nsstring*) name{
    nslog(@"name");
    return _name;
}

//代碼三:
@synthesize name = _name;   //這里因為你定義了setter方法,所以編譯器只會為你生成getter方法

-(void) setname:(nsstring *)name{
    nslog(@"setname");
    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}

//代碼四:
@synthesize name = _name;  //這里你自己定義了getter和setter,這句話沒用了,你可以注釋掉。

-(nsstring*) name{
    nslog(@"name");
    return _name;
}

-(void) setname:(nsstring *)name{
    nslog(@"setname");
    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}


  上面這四段代碼也是等價的??吹竭@里,大家對property的作用相信會有更加進一步的理解了吧。但是,你必須小心,你如果使用了property,而且你自己又重寫了setter/getter的話,你需要清楚的明白,你究竟干了些什么事。別寫出下面的代碼,雖然是合法的,但是會誤導別人:

復制代碼 代碼如下:


//baseclass.h
@interface baseclass : nsobject{
@public
    nsarray *_names;
}
@property(nonatomic,assgin,readonly) nsarray *names;  //注意這里是assign

 

-(void) setnames:(nsarray*)names;

//baseclass.m
@implementation baseclass

@synthesize names = _names;

-(nsarray*) names{
    nslog(@"names");
    return _names;
}

-(void) setnames:(nsarray*)names{
    nslog(@"setnames");
    if (_name != name) {
        [_name release];
        _name = [name retain];  //你retain,但是你不覆蓋這個方法,那么編譯器會生成setnames方法,里面肯定是用的assign
    }
}


  當別人使用@property來做內存管理的時候就會有問題了??偨Y一下,如果你自己實現了getter和setter的話,atomic/nonatomic/retain/assign/copy這些只是給編譯的建議,編譯會首先會到你的代碼里面去找,如果你定義了相應的getter和setter的話,那么好,用你的。如果沒有,編譯器就會根據atomic/nonatomic/retain/assign/copy這其中你指定的某幾個規則去生成相應的getter和setter。

 

我們來整理一下@property中的屬性關鍵字:
1.原子性 nonatomic/atomic

在默認的情況下,由編譯器合成的方法會通過鎖定機制確保其原子性(atomicity)。如果具備nonatomic特質,則不使用同步鎖。

2.讀/寫權限  readwrite/readonly

3.內存管理語義

assign “設置方法” 只會針對“純量類型”(scalar type, cgfloat或nsinteger等)的簡單賦值操作

strong “擁有關系” 為這種屬性設置新值時,設置方法先保留新值,并釋放舊值,然后再將新值設置上去

weak “非擁有關系” 為這種屬性設置新值時,設置方法既不保留新值,也不釋放舊值。此特質同assign類似,然而屬性所指的對象遭到摧毀時,屬性也會被清空(nil out)

unsafe_unretained 此特質的語義和assign相同,但是它適用于“對象類型”(object type),該特質表達一種“非擁有關系”(“不保留”,unretained),當目標對象遭到摧毀時,屬性值不會自動清空(“不安全”,unsafe),這一點與weak有區別

copy 此特質所表達的所屬關系與strong類似。然而設置方法并不保留新值,而是將其“拷貝”(copy)

4.方法名

getter=<name>

@property (nonatomic, getter=ison) bool on;

setter=<name> 不太常用


總結
  好了,說了這么多,回到我們的正題吧。atomic和nonatomic的作用與區別:

  如果你用@synthesize去讓編譯器生成代碼,那么atomic和nonatomic生成的代碼是不一樣的。如果使用atomic,如其名,它會保證每次getter和setter的操作都會正確的執行完畢,而不用擔心其它線程在你get的時候set,可以說保證了某種程度上的線程安全。但是,我上網查了資料,僅僅靠atomic來保證線程安全是很天真的。要寫出線程安全的代碼,還需要有同步和互斥機制。

  而nonatomic就沒有類似的“線程安全”(我這里加引號是指某種程度的線程安全)保證了。因此,很明顯,nonatomic比atomic速度要快。這也是為什么,我們基本上所有用property的地方,都用的是nonatomic了。

  還有一點,可能有讀者經常看到,在我的教程的dealloc函數里面有這樣的代碼:self.xxx = nil;看到這里,現在你們明白這樣寫有什么用了吧?它等價于[xxx release];  xxx = [nil retain];(---如果你的property(nonatomic,retian)xxx,那么就會這樣,如果不是,就對號入座吧)。

  因為nil可以給它發送任何消息,而不會出錯。為什么release掉了還要賦值為nil呢?大家用c的時候,都有這樣的編碼習慣吧。

  int* arr = new int[10];    然后不用的時候,delete arr; arr = null;  在objc里面可以用一句話self.arr = nil;搞定。

延伸 · 閱讀

精彩推薦
  • IOSiOS實現控制屏幕常亮不變暗的方法示例

    iOS實現控制屏幕常亮不變暗的方法示例

    最近在工作中遇到了要將iOS屏幕保持常亮的需求,所以下面這篇文章主要給大家介紹了關于利用iOS如何實現控制屏幕常亮不變暗的方法,文中給出了詳細的...

    隨風13332021-04-02
  • IOSiOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果

    這篇文章主要介紹了iOS自定義UICollectionViewFlowLayout實現圖片瀏覽效果的相關資料,需要的朋友可以參考下...

    jiangamh8882021-01-11
  • IOS詳解iOS中多個網絡請求的同步問題總結

    詳解iOS中多個網絡請求的同步問題總結

    這篇文章主要介紹了詳解iOS中多個網絡請求的同步問題總結,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧...

    liang199111302021-03-15
  • IOSiOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)

    iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和

    這篇文章主要介紹了iOS中滑動控制屏幕亮度和系統音量(附加AVAudioPlayer基本用法和Masonry簡單使用)的相關資料,需要的朋友可以參考下...

    CodingFire13652021-02-26
  • IOSiOS中UILabel實現長按復制功能實例代碼

    iOS中UILabel實現長按復制功能實例代碼

    在iOS開發過程中,有時候會用到UILabel展示的內容,那么就設計到點擊UILabel復制它上面展示的內容的功能,也就是Label長按復制功能,下面這篇文章主要給大...

    devilx12792021-04-02
  • IOSiOS中MD5加密算法的介紹和使用

    iOS中MD5加密算法的介紹和使用

    MD5加密是最常用的加密方法之一,是從一段字符串中通過相應特征生成一段32位的數字字母混合碼。對輸入信息生成唯一的128位散列值(32個字符)。這篇文...

    LYSNote5432021-02-04
  • IOSiOS開發之視圖切換

    iOS開發之視圖切換

    在iOS開發中視圖的切換是很頻繁的,獨立的視圖應用在實際開發過程中并不常見,除非你的應用足夠簡單。在iOS開發中常用的視圖切換有三種,今天我們將...

    執著丶執念5272021-01-16
  • IOSiOS開發技巧之狀態欄字體顏色的設置方法

    iOS開發技巧之狀態欄字體顏色的設置方法

    有時候我們需要根據不同的背景修改狀態欄字體的顏色,下面這篇文章主要給大家介紹了關于iOS開發技巧之狀態欄字體顏色的設置方法,文中通過示例代碼...

    夢想家-mxj8922021-05-10
主站蜘蛛池模板: 狠狠色成人综合网图片区 | 91久久国产露脸精品 | 91在线精品国产 | 色多多视频网站 | 武侠古典久久亚洲精品 | 丝袜护士强制脚足取精 | 俄罗斯年轻男同gay69 | 日韩欧美国产成人 | 日本免费观看的视频在线 | 亚洲精品色婷婷在线影院麻豆 | 国产最新精品视频 | 污污的动态图合集 | 久久免费观看视频 | 精选国产AV精选一区二区三区 | 国产精品女主播自在线拍 | 久久学生精品国产自在拍 | 小寡妇水真多好紧 | va在线视频 | 色婷婷久久综合中文久久一本 | 国产精品久久免费观看 | 青草热久精品视频在线观看 | 俄罗斯激情性孕妇孕交大全 | 边打电话边操 | 久久re热在线视频精69 | 日本护士撒尿 | 免费一级欧美片片线观看 | 舔大逼 | 国产激情久久久久影院小草 | 性生大片免费看 | 欧美成人免费观看的 | 99re热这里只有精品视频 | 午夜精品久久久久久 | 亚洲女人国产香蕉久久精品 | 欧美日韩视频在线第一区二区三区 | 男gay男gay男gay野外 | 九九艹| 美女私人影院 | 国产在视频线在精品 | 久久久久久久伊人电影 | 放荡的女老板bd中文字幕 | 亚洲国产欧美日韩在线一区 |