码迷,mamicode.com
首页 > 其他好文 > 详细

Objective-C中的内存管理——手动内存管理

时间:2015-11-28 10:33:17      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:

一、引用计数(retainCount)

1、内存的申请

allocnewObjective-C语言中申请内存的两种常用方式。

当我们向一个类对象发送一个alloc消息的时候,其会向操作系统在堆中申请一块内存用于存放该类的实例对象。然后将该实例对象的引用计数(retainCount)设置为1,最后返回该对象的指针。

allocnew的区别:一句话,[Person new][[Person alloc]new]

2、引用计数(retainCount)

Cocoa框架中,所有继承自NSObject的子类(包括NSObject)对象中都有一个4个字节的存储空间用于存储其retainCount的值。

我们可以通向对象发送retainCount消息来获取该对象的retainCount的值。

3retainrelease

当我们向一个实例对象发送一个retain消息的时候,其引用计数(retainCount)会执行+1操作。

当我们向一个实例对象发送给一个release消息的时候,其引用计数(retainCount)会执行-1操作。

4、内存的释放

OC中,当我们向一个对象发送release消息是,其先使得该对象的retainCount属性-1,然后在判断该对象的retainCount是否为0。如果为0则在release方法中释放该对象的内存。

 

    NSObject对象的retainrelease实现的猜想

    @implementation NSObject

    {

        Class isa  OBJC_ISA_AVAILABILITY;

        int retainCount;

    }

    -(instancetype)retain

    {

        self->retainCount++;

        return self;

    }

    -(void)release

    {

        self->retainCount--;

        if (self->retainCount==0) {

            [self dealloc];

            free(self);

        }

    }

    @end

 

Tip:如果在一个局部作用域中申请了一块内存,但是当该作用域结束时,系统不会自动调用该对象的release方法。

示例:

int main(int argc, const char * argv[]) {

    

    Person* kaka;

    if (YES) {

        kaka = [Person alloc];

        NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

        NSLog(@"end");

    }

    NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

    return 0;

}

代码执行结果:

    2015-11-23 13:31:13.447 Test[4576:53048] 调用了allc

    2015-11-23 13:31:13.448 Test[4576:53048] kaka   retainCount = 1

    2015-11-23 13:31:13.448 Test[4576:53048] end

    2015-11-23 13:31:13.449 Test[4576:53048] kaka retainCount = 1

    Program ended with exit code: 0

    可以看出,该系统并不会自动向该对象发送release消息。

    

 

注意:当一个对象已经被释放之后,再次对该对象发送release消息,会造成运行时异常。因为该指针指向的内存地址已经不存在了。

    错误代码

      Person* kaka;

    kaka = [Person alloc];

    NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

    [kaka release];

    NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

    因此,当一个对象的已经被释放之后,我们应该将该指针赋值为nil

    问题:当一个对象被释放之后,我们不能向其发送retainCount消息,如何判断其已经被释放呢?

            解决方案:在发送release消息之前,先发送retainCount消息,判断其retainCount是否为1.如果是不是1则直接发送release消息,否则发送release消息,再将该指针置为nil

     示例:

        Person* kaka;

        kaka = [Person alloc];

        NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

        [kaka retain];

        NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

        if ([kaka retainCount]==1) {

            [kaka release];

            kaka = nil;

        }else{

            [kaka release];

        }

        NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

        if ([kaka retainCount]==1) {

            [kaka release];

            kaka = nil;

        }else{

            [kaka release];

        }

        NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

        代码执行结果:

        2015-11-23 13:54:23.405 Test[5913:65897] 调用了allc

        2015-11-23 13:54:23.406 Test[5913:65897] kaka retainCount = 1

        2015-11-23 13:54:23.406 Test[5913:65897] kaka retainCount = 2

        2015-11-23 13:54:23.406 Test[5913:65897] kaka retainCount = 1

        2015-11-23 13:54:23.406 Test[5913:65897] -[Person dealloc]

        2015-11-23 13:54:23.406 Test[5913:65897] kaka retainCount = 0

        可以看出,通过这种方式可以避免对象被释放后,指针没有及时地置为nil

