Objective-c入门-对象实例变量及属性(9)

目录

一、对象所有权与ARC

二、创建BNRAsset类

三、为BNREmployee创建一对多关系

四、GitHub项目源码链接


对象实例变量的三种常见用途:

  1. 对象属性:指针,指向某个单一的、代表某个值的对象,如NSString对象,员工的姓
  2. 一对一关系:例如:员工可能会有配偶
  3. 一对多关系:例如:员工可能会有小孩,小孩可能有多个。

下面针对上述的用途为BNREmployee新增三个实例变量:

@interface BNREmployee : BNRPerson

@property (nonatomic) unsigned int employeeID;
@property (nonatomic) unsigned int officeAlarmCode;
@property (nonatomic) NSDate* hireDate;
@property (nonatomic) NSString* lastName;
@property (nonatomic) BNRPerson* spouse;
@property (nonatomic) NSMutableArray* children;

一、对象所有权与ARC

对象所有权:当某个对象(A)拥有某个对象实例变量(B)时,称为A拥有B指向的对象。

ARC:任何一个对象都知道自己当前有多少个拥有方。

下面扩充一下,创建一个BNRAsset类,为BNREmloyee对象新增一个数组来保存某个员工的物品对象。

二、创建BNRAsset类

@interface BNRAsset : NSObject
@property (nonatomic, copy) NSString* label;
@property (nonatomic) unsigned int resaleValue;
@end

当某个对象没有拥有方时,就会被释放掉。

有一个NSObject方法称为dealloc,如果类覆盖了dealloc,那么当类的实例被释放时,就会执行dealloc方法。

#import "BNRAsset.h"

@implementation BNRAsset
- (NSString*) description     //改变%@的显示内容
{
    return [NSString stringWithFormat:@"<%@: $%u>", self.label, self.resaleValue];
}
- (void) dealloc    //对象释放执行此方法
{
    NSLog(@"deallocating %@", self);
}
@end

三、为BNREmployee创建一对多关系

一对多关系是由collection对象(如数组)和其包含的对象组成的。

  • 当collection对象加入某个对象时,会保存指向该对象的指针,并成为该对象的拥有方。
  • 当collection对象移除某个对象时,会删除指向该对象的指针,并不再是该对象的拥有方。

现在为BNREmployee增加一对多的关系。

//BNREmployee.h文件内容:
#import "BNRPerson.h"
@class BNRAsset;  //告诉编译器程序有BNRAsset类,不要报错
NS_ASSUME_NONNULL_BEGIN

@interface BNREmployee : BNRPerson
{
    NSMutableArray* _assets;
}
@property (nonatomic) unsigned int employeeID;
@property (nonatomic) unsigned int officeAlarmCode;
@property (nonatomic) NSDate* hireDate;
@property (nonatomic, copy) NSArray* assets;
@property (nonatomic) NSString* lastName;
@property (nonatomic) BNRPerson* spouse;
@property (nonatomic) NSMutableArray* children;
- (double) yearsOfEmployment;
- (void) addAssets:(BNRAsset*) a;
- (unsigned int) valueOfAssets;
@end

NS_ASSUME_NONNULL_END

使用@class而不是#import时,编译器不会查看文件的全部内容,因此处理速度更快。

NSArray类型的含义是告诉其他类,如果询问我的assets,就会得到一些不可变的对象。

然而,assets数组实际上是NSMutableArray实例,所以我们可以在BNREmployee.m文件中增加和删除元素,这也就是为什么需要分别声明一个属性和一个实例变量。

创建这种collection对象的时机有两个:

1. 创建主体对象(BNREmployee对象)时

2. 需要使用相应的collection对象时,(这里我们选择后者,延迟创建机制)

#import "BNREmployee.h"
//编译器需要知道BNRAsset类的具体定义才能处理BNREmployee.m文件,所以治理需要导入BNRAsset.h,而不是使用@class
#import "BNRAsset.h"
@implementation BNREmployee
- (double) yearsOfEmployment
{
    //判断是否有一个非nil的hireDate
    if(self.hireDate) {
        NSDate* now = [NSDate date];
        //NSTimeInterval是double类型
        NSTimeInterval secs = [now timeIntervalSinceDate:self.hireDate];
        //根据秒数计算年数
        return secs / 31557600.0;  //除以每年的秒数
    } else {
        return 0;
    }
}
//覆盖了父类的方法
- (float) bodyMassIndex
{
    float normalBMI = [super bodyMassIndex];
    return normalBMI * 0.9;
}
//为了更好的跟踪BNREmployee实例的释放状况,覆盖descricption方法和dealloc方法
- (NSString*) description
{
    return [NSString stringWithFormat:@"<Emplyee %u : %u in assets>", self.employeeID, self.valueOfAssets];
}
- (void) dealloc
{
    NSLog(@"deallocating %@", self);
}
- (void) setAssets:(NSArray *)a
{
    _assets = [a mutableCopy];
}
- (NSArray *) assets
{
    return [_assets copy];
}
- (void) addAssets:(BNRAsset*) a
{
    //assets是否为nil?
    if(!_assets) {
        //如果为空,创建数组
        _assets = [[NSMutableArray alloc] init];
    }
    [_assets addObject:a];
}
- (unsigned int) valueOfAssets
{
    unsigned int sum = 0;
    for(BNRAsset* a in _assets) {
        sum += [a resaleValue];
    }
    return sum;
}
@end

编辑main.m文件:

#import <Foundation/Foundation.h>
#import "BNREmployee.h"
#import "BNRAsset.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //创建一个数组,用来包含多个BNREmployee对象
        NSMutableArray* employees = [[NSMutableArray alloc] init];
        for(int i = 0; i < 10; i++) {
            //创建BNREmployee的实例
            BNREmployee* mikey = [[BNREmployee alloc] init];
            mikey.heightInMeters = 1.8 - i / 10.0;
            mikey.weightInKilos = 90 + i;
            mikey.employeeID = i;
            //将创建的BNREmployee实例添加到数组中
            [employees addObject:mikey];
        }
        //创建10个BNRAsset对象
        for(int i = 0; i < 10; i++) {
            //创建一个BNRAsset对象
            BNRAsset* asset = [[BNRAsset alloc] init];
            //为实例变量赋值
            NSString* currentLabel = [NSString stringWithFormat:@"Laptop %d", i];
            asset.label = currentLabel;
            asset.resaleValue = 350 + i * 17;
            //生成0至9之间的随机整数(包含0和9)
            NSUInteger randomIndex = random() % [employees count]; //员工的个数10
            //取出相应的BNREmployee对象
            BNREmployee* randomEmployee = [employees objectAtIndex:randomIndex];
            //将BNRAsset对象付给该BNREmployee对象
            [randomEmployee addAssets:asset];
        }
        NSLog(@"Employees: %@", employees);
        NSLog(@"Giving up ownership of one employee");
        //删除索引为5的员工
        [employees removeObjectAtIndex:5];
        NSLog(@"Giving up ownership of arrays");
        //将存放员工的数组置为nil
        employees = nil;
    }
    return 0;
}

当程序将employee变量赋为nil时,其指向的数组不再有拥有方,因此会被释放。它的释放会引发一连串的内存释放动作,倒是所有的BNREmployee对象都不再有拥有方。

如果程序有用不到的但又没有释放的对象,就成程序有内存泄漏,内存泄漏会导致程序中不使用的对象越来越多,从而占用越来越多的内存。

四、GitHub项目源码链接

 Objective-c/.gitignore at main · hhhating/Objective-c · GitHub

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值