ObjC第二节:属性声明、类的组合

属性声明、类的组合

1、属性声明

     1.1 声明属性让编译器自动合成setter和getter方法,使用关键字@property和@synthesize

     1.2 在头文件中,@property int count; 等价于- (int) count;  -(void)setCount:(int)newCount;

           在实现文件中,@synthesize count; 等价于 - (int) count{ return count; }  - (void) setCount:(int)newCount { count = newCount; } 

     1.3 @property 可以将同类型的实例变量写在一行,不同类型需分开写;@synthesize 则无论类型

     1.4 @property (参数) 类型 名字;

2、参数

     2.1 三类参数:读写属性(readwrite,readonly) setter语意(assign,retain, copy) 原子性(atomic, nonatomic)

     2.2 readwrite 产生setter、getter方法(默认)

readonly 只产生getter方法,没有setter方法

assign 直接赋值,适用于基本数据类型(默认)

retain 旧空间释放再进行retain操作,适用于OC对象

copy 旧空间释放再进行copy操作,适用于NSString等不可变对象(?)

nonatomic 禁止多线程,提高性能

atomic 提供多线程安全,防止在写未完成的时候被另一个线程读取,造成数据错误。如果使用多线程,有时会出现两个线程相互等待对方导致死锁,使用atomic防止出现此情况,但会消耗一定资源。(加锁,解锁)(默认)

     2.3 

<span style="font-size:12px;">//assign
get
- (Toy *) toy;
- (Toy *) toy
{
    return toy;
}
set
- (void) setToy:(Toy *)_toy;
- (void) setToy:(Toy *)_toy
{
    toy = _toy;
}
//retain
get
- (Toy *) toy;
- (Toy *) toy
{
    return toy;
}
set
- (void) setToy:(Toy *)_toy;
- (void) setToy:(Toy *)_toy
{
    if (toy != _toy)  //避免自赋值
    {
        [toy release];  //旧空间释放,引用计数器-1
        toy = [_toy retain];  //引用计数器+1,最终指向同一内存空间
    }
}
//copy
get
- (Toy *) toy;
- (Toy *) toy
{
    return toy;
}
set
- (void) setToy:(Toy *)_toy;
- (void) setToy:(Toy *)_toy
{
    if (toy != _toy)
    {
        [toy release];
        toy = [_toy retain];  //复制该内存存储的内容,赋给一个新建的对象,最终指向不同的内存空间,但内容相同
    }
}</span>
3、类的组合

     3.1 @class 。。。;  前向声明,提高程序运行效率,需要在.m中再用import导入

     3.2 Has-A为组合关系,Is-A是继承关系

A、属性声明

Toy.h

#import <Foundation/Foundation.h>

@interface Toy : NSObject

@property (nonatomic) int num;
@property (nonatomic, retain) NSString * color;
//- (int) num;
//- (NSString *) color;
//- (void) setNum:(int)_num andColor:(NSString *)_color;
- (void) print;
@end
Toy.m

#import "Toy.h"

@implementation Toy

@synthesize num, color;
//- (int) num
//{
//    return num;
//}
//- (NSString *) color
//{
//    return color;
//}
//- (void) setNum:(int)_num andColor:(NSString *)_color
//{
//    num = _num;
//    color = _color;
//}
- (void) print
{
    NSLog(@"num: %d, color: %@", num, color);
}
@end
Baby.h

#import <Foundation/Foundation.h>
#import "Toy.h"
@interface Baby : NSObject

@property (nonatomic, retain) Toy * toy;
@property (nonatomic, retain) NSString * name;
@property (nonatomic) int age;
//- (Toy *) toy;
//- (NSString *) name;
//- (int) age;
//- (void) setToy:(Toy *)_toy;
//- (void) setName:(NSString *)_name andAge:(int)_age;
- (void) print;  //不声明只实现,就是私有方法,只能在.m中使用
//- (void) dealloc;  //系统自动调用,就算不声明只实现,也可以正常使用
@end
assign
//get
//- (Toy *) toy;
//- (Toy *) toy
//{
//    return toy;
//}
//set
//- (void) setToy:(Toy *)_toy;
//- (void) setToy:(Toy *)_toy
//{
//    toy = _toy;
//}
retain
//get
//- (Toy *) toy;
//- (Toy *) toy
//{
//    return toy;
//}
//set
//- (void) setToy:(Toy *)_toy;
//- (void) setToy:(Toy *)_toy
//{
//    if (toy != _toy)
//    {
//        [toy release];
//        toy = [_toy retain];
//    }
//}
copy
//get
//- (Toy *) toy;
//- (Toy *) toy
//{
//    return toy;
//}
//set
//- (void) setToy:(Toy *)_toy;
//- (void) setToy:(Toy *)_toy
//{
//    if (toy != _toy)
//    {
//        [toy release];
//        toy = [_toy retain];
//    }
//}
Baby.m

#import "Baby.h"