二、NSAutoreleasePool

1NSAutoreleasePool的接口

    @interface NSAutoreleasePool : NSObject {

 

    @private

        void    *_token;

        void    *_reserved3;

        void    *_reserved2;

        void    *_reserved;

    }

 

    + (void)addObject:(id)anObject;

 

    - (void)addObject:(id)anObject;

 

    - (void)drain;

 

    @end

2NSAutoreleasePool对象介绍

NSAutoreleasePool的接口我们可以知道,我们能够向NSAutoreleasePool对象发送的消息只有两个,即addObjectdrain

因此,我们可以从其方法addObject进行猜测,NSAutoreleasePool对象内部有一个属性NSArray* _objects,用于存放其它任意对象,而其方法addObject就是将其参数添加到其_objects属性中。

APPLE官方文档对NSAutoreleasePooldrain的介绍

    "In a reference-counted environment, this method behaves the same as release. Since an autorelease pool cannot be retained (see retain), this therefore causes the receiver to be deallocated. When an autorelease pool is deallocated, it sends a release message to all its autoreleased objects. If an object is added several times to the same pool, when the pool is deallocated it receives a release message for each time it was added."

我们可以发现,这个方法的作用就是对其遍历其_objects属性,依次向对象发送release消息。

 

最后我们可以大胆的猜测NSAutoreleasePool类的基本实现如下:

 

@implementation NSAutoreleasePool

{

    NSMutableArray* _objects;

}

 

-(instancetype)init

{

    self = [super init];

    self->_objects = [NSMutableArray new];

    return self;

}

-(void)addObject:(id)anObject

{

    [self->_objects addObject:anObject];

}

-(void)drain

{

    for (int index = [self->_objects count]; index>0; index--) {

        [[self->_objects objectAtIndex:(index-1)] release];

    }

}

-(void)dealloc

{

    [self drain];

}

@end

3、验证我们的猜测

验证代码:

 

    int main(int argc, const char * argv[]) {

 

        NSAutoreleasePool *autoReleasePool = [NSAutoreleasePool new];

        Person* kaka = [[Person alloc] initWithName:@"kaka"];

        Person* maomao = [[Person alloc] initWithName:@"maomao"];

        [autoReleasePool addObject:kaka];

        [autoReleasePool addObject:maomao];

        NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

        NSLog(@"maomao retainCount = %ld",[maomao retainCount]);

        [autoReleasePool drain];

        return 0;

    }

 

    代码执行结果:

    2015-11-23 15:01:07.518 Test[10150:105757] +[Person alloc]

    2015-11-23 15:01:07.519 Test[10150:105757] -[Person initWithName:] kaka

    2015-11-23 15:01:07.520 Test[10150:105757] +[Person alloc]

    2015-11-23 15:01:07.520 Test[10150:105757] -[Person initWithName:] maomao

    2015-11-23 15:01:07.520 Test[10150:105757] *** -[NSAutoreleasePool addObject:]: Do not use this instance method on specific pools -- just use -autorelease instead.

    2015-11-23 15:01:07.520 Test[10150:105757] kaka retainCount = 1

    2015-11-23 15:01:07.520 Test[10150:105757] maomao retainCount = 1

    2015-11-23 15:01:07.520 Test[10150:105757] -[Person release] maomao

    2015-11-23 15:01:07.520 Test[10150:105757] -[Person dealloc] maomao

    2015-11-23 15:01:07.520 Test[10150:105757] -[Person release] kaka

    2015-11-23 15:01:07.520 Test[10150:105757] -[Person dealloc] kaka

 

由验证代码的执行结果,我们可以发现我们的猜测是对的。而且在其addObject方法中,并没有对传入的对象进行retain(引用计数+1)。在其drain方法中,是按照栈的顺序来向对象发送release消息

4、向NSObject对象发送autorelease消息

我们先对autorelease方法的实现做一个猜想

 

    @implementation NSObject

 

    -(instancetype)autorelease

    {

        [NSAutoreleasePool addObject:self];

        return self;

    }

 

    @end

 

