程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Objective-C學習筆記_屬性

Objective-C學習筆記_屬性

編輯:關於C語言

Objective-C學習筆記_屬性


一、屬性

屬性是Objective-C 2.0定義的語法,為實例變量提供了setter、getter方法的默認實現。能在一定程度上簡化程序代碼,並且增強實例變量的訪問安全性。

屬性的聲明

與類相似,屬性也需要聲明和實現。

屬性的聲明:使用@property聲明屬性

例如:@property NSString *name;

相當於 @interface 中聲明了兩個方法(setter、getter):

- (void)setName:(NSString *)name;

- (NSString *)name;

屬性的實現

屬性的實現:使用@synthesize實現屬性

例如:@synthesize name = _name;

相當於 @implementation 實現了setter、getter

- (void)setName:(NSString *)name
{
    _name = name;
}

- (NSString *)name
{
    return _name;
}

注意:

原先 @property 聲明與實現文件中的另一個聲明 @synthesize 相結合,來完成setter、getter方法的創建。Xcode4.5之後 @synthesize 會在內部自動生成,不用手動添加。但是,如果屬性 @property 聲明之後,要在.m實現文件中重寫setter、getter方法,則必須在.m實現文件中添加 @synthesize。

屬性聲明後,重寫setter、getter方法,聲明@synthesize的示例代碼如下:

#import 

@interface Person : NSObject

@property NSString *name;

- (void)setName:(NSString *)name;
- (NSString *)name;

@end


#import Person.h

@implementation Person

/* 屬性聲明後,重寫setter、getter方法,必須聲明@synthesize */
@synthesize name = _name;

- (void)setName:(NSString *)name
{
    _name = name;
}

- (NSString *)name
{
    return _name;
}
@end


二、屬性的屬性(Attribute)

Objective-C提供屬性的目的是為了簡化程序員編碼,為屬性提供了一些關鍵字?以控制setter、getter的實現細節,這些關鍵字我們稱為屬性的屬性(attribute)。屬性的屬性一共3大類。

第一類:讀寫性控制(readonly、readwrite、setter、getter)

readonly,告訴編譯器,只聲明getter方法(無setter方法)。

例如:@property (readonly) NSString *name; //等價於 - (NSString *) name;

readwrite,告訴編譯器,既聲明setter?聲明getter。

例如: @property (readwrite) NSString *name; //等價於 - (NSString *) name; - (void)setName:(NSString *)name;,讀寫性控制的默認設置。

setter = 方法名,指定設置器的方法名。

getter = 方法名,指定訪問器的方法名。

第二類:原子性控制(nonatomic、atomic)

atomic,setter、getter方法在多線程訪問下是絕對安全的,即setter、getter內部做了多線程訪問處理。原?子性控制的默認設置是atomic。

nonatomic,setter、getter方法內部不會做多線程訪問處理,僅僅是普通的setter、getter?法。

程序開發過程中,setter、getter處處都在用,如果使用atomic,需要不斷對setter、getter加鎖解鎖以保證線程訪問安全,會很占用系統資源,降低系統性能通常設置為nonatomic,某些屬性需要線程安全的時候,才定義為atomic。

例如:

@property (readwrite, nonatomic) NSString *name;
//等價於
- (NSString *)name;
- (void)setName:(NSString *)name;

第三類:語義設置(assign、retain、copy)

assign,setter、getter內部實現是直接賦值,適用於基本數據類型,默認值。

例如:

@property (nonatomic, assign) NSString *name;

- (void)setName:(NSString *)name{
  _name = name;
}
- (NSString *)name{
  return _name;
}

retain,setter、getter的內部實現會做內存優化,適用於對象類型。

例如:

@property (nonatomic, retain) NSString *name;

- (void)setName:(NSString *)name{
if(_name != name){
  [_name release];
  _name = [name retain];
}
}
- (NSString *)name{
  return [[_name retain]autorelease];
}

copy,setter、getter的內部實現也會做內存優化,復制一個副本,適用於特殊的對象類型,一般適用於NSSting。

例如:

@property (nonatomic, copy) NSString *name;

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


- (NSString *)name{
  return [[_name retain]autorelease];
}

小結:

如果屬性是?對象類型(比如int,float等)屬性的語義設置使用assign。 如果屬性是對象類型(?如NSStrng、NSArray等)屬性的語義設置使用retain。 如果屬性是對象類型並且想得到參數的copy,使用copy關鍵字。

三、點語法

點語法是Objective-C 2.0中定義的語法格式。提供了?種便捷的屬性訪問?式。

點語法的使用

凡是符合系統默認setter、getter書寫格式的方法都可以使用點語法。

例如:[person1 setName:@”ZhangSan”];可以等價寫成person1.name = @”ZhangSan”;

NSString *name = [person1 name];可以等價寫成NSString *name = person1.name;

屬性是一對getter、setter方法,點語法是屬性的另一種調用格式。