@implementation Baby

@synthesize name, age, toy;
//- (Toy *) toy
//{
//    return toy;
//}
//- (NSString *) name
//{
//    return name;
//}
//- (int) age
//{
//    return age;
//}
//- (void) setToy:(Toy *)_toy
//{
//    if (toy != _toy)
//    {
//        [toy release];
//        toy = [_toy retain];
//    }
//}
//- (void) setName:(NSString *)_name andAge:(int)_age
//{
//    name = _name;
//    age = _age;
//}
- (void) print
{
    NSLog(@"name: %@, age: %d", name, age);
    [toy print];
}
- (void) dealloc
{
    [toy release];
    [super dealloc];
}
@end

main.m

#import <Foundation/Foundation.h>
#import "Baby.h"
int main()
{
    @autoreleasepool
    {
        Baby * b = [[Baby alloc] init];  //初始化的Baby含有指针toy,但为nil,因为没有新建Toy对象并赋值
        b.name = @"AAA";
        b.age = 5;
        b.toy.color = @"紫";
        b.toy.num = 5;
        [b print];
        NSLog(@"num: %d, color: %@", b.toy.num, b.toy.color);
        
        
        Toy * t1 = [[Toy alloc] init];
        t1.num = 10;
        t1.color = @"红";
        [t1 print];
        
        Toy * t2 = [[Toy alloc] init];
        t2.num = 20;
        t2.color = @"绿";
        [t2 print];
        
        b.toy = t1;
        [b print];
        b.toy = t2;
        [b print];
        b.toy.color = @"紫";
        b.toy.num = 5;
        NSLog(@"num: %d, color: %@", b.toy.num, b.toy.color);
        
        [b release];
        [t1 release];
        [t2 release];
    }
}

B、组合

XYPoint.h

#import <Foundation/Foundation.h>
@class Circle;
@interface XYPoint : NSObject
{
    int x;
    int y;
}
@property int x, y;
- (void) setX:(int)xVal andY:(int)yVal;
@end
XYPoint.m

#import "XYPoint.h"

@implementation XYPoint
@synthesize x, y;
- (void) setX:(int)xVal andY:(int)yVal
{
    x = xVal;
    y = yVal;
}
@end
Circle.h

#import <Foundation/Foundation.h>
//#import "XYPoint.h"
@class XYPoint;
@interface Circle : NSObject
{
    int radius;
    XYPoint * origin;
}
@property int radius;
- (XYPoint *) origin;
- (void) setOrigin : (XYPoint *)pt;
- (int) area;
- (int) perimeter;
@end
//objective-c中,当一个类使用到另一个类时,并且在类的头文件中需要创建被引用的指针时,如下面代码:
//A.h文件
//#import "B.h"
//@interface A : NSObject {
//    B *b;
//}
//@end
//为了简单起见:A类是引用类,B类是被引用类,这里先不考虑A类的实现文件。
//通常引用一个类有两种办法:一种是通过#import方式引入;另一种是通过@class引入;
//这两种的方式的区别在于:
//1、#import方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在A.h文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息;
//2、使用@class方式由于只需要被引用类(B类)的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以需要使用#importl来包含被引用类的头文件;
//3、通过上面2点也很容易知道在编译效率上,如果有上百个头文件都#import了同一 个文件,或者这些文件依次被#improt(A->B, B->C,C->D…),一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一遍,这样的效率也是可想而知的,而相对来讲,使用@class方式就不会出现这种问题了;
//4、对于循环依赖关系来说,比方A类引用B类,同时B类也引用A类,B类的代码:
//#import "A.h"
//@interface B : NSObject {
//    A *a;
//}
//@end
//当程序运行时,编译会报错,
//当使用@class在两个类相互声明,就不会出现编译报错。
//由上可知,@class是放在interface中的,只是在引用一个类,将这个被引用类作为一个类型,在实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用#import方式引入被引用类。
Circlr.m

#import "Circle.h"
#import "XYPoint.h"
@implementation Circle
@synthesize radius;
- (XYPoint *) origin
{
    return origin;
}
- (void) setOrigin : (XYPoint *)pt
{
    origin = pt;
}
- (int) area
{
    return 3.14 * radius * radius;
}
- (int) perimeter
{
    return 2 * 3.14 * radius;
}
@end
main.m

#import <Foundation/Foundation.h>
#import "Circle.h"
#import "XYPoint.h"  //如果不包含会报错,XYPoint是外部定义的类
int main()
{
    @autoreleasepool
    {
        XYPoint * p = [[XYPoint alloc] init];
        p.x = 2;
        p.y = 2;
        Circle * c = [[Circle alloc] init];
        c.radius = 2;
        NSLog(@"%d",c.radius);
        c.origin = p;
        NSLog(@"%@",c.origin);
        NSLog(@"%d, %d",c.origin.x, c.origin.y);
        NSLog(@"%d, %d",[[c origin] x], [[c origin] y]);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值