在我们的猜想中,autorelease方法是先NSAutoreleasePool类对象发送一个addObject消息(在前面NSAutoreleasePool的接口中我们可以发现,其提供了向NSAutoreleasePool类对象发送addObject消息的接口,而且我们可以猜测其作用也是将传入的对象添加到NSAutoreleasePool实例对象的_objects属性中),然后再返回self

 

验证:对比验证

 

    代码一:

 

        int main(int argc, const char * argv[]) {

 

            NSAutoreleasePool *autoReleasePool = [NSAutoreleasePool new];

            Person* kaka = [[Person alloc] initWithName:@"kaka"];

            Person* maomao = [[Person alloc] initWithName:@"maomao"];

            [kaka autorelease];

            [maomao autorelease];

            NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

            NSLog(@"maomao retainCount = %ld",[maomao retainCount]);

        //    [autoReleasePool drain];

            return 0;

        }

 

        代码一的执行结果:

        2015-11-23 15:16:57.852 Test[10999:113705] +[Person alloc]

        2015-11-23 15:16:57.853 Test[10999:113705] -[Person initWithName:] kaka

        2015-11-23 15:16:57.853 Test[10999:113705] +[Person alloc]

        2015-11-23 15:16:57.853 Test[10999:113705] -[Person initWithName:] maomao

        2015-11-23 15:16:57.853 Test[10999:113705] kaka retainCount = 1

        2015-11-23 15:16:57.853 Test[10999:113705] maomao retainCount = 1

        Program ended with exit code: 0

 

    代码二:

 

        int main(int argc, const char * argv[]) {

 

            NSAutoreleasePool *autoReleasePool = [NSAutoreleasePool new];

            Person* kaka = [[Person alloc] initWithName:@"kaka"];

            Person* maomao = [[Person alloc] initWithName:@"maomao"];

            [kaka autorelease];

            [maomao autorelease];

            NSLog(@"kaka retainCount = %ld",[kaka retainCount]);

            NSLog(@"maomao retainCount = %ld",[maomao retainCount]);

            [autoReleasePool drain];

            return 0;

        }

 

        代码二的执行结果:

        2015-11-23 15:19:39.184 Test[11155:115422] +[Person alloc]

        2015-11-23 15:19:39.185 Test[11155:115422] -[Person initWithName:] kaka

        2015-11-23 15:19:39.185 Test[11155:115422] +[Person alloc]

        2015-11-23 15:19:39.185 Test[11155:115422] -[Person initWithName:] maomao

        2015-11-23 15:19:39.185 Test[11155:115422] kaka retainCount = 1

        2015-11-23 15:19:39.185 Test[11155:115422] maomao retainCount = 1

        2015-11-23 15:19:39.186 Test[11155:115422] -[Person release] maomao

        2015-11-23 15:19:39.186 Test[11155:115422] -[Person dealloc] maomao

        2015-11-23 15:19:39.186 Test[11155:115422] -[Person release] kaka

        2015-11-23 15:19:39.186 Test[11155:115422] -[Person dealloc] kaka

 

    结论:[NSAutoreleasePool addObject:self];应该是将传入的参数添加到一个NSAutoreleasePool实例对象的_objects属性中(通过调用NSAutoreleasePool实例对象的addObject方法)。

 

    经过我反复的验证,我发现前面的关于NSAutoreleasePool实例对象drain的实现并不完全正确,最后我关于NSAutoreleasePool类的实现如下

 

    @implementation NSAutoreleasePool

        static NSMutableArray* objects;

        static NSMutableArray* autoReleaseRools;

 

        + (void)initialize

        {

            autoReleaseRools = [NSMutableArray new];

            objects = [NSMutableArray new];

        }

        -(instancetype)init

        {

            self = [super init];

            [autoReleaseRools addObject:self];

            return self;

        }

        -(void)addObject:(id)anObject

        {

            [objects addObject:anObject];

        }

        +(void)addObject:(id)anObject

        {

            [objects addObject:anObject];

        }

        -(void)drain

        {

            for (int index = [objects count]; index>0; index--) {

                [[objects objectAtIndex:(index-1)] release];

            }

        }

        -(void)dealloc

        {

            [self drain];

        }

    @end

5NSAutoreleasePool的作用

先前我们当我们需要释放一个一个对象时需要向该对象发送release消息,直到其引用计数为0

 

        int main(int argc, const char * argv[]) {

            Person* kaka = [[Person alloc] initWithName:@"kaka"];

            [kaka retain];

            [kaka retain];

            if ([kaka retainCount]==1) {

                [kaka release];

                kaka = nil;

            }else{

                [kaka release];

            }

            if ([kaka retainCount]==1) {

                [kaka release];

                kaka = nil;

            }else{

                [kaka release];

            }

            if ([kaka retainCount]==1) {

                [kaka release];

                kaka = nil;

            }else{

                [kaka release];

            }

 

            return 0;

        }

 

    现在我们可以向该对象发送一个autorelease消息(建议在创建一个对象的时候就发送autorelease消息,且应该只发送给一次,多次发送可能会造成程序异常。),将该对象添加到NSAutoreleasePool中。最后我们我们当我们只需要在NSAutoreleasePool对象被释放前,所有对象的retainCount<=1即可

    int main(int argc, const char * argv[]) {

        NSAutoreleasePool* autoReleasePool = [NSAutoreleasePool new];

        Person* kaka = [[[Person alloc] initWithName:@"kaka"] autorelease];

        [kaka retain];

        [kaka retain];

        [kaka release];

        [kaka release];

         NSLog(@"autoReleasePool将被释放");

        [autoReleasePool release];

        return 0;

    }

三、NSCopying协议和NSMutableCopying协议

1NSObject对象的copymutableCopy

NSObject类的接口我们可以发现,我们可以向NSObject对象发送copymutableCopy消息

    - (id)copy;

    - (id)mutableCopy;

Apple官方文档对这两个方法的注释如下

    -(id)copy

 

        Return Value

        The object returned by the NSCopying protocol method copyWithZone:.

 

        Discussion

        This is a convenience method for classes that adopt the NSCopying protocol. An exception is raised if there is no implementation for copyWithZone:.

 

        NSObject does not itself support the NSCopying protocol. Subclasses must support the protocol and implement the copyWithZone: method. A subclass version of the copyWithZone: method should send the message to super first, to incorporate its implementation, unless the subclass descends directly from NSObject.

 

-(id)mutableCopy

 

        Return Value

        The object returned by the NSMutableCopying protocol method mutableCopyWithZone:.

 

        Discussion

        This is a convenience method for classes that adopt the NSMutableCopying protocol. An exception is raised if there is no implementation for mutableCopyWithZone:.

 

因此我们可以发现,NSObject对象的copymutableCopy方法就是分别向其自身发送copyWithZonemutableCopy消息。但是NSObject对象本身并没有实现copyWithZonemutableCopy方法。因此,当我们向一个对象发送copymutableCopy的消息时,需要确保该对象实现了copyWithZonemutableCopyWithZone方法。

 

 

根据Apple官方文档中对NSMutableCopying协议的介绍

    The NSMutableCopying protocol declares a method for providing mutable copies of an object. Only classes that define an “immutable vs. mutable” distinction should adopt this protocol. Classes that don’t define such a distinction should adopt NSCopying instead.

我们可以发现,对于那些定义了可变不可变的类才应该都实现NSMutableCopying协和和NSCopying协议。如果,不存在可变不可变的类只需要实现NSCopying协议即可。

 

总之copyWithZonemutableCopyWithZone都是实例化一个新对象,该新对象的所有属性和当前对象的所有属性完全相同。但是copyWithZone返回的事"Immutable",而mutableCopyWithZone返回的是“mutable”

2、实现NSCopying协议