四、KVC

KVC(Key-Value-Coding),鍵值編碼,是一種間接訪問實例變量的方法

key:鍵,用於標識實例變量。

vlaue:實例變量對應的值。

修改值

setValue:forKey: setValue:forKeyPath: setValue:forUndefinedKey: setValuesForKeysWithDictionary:

獲取值

valueForKey: valueForKeyPath: valueForUndefinedKey:

注意事項

當key不存在的時候,會執行setValue:forUndefinedKey:

系統默認實現是拋出一個異常

為了更好的體驗KVC的用途,以下是示例代碼:

要求
定義一個Classroom類: 實例變量: 教室編號, 學生(Person類)
實例變量不寫setter, getter方法

Classroom.h文件代碼如下:

#import 
@class Person;

@interface Classroom : NSObject
{
@protected
    NSString *_classNum;
    Person *_student;
}

#pragma mark - 重寫父類方法
- (void)setValue:(id)value forUndefinedKey:(NSString *)key;

- (id)valueForUndefinedKey:(NSString *)key;
@end

Classroom.m文件代碼如下:

#import Classroom.h
#import Person.h

@implementation Classroom
- (void)setValue:(id)value forUndefinedKey:(NSString *)key
{
    NSLog(@無此實例變量: %@, key);
}

- (id)valueForUndefinedKey:(NSString *)key
{
    NSLog(@無此實例變量: %@, key);
    return nil;
}
@end

Person.h文件代碼如下:

#import 

@interface Person : NSObject
/* 實例變量 */
{
@protected
    NSString *_name;
    NSInteger _age;
}

#pragma mark - 屬性的聲明
/* 代碼規范: 屬性的名字沒有 _
 * 屬性包含三部分內容: 實例變量, 實例變量的setter方法, 實例變量的getter方法
 */
@property NSString *hobby;
@property NSString *sex;

#pragma mark - 屬性的屬性(特性)
/* 第一類 attribute: 讀寫性控制
 * readonly: 相當於只提供了getter方法
 * readwrite: 相當於提供了setter 和 getter方法
 * 默認: readwrite
 * 通常設置: readwrite
 */
//@property (readonly) NSString *name;

/* 第二類: attribute: 原子性控制
 * atomic: 原子性
 * nonatomic: 非原子性
 * 默認: atomic
 * 通常設置: nonatomic
 */
@property (readwrite, nonatomic) NSString *height;

/* 第三類 attribute: 語義設置
 * assign: 非對象類型使用: int, float, NSInteger
 * retain: 對象類型使用: NSString, NSArray, 會對setter, getter方法進行內存優化
 * copy: 對象類型使用, 對setter, getter方法進行內存優化
 * 默認: assign
 */
@property (readwrite, nonatomic, assign) NSInteger weight;

@property (readwrite, nonatomic, retain) NSString *marry;

@property (readwrite, nonatomic, copy) NSString *work;

/* 通常的屬性聲明 */
@property (nonatomic, retain) NSString *blood;

#pragma mark -
/* 實例變量setter, getter方法 */
- (void)setName:(NSString *)name;
- (NSString *)name;

- (void)setAge:(NSInteger)age;
- (NSInteger)age;
@end

Person.m文件代碼如下:

#import Person.h

@implementation Person
#pragma mark - 屬性的實現
/* 相當於實現了 setter 和 getter 方法
 * 可以省略 @synthesize 一行
 */
@synthesize hobby = _hobby;
@synthesize sex = _sex;

- (void)setName:(NSString *)name
{
    _name = name;
}

- (NSString *)name
{
    return _name;
}

- (void)setAge:(NSInteger)age
{
    _age = age;
}

- (NSInteger)age
{
    return _age;
}
@end

main.m文件代碼如下:

#import 
#import Person.h
#import Classroom.h

int main(int argc, const char * argv[]) {
    @autoreleasepool {
     /* 定義一個Classroom類: 實例變量: 教室編號, 學生(Person類)
      * 實例變量不寫setter, getter方法
      */
        /* 創建一個Person對象, 一個Classroom對象 */
        Person *stu = [[Person alloc] init];

        Classroom *classroomOne = [[Classroom alloc] init];

        /* 使用KVC賦值 */
        [classroomOne setValue:@5211 forKey:@_classNum];
        [classroomOne setValue:stu forKey:@_student];

        [classroomOne setValue:@5212 forKey:@classroomNum];
        [classroomOne setValue:@dd forUndefinedKey:@sss];

        [classroomOne setValue:@ZhangSan forKeyPath:@_student.name];

        /* 使用KVC取值 */
        NSLog(@classNum: %@, [classroomOne valueForKey:@_classNum]);
        NSLog(@student name: %@, [classroomOne valueForKeyPath:@_student.name]);
        NSLog(@student name: %@, [classroomOne valueForKeyPath:@_student002]);

     }
    return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved