【oc】--面向对象(下)

【oc】–面向对象(下)

oc的包装类

它们不是包装类

  1. NSInterger: 大致相当于long型整数

  2. NSUInterger: 大致相当于 unsigned long型整数

  3. CGFLoat:在64位平台上相当于double

NSValue 和NSNumber

这两者都是包装类。NSValue是NSNumber的一个父类,它可以用于包装单个short,int,long,float,char,指针,对象id等数据项,通过这些包装类,可以把它添加到NSArray,NSSet等集合中(元素必须都是对象)

NSNumber是更具体的包装类,主要用于包装C语言的各种数值类型,NSNumber主要包括如下三类方法

+numberWithXxx:这个类方法直接将特定类型的值包装成NSNumber。
-initWithXxx:这个实例方法先要创建一个NSNumber对象,再用一个基本类型值来初始化NSnumber
-xxxValue:这个实例方法返 回该NSNumber对象包装的基本类型的值。

xxx可以代表int,char等各种基本类型

示例:

#import <Foundation/Foundation.h>
#import "test.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSNumber* num = [NSNumber numberWithInt: 20];
        NSNumber* de = [NSNumber numberWithDouble: 3.4];
        NSLog(@"%d", [num intValue]);
        NSLog(@"%g", [de doubleValue]);
        NSNumber* ch = [[NSNumber alloc] initWithChar:'J'];
        NSLog(@"%d", [ch charValue]);
        NSLog(@"%@", ch);
    }
}

处理对象

==和isEqual:方法

测试两个变量是否相等有两种方式,一个是利用运算符,另一个是利用isEqual方法。 使用来判断两个变量是否相等时,如果两个变量时基本类型的变量,且都是数值型,则只要两个变量的值相等,==判断就返回真。

对于两个指针类型的变量,他们必须指向同一个对象,即保存的内存地址相同时,判断才会返回真。(使用比较类型上没有继承关系的两个指针变量时,编译器会提示警告)

重写isEqual方法

重写isEqual方法可以实现按自定义的相等标准,来判断比较对象是否相同 比如如下面代码所示,判断对象中的idStr成员变量是否相同,来判断该对象是否相同

下面提供一段代码示例:

#import <Foundation/Foundation.h>
#import "FKUser.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        FKUser* p1 = [[FKUser alloc] initWithName: @"孙悟空" idStr: @"123456"];
        FKUser* p2 = [[FKUser alloc] initWithName: @"孙行者" idStr: @"123456"];
        FKUser* p3 = [[FKUser alloc] initWithName: @"猪八戒" idStr: @"654321"];
        NSLog(@"p1和p2是否相等:%d", [p1 isEqual: p2]);
        NSLog(@"p1和p3是否相等: %d", [p1 isEqual: p3]);
    }
    return 0;
}
#import "FKUser.h"

@implementation FKUser
- (id) initWithName:(NSString *)name idStr:(NSString *)idStr
{
    if (self = [super init]) {
        self.name = name;
        self.idStr = idStr;
    }
    return self;
}
- (BOOL) isEqual:(id)other {
    if (self == other) {
        return YES;
    }
    if (other != nil && [other isMemberOfClass: FKUser.class]) {
        FKUser* target = (FKUser*) other;
        return [self.idStr isEqual: target.idStr];
    }
    return NO;
}
@end
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface FKUser : NSObject
@property (nonatomic, copy) NSString* name;
@property (nonatomic, copy) NSString* idStr;
- (id) initWithName: (NSString*)name idStr: (NSString*) idStr;
@end

NS_ASSUME_NONNULL_END

我们重写的isEqual方法要满足下面几个要求:

  1. 自反性:对任意x,[x isEqual: x]一定返回真
  2. 对称型:对任意x,y,如果[x isEqual:y]返回真,则[y isEqual:x]一定返回真
  3. 传递性:对任意x,y,z,如果有[x isEqual:y]返回真,[y isEqual:z]返回真,则[x isEqual:z]一定返回真
  4. 一致性:对任意x,y,如果对象中用于等价比较的关键信息没有改变,那么无论调用多少次[x isEqual:y],返回的结果应该保持一致,要么一直是真,要么一直是假
  5. 对任何不是nil的x,[x isEqual:nil]一定返回假