现在我们来实现一个Book类,并为其实现一下NSCopying协议

    @implementation Book:NSObject

    {

        NSString* _bookName;

        NSString* _bookAuthor;

    }

    -(id)copyWithZone:(NSZone*)zone

    {

        Book* newBook = [Book allocWithZone:zone];

        newBook->_bookAuthor = self->_bookAuthor;

        newBook->_bookName = self->_bookName;

        return newBook;

    }

    @end

3Foundation框架中的IMMutable

Foundation框架中定义了一些集合类,为了尽可能地减少内存开销,这些集合类分为MMutableMutable

    IMMutable:NSStringNSArrayNSSetNSDictionary

    Mutable:NSMutableStringNSMutableArrayNSMutableSetNSMutableDictionary

1]其中IMMutable集合对象一旦被创建,则不可以对其成员进行增删操作,而Mutable集合对象则可以对其成员进行增删操作

2IMMutable集合对象和Mutable集合对象最大的区别在于IMMutable集合对象copyWithZone方法的实现并未依照NSCopying协议的约定,而是先对其自身发送retain消息,然后返回自身对象的指针。

        NSArray对象的copyWithZone实现为例:

 

                        @implementation NSArray

 

                        -(id)mutableCopy

                        {

                            [self retain];

                            return self;

                        }

 

                        @end

        验证:

 

            NSDictionary* dict = @{@"one":@1,@"two":@"2"};

            NSLog(@"dict retainCount:%ld",[dict retainCount]);

            NSDictionary* dict2 = [dict copy];

            NSMutableArray* dict3 = [dict mutableCopy];

            NSLog(@"dict retainCount:%ld",[dict retainCount]);

            if (dict==dict2) {

                NSLog(@"dict==dict2");

            }

            if (dict3!=dict) {

 

                NSLog(@"dict3!=dict");

            }

 

            NSMutableDictionary* mutableDict = [NSMutableDictionary dictionaryWithDictionary:dict];

            NSLog(@"mutableDict:retainCount %ld",[mutableDict retainCount]);

            NSDictionary* mutableDict2 = [mutableDict copy];

            NSLog(@"mutableDict:retainCount %ld",[mutableDict retainCount]);

            if (mutableDict==mutableDict2) {

                NSLog(@"mutableDict==mutableDict2");

            }else{

                NSLog(@"mutableDict!=mutableDict2");

            }

 

            代码执行结果:

            2015-11-23 17:52:04.148 Test[20157:198839] dict retainCount:1

            2015-11-23 17:52:04.150 Test[20157:198839] dict retainCount:2

            2015-11-23 17:52:04.150 Test[20157:198839] dict==dict2

            2015-11-23 17:52:04.150 Test[20157:198839] dict3!=dict

            2015-11-23 17:52:04.151 Test[20157:198839] mutableDict:retainCount 1

            2015-11-23 17:52:04.151 Test[20157:198839] mutableDict:retainCount 1

            2015-11-23 17:52:04.152 Test[20157:198839] mutableDict!=mutableDict2

            Program ended with exit code: 0

 

        因此当我们向Foudation框架中的不可变集合类型发送copy消息时,其返回的是原对象的指针,且该对向的retainCount进行了+1操作

 

