OC处理对象

Posted Billy Miracle

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OC处理对象相关的知识,希望对你有一定的参考价值。

打印对象和description方法

NSLog()函数不仅可以用于输出基本类型的值,也可用于输出OC对象,当使用NSLog()函数输出OC对象时,输出的是该对象的description方法的返回值。也就是说,下面两行代码完全一样:

NSLog(@"%@", p);
NSLog(@"%@", [p description]);

description方法是NSObject类的一个实例方法,所有的OC类都是NSObject类的子类,因此,所有的OC对象都有description方法。
description方法是一个特殊的方法,它是一个“自我描述”方法,该方法通常用于实现这样一个功能:当程序员直接打印该对象时,系统会输出该对象的“自我描述”信息,用以告诉外界该对象具有的状态信息。
NSObject类提供的description方法总是返回<FKPerson: 十六进制的首地址>,这个返回值并不能真正实现“自我描述”功能,因此,用户可以重写NSObject类的description方法。
很多时候,重写description方法可以返回该对象所有令人感兴趣的信息所组成的字符串,格式通常如下:

<类名 [实例变量1 =1,实例变量2 =2,...]>

示例:

//  FKApple.h

#import <Foundation/Foundation.h>

@interface FKApple : NSObject
@property (nonatomic , copy) NSString* color;
@property (nonatomic , assign) double weight;
-(id) initWithColor: (NSString*) color weight: (double) weight;
-(NSString*) description2;
@end
//  FKApple.m

#import "FKApple.h"

@implementation FKApple
-(id) initWithColor:(NSString *)color weight:(double)weight {
    if(self = [super init]) {
        self.color = color;
        self.weight = weight;
    }
    return self;
}
//重写父类的description方法
-(NSString*) description {
    //返回一个字符串
    return [NSString stringWithFormat:@"<FKApple[_color=%@,_weight=%g]>",self.color,self.weight];
}
//演示父类的description方法
-(NSString*) description2 {
    return [super description];
}
@end
//  main.m

#import "FKApple.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKApple* a = [[FKApple alloc] initWithColor: @"red" weight: 8.6];
        NSLog(@"%@", a);
        NSLog(@"%@", [a description]);
        NSLog(@"%@", [a description2]);
    }
    return 0;
}

输出结果:

<FKApple[_color=red,_weight=8.6]>
<FKApple[_color=red,_weight=8.6]>
<FKApple: 0x100709ba0>

从上面输出结果可以看出,通过重写FKapple类的description方法,就可以让系统在打印FKapple对象时打印出该对象的“自我描述”信息。

==和isEqual: 方法

OC程序中测试两个变量是否相等有两种方式:一种是利用 == 运算符,另一种是利用 isEqual: 方法。
当使用 == 来判断两个变量是否相等时,如果两个变量是基本类型的变量,且都是数值型,则只要两个变量的值相等,使用 == 判断就将返回真。对于两个指针型变量,它们必须指向同一个对象(两个指针变量保存的地址相同)时,使用 == 判断才会返回真。
示范:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int it = 65;
        float f1 = 60.0f;
        char ch = 'A';
        
        NSLog(@"65和65.0f是否相等:%d", (it == f1));
        NSLog(@"65和‘A'是否相等:%d", (it == ch));
        
        NSString* str1 = [NSString stringWithFormat:@"我是一个菜鸡"];
        NSString* str2 = [NSString stringWithFormat:@"我是一个菜鸡"];
        
        NSLog(@"str1和str2二者地址:%p   %p",str1,str2);
        NSLog(@"str1 == str2 结果:%d",(str1 == str2));
        NSLog(@"str1 isEqual:str2 结果:%d",[str1 isEqual: str2]);
    }
    return 0;
}

结果:

6565.0f是否相等:0
65和‘A'是否相等:1
str1和str2二者地址:0x10060e490   0x10060f310
str1 == str2 结果:0
str1 isEqual:str2 结果:1

常量池:

NSString* s1 = @"我是一个菜鸡";
NSString* s2 = @"我是一个菜鸡";
NSString* s3 = [NSString stringWithFormat:@"我是一个菜鸡"];

常量池保证相同的字符串直接量只有一个,不会产生多个副本,例子中的s1、s2都将指向常量池中的同一个字符串对象,因此,s1、s2保存的地址值完全相同。
使用NSString的stringWithFormat: 类方法创建的字符串对象是运行时创建出来的,它被保存在运行时内存区(即堆内存)内,不会放入常量池,所以s3指针变量中保存的地址与s1、s2指针变量中保存的地址并不相同。

重写isEqual: 方法

如果希望采用自定义的相等标准,则可以通过重写isEqual: 方法来实现。
NSString已经重写了NSObject的 isEqual: 方法:NSString的isEqual: 方法判断两个字符串相等的标准是:只要两个字符串所包含的字符序列相同,通过 isEqual: 比较就将返回真,否则返回假。
示例:

//  FKUser.h

#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
//  FKUser.m

#import "FKUser.h"

@implementation FKUser
-(id) initWithName:(NSString *)name idStr:(NSString *)idStr {
    if(self = [super init]) {
        self.name = name;
        self.idStr = idStr;
    }
    return self;
}
//重写isEqual:方法,提供自定义的相等标准
-(BOOL) isEqual:(id) other {
    //如果两个对象为同一个对象
    if (self == other) {
        return YES;
    }
    //当other不为nil,且它是FKUser类的实例时
    if(other != nil && [other isMemberOfClass: FKUser.class]) {
        FKUser* target = (FKUser*) other;
        //并且当前对象的idStr与target对象的idStr相等才可判断两个对象相等
        return [self.idStr isEqual: target.idStr];
    }
    return NO;
}
@end
//  main.m

#import "FKUser.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        FKUser* p1 = [[FKUser alloc] initWithName: @"Billy" idStr: @"12345123456"];
        FKUser* p2 = [[FKUser alloc] initWithName: @"Billie" idStr: @"12345123456"];
        FKUser* p3 = [[FKUser alloc] initWithName: @"Peter" idStr: @"12345678911234"];
        //p1和p2的idStr相等,输出1
        NSLog(@"p1和p2是否相等:%d", [p1 isEqual: p2]);
        //p2和p3的idStr不相等,输出0
        NSLog(@"p2和p3是否相等:%d", [p2 isEqual: p3]);
    }
    return 0;
}

通常而言,正确地重写isEqual: 方法应该满足下列条件:

  • 自反性:对任意x,[x isEqual: x]一定返回真。
  • 对称性:对任意x和y,如果[y isEqual: x]返回真,则[x isEqual: y]也返回真。
  • 传递性:对任意x、y、z,如果有[x isEqual: y]返回真,[y isEqual: z]返回真,则[x isEqual: z]一定返回真。
  • 一致性:对任意x和y,如果对象中用于比较的关系属性没有改变,那么无论调用[x isEqual: y]多少次,返回的结果都应该保持一致,要么一直是真,要么一直是假。
  • 对任何不是nil的x,[x isEqual: nil]一定返回假。

以上是关于OC处理对象的主要内容,如果未能解决你的问题,请参考以下文章

oc语言关闭指定程序

介绍 - OC中的代理模式

介绍 - OC中的代理模式

OC面向对象—封装

OC对象的本质

OC基础--OC内存管理原则和简单实例