类别

类别

通过使用类别我们可以动态地为现有的类添加新方法,且将类定义模块化地分布到多个文件中

类别同样是接口和实现部分组成

接口部分的语法格式:

@interface 已有类(类别名)
//实现方法
...
@end

与类语法之间的差异:

  1. 定义类时使用类名必须时该类中不存在的类,而定义类别时使用的类名必须是已有的类
  2. 定义类别是必须用圆括号来包括类别名
  3. 类别中通常只定义方法

接口部分的语法格式:

@implementation 已有类(类别名)
//方法实现
...
@end

代码示例:

#import <Foundation/Foundation.h>
#import "NSNumber+fk.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        NSNumber* new = [NSNumber numberWithInt: 1];
        NSNumber* add = [new add: 2.4];
        NSLog(@"%@", add);
        NSNumber* substract = [new substract: 2.4];
        NSLog(@"%@", substract);
        NSNumber* multiply = [new multiply: 2.4];
        NSLog(@"%@", multiply);
        NSNumber* divide = [new divide: 2.4];
        NSLog(@"%@", divide);
    }
    return 0;
}
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSNumber (fk) 

- (NSNumber*) add: (double) num2;
- (NSNumber*) substract: (double) num2;
- (NSNumber*) multiply: (double) num2;
- (NSNumber*) divide: (double) num2;

@end

NS_ASSUME_NONNULL_END
#import "NSNumber+fk.h"

@implementation NSNumber (fk)

- (NSNumber*) add:(double)num2 {
    return [NSNumber numberWithDouble: ([self doubleValue] + num2)];
}
- (NSNumber*) substract:(double)num2 {
    return [NSNumber numberWithDouble: ([self doubleValue] - num2)];
}
- (NSNumber*) multiply:(double)num2 {
    return [NSNumber numberWithDouble: ([self doubleValue] * num2)];
}
- (NSNumber*) divide:(double)num2 {
    return [NSNumber numberWithDouble: ([self doubleValue] / num2)];
}
@end

虽然类别可以重写原有类中的方法,但通常不建议这么做,如果需要重写原有类的方法,更好的建议是通过原有类派生子类,然后在子类中重写父类原有的方法。

请添加图片描述

利用类别对类进行模块化设计

在前面类的设计中,可以使用.h 文件来定义类接口部分,使用.m 文件来定义类实现部分,但不能将类实现部分分布到多个 .m 文件中。当某个类非常大时,如果将该类的所有实现代码放在一个文件中,将会导致这个文件非常大,以至于维护起来非常困难 通过类别可以对类实现按模块分布到不同的.m文件中,从而提高项目后期的可维护性。

使用类别来调用私有方法

​ 在前面的学习中我们知道,在实现部分定义的方法相当于私有方法,通常不允许调用。但是实际上,OC没有真正的私有方法,使用NSObject的performSelector:方法来执行动态调用,就可以调用那些私有方法。

除了使用performSelector:方法来执行动态调用私有方法外,我们还可以通过类别来定义前向引用,从而实现私有方法的调用。

代码示例:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface FKItem : NSObject

@property (nonatomic, assign) double price;
- (void) info;

@end

NS_ASSUME_NONNULL_END
#import "FKItem.h"

@implementation FKItem

@synthesize price;

- (void) info
{
    NSLog(@"开始的info方法");
}
//额外新增的方法
- (double) calDiscount: (double) discount
{
    return self.price * discount;
}

@end
#import <Foundation/Foundation.h>
#import "FKItem.h"

//为FKItem定义一个类别
@interface FKItem (fk)
- (double) calDiscount: (double) discount;
@end
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKItem* item = [[FKItem alloc] init];
        item.price = 80;
        [item info];
        NSLog(@"物品打折后的价格为%g", [item calDiscount: 0.75]);
    }
    return
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值