[3]NSFoundatioin框架还对NSString对象进行了进一步优化。

        当我们创建一个NSString对象时,其retainCount-1

            示例代码:

 

                    NSString* str = [NSString stringWithString:@"Hello World"];

                    [str retain];

                    NSLog(@"str retainCount:%ld",[str retainCount]);

                    NSMutableString* mutableStr = [NSMutableString stringWithString:@"Hello World"];

                    NSLog(@"mutableStr retainCount:%ld",[mutableStr retainCount]);

                    NSLog(@"执行copy");

                    NSString* str2 = [str copy];

                    NSLog(@"str retainCount:%ld",[str retainCount]);

                    if (str2==str) {

                        NSLog(@"str2==str1");

                    }

                    NSString* mutableStr2 = [mutableStr copy];

                    NSLog(@"mutableStr retainCount:%ld",[mutableStr retainCount]);

                    if (mutableStr2==mutableStr) {

                        NSLog(@"mutableStr2==mutableStr");

                    }else{

                        NSLog(@"mutableStr2!=mutableStr1");

                    }

                    代码执行结果:

                    2015-11-23 17:55:16.578 Test[20327:200783] str retainCount:-1

                    2015-11-23 17:55:16.579 Test[20327:200783] mutableStr retainCount:1

                    2015-11-23 17:55:16.579 Test[20327:200783] 执行copy

                    2015-11-23 17:55:16.579 Test[20327:200783] str retainCount:-1

                    2015-11-23 17:55:16.579 Test[20327:200783] str2==str1

                    2015-11-23 17:55:16.579 Test[20327:200783] mutableStr retainCount:1

                    2015-11-23 17:55:16.579 Test[20327:200783] mutableStr2!=mutableStr1

                    Program ended with exit code: 0

 

        由上面的代码我们可以发现,当我们向一个NSString对象发送copy消息时,其retainCount不变,且返回的指针就是当前对象的指针。因此,我们可以猜测NSStringcopyWithZone方法实现如下:

 

                    @implementation NSString

 

                    -(id)copyWithZone:(NSZone *)zone

                    {

                        return self;

                    }

 

                    @end

四、属性特性

1、数据隐藏

    Matt Weisfeld大师在其写的《The Object-Oriented Thought Proccess(中文版为《写给大家看的面向对象编程书》)谈到,创建对象的其中一个作用就是实现数据隐藏,数据隐藏包括限制对属性和方法的访问,并且所有的属性都应该隐藏。因此在类的接口中,将属性声明为public会破坏数据隐藏的概念。

    如果对象的某个属性需要和外界进行交互,可以通过在类的接口中提供该属性的获取方法和设置方法。在面向对象编程的术语中,获取方法和设置方法就是该属性的property(特性)

        注意:获取方法和设置方法的概念支持数据隐藏的概念。因为其他对象不能直接处理另一个对象内部的数据,所以获取方法和设置方法提供了对对象的数据的一种受控访问。获取方法和设置方法有时分别称为访问方法(accessor method)和修改方法(mutator method)

2、为属性添加property

    下面我们将定一个Server类,并为其某些属性添加property

 

            @interface Server : NSObject

            -(NSString*)ipAdderss;

            -(void)postWithData:(NSData*)data;

            @end

 

            @implementation Server

            {

                NSString* _hostName;

                NSString* _ipAddress;

            }

            -(NSString*)ipAddress

            {

                return self->_ipAddress;

            }

 

            -(void)postWithData:(NSData*)data

            {

                [self handlePostRequest];

            }

            -(void)handlePostRequest

            {

 

            }

    在这个Server类的接口中,我们提供了关于Server对象内部的_ipAddress属性的访问方法ipAddress.这个ipAddress方法成为_ipAddress属性的property

3、访问方法和设置方法在OC中的正确使用

    下面我们将分别定义两个类:PersonHouse

 

    @interface Person : NSObject

    -(instancetype)initWithName:(NSString*)name;

    -(NSString*)name;

    @end

 

    @implementation Person

    {

        NSString* _name;

    }

    -(NSString*)description

    {

        return [NSString stringWithFormat:@"Hello I‘m %@",self->_name];

    }

    -(instancetype)initWithName:(NSString *)name

    {

        self = [super init];

        [name retain];

        self->_name = name;

        return self;

    }

 

    -(NSString*)name

    {

        return self->_name;

    }

 

    @end

 

    @class Person;

    @interface House : NSObject

    -(Person*)owner;

    -(void)setOwner:(Person*)owner;

    @end

 

    @implementation House

    {

        Person* _owner;

    }

    -(instancetype)initWithOwner:(Person*)owner

    {

        self = [super init];

        Owner retain;

        self->_owner = owner;

        return self;

    }

    -(Person*)owner

    {

        return self->_owner;

    }

    -(void)setOwner:(Person*)owner

    {

        //使原对象的retainCount-1

        [self->_owner release];

        //使新对象的retainCount+1

        [owner retain];

        //赋值

        self->_owner = owner;

 

    }

    @end

 

    我们在定义HousePerson的时候,为对象的属性进行赋值时,一般会对属性指向的就对象发送release,然后对新对象进行retain,再将该属性指向新对象。

