【oc】–面向对象(下)
文章目录
oc的包装类
它们不是包装类
-
NSInterger: 大致相当于long型整数
-
NSUInterger: 大致相当于 unsigned long型整数
-
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方法要满足下面几个要求:
- 自反性:对任意x,[x isEqual: x]一定返回真
- 对称型:对任意x,y,如果[x isEqual:y]返回真,则[y isEqual:x]一定返回真
- 传递性:对任意x,y,z,如果有[x isEqual:y]返回真,[y isEqual:z]返回真,则[x isEqual:z]一定返回真
- 一致性:对任意x,y,如果对象中用于等价比较的关键信息没有改变,那么无论调用多少次[x isEqual:y],返回的结果应该保持一致,要么一直是真,要么一直是假
- 对任何不是nil的x,[x isEqual:nil]一定返回假
类别
类别
通过使用类别我们可以动态地为现有的类添加新方法,且将类定义模块化地分布到多个文件中
类别同样是接口和实现部分组成
接口部分的语法格式:
@interface 已有类(类别名)
//实现方法
...
@end
与类语法之间的差异:
- 定义类时使用类名必须时该类中不存在的类,而定义类别时使用的类名必须是已有的类
- 定义类别是必须用圆括号来包括类别名
- 类别中通常只定义方法
接口部分的语法格式:
@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
&spm=1001.2101.3001.5002&articleId=147874260&d=1&t=3&u=9335ed94efff43479c6586fde2be7207)
5998

被折叠的 条评论
为什么被折叠?