4Objective-C2.0新的关键字@property

Objective-C2.0,可以使用@property关键字快速生成属性的获取方法和设置方法。

1@property的参数

        我们在使用@property关键字的时候,还可以指定参数,使得编译器根据指定的参数生成获取方法和设置方法

 

        是否生成设置方法readwritereadonly

            使用readwrite作为参数时,则会同时生成访问方法和设置方法。

            使用readonly作为参数时,则不会生成设置方法,只会生成访问方法

 

        设置方法和访问访问的方法名setter=getter=

            可以在settergetter后面指定生成的设置方法名和访问方法名。如果不指定则getter方法名默认为属性名,setter方法名默认为set属性名。

 

        获取方法的参数atomicnonatomic

            使用atomic作为参数时,则多个线程不可以同时访问@property关联的属性,但是会影响CPU的性能。

            使用nonatomic作为参数时,则多个线程可以同时访问@property关联的属性。因为在iOS平台和Mac OSX平台中,属性默认是atomic。但是在iOS开发中,我们推荐使用nonatomic

 

        设置方法的参数retaincopyassign

            使用retain作为参数时,则会对原属性指向的对象发送release消息,然后在向新对象发送retain消息,最后再将属性指向新对象。

                其生成的代码相当于:

                        -(void)setOwner:(Person*)owner

                        {

                            //使原对象的retainCount-1

                            [self->_owner release];

                            //使新对象的retainCount+1

                            [owner retain];

                            //赋值

                            self->_owner = owner;

 

                        }

            使用copy作为参数时,则会向原属性指向的对象发送release消息,然后再向新对象发送copy消息,最后再将属性指向新对象。

                其生成的代码相当于:

                   -(void)setOwner:(Person*)owner

                    {

                        //使原对象的retainCount-1

                        [self->_owner release];

                        //使新对象的retainCount+1

                        [owner copy];

                        //赋值

                        self->_owner = owner;

 

                    }因此通常我们在使用copy作为参数时需要确定该参数的类型是否实现了NSCopying协议。

 

            使用assign作为参数,则会直接将原属性指向新对象或者基本数据类型。

                其生成的代码相当于

 

                -(void)setOwner:(Person*)owner

                {

                    self->_owner = owner;

                }

 

2@property的作用

            根据参数在类的接口中生成指定的获取方法和设置方法的声明,在接口中生成属性的声明(访问控制为private)。在类的实现中生成获取方法和设置方法的实现

            提供点语法机制:在OCslef指针的本质上就是一个结构体指针,因此访问其内部的成员变量只能通过“self->成员变量名的形式进行访问。而使用了@property之后,可以通过self.property的形式进行访问,编译器会自动将其替换为对相关方法的调用。

                    示例:

                    self.owner = owner;

                    相当于

                    [self setOwner:owner];

 

                    owner = self.owner

                    相当于

                    owner = [self owner];               

5@synthesize@dynamic

    @synthesize关键字会根据其后面指定的参数,在类的实现中声明指定的属性。一般不使用,因为在Xcode4Apple LLVM compiler 4.0新编译器中会自动为属性添加@synthesize

        示例:

                @synthesize owner = _owner

                编译器会根据将接口中@property (nonatomic,retain)Person* owner,在类的实现中声明Person* _owner;然后,将生成的获取方法和设置方法关联到_owner属性。

 

    @dynamic关键字,表示该@propertysetter方法和getter方法有其他方式生成,比如super类,比如程序员自己定义。

写在后面

@property关键字为我们开发人员带来了不少便利,但我觉得@property带来的点语法机制不但破坏了Objective-C的设计哲学,还容易误导初学者。

Objective-C中的内存管理——手动内存管理

标签:

原文地址:http://www.cnblogs.com/kakawater/p/5002194.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!