首页 > 解决方案 > 使用 NSPredicate 按 NSNumber 过滤自定义对象数组时遇到问题

问题描述

这应该很简单,但有些东西阻止我使用 NSPredicate 通过 NSNumber 过滤自定义对象数组。也许它与从 JSON 转换时的数据类型有关,但我无法弄清楚。

我从一组自定义对象中的 JSON 下载数据,如下所示:

{"hid":"47","public":"1"}

解析 JSON 的代码如下所示:

 if (feedElement[@"public"] && ![feedElement[@"public"] isEqual:[NSNull null]]) {
            newMyObject.pub = feedElement[@"public"]== nil ? @"0" : feedElement[@"public"];}

该对象看起来像:

#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface MyObject : NSObject
@property (nonatomic, retain) NSNumber * hid; 
@property (nonatomic, retain) NSNumber * pub;
@end
NS_ASSUME_NONNULL_END

对象被放置在一个 NSArray * myObjects

我的 NSPredicate 和过滤器代码如下所示:

NSPredicate *pubPred = [NSPredicate predicateWithFormat:@"pub == 1"];
NSArray *filteredArray = [myObjects filteredArrayUsingPredicate:pubPred];

当我登录[myObjects valueForKey:@"pub"]时,它会记录为 1、1、1 等,所以我知道 pub 的值都是 1,但结果filteredArray是空的。

我的代码可能有什么问题?

感谢您的任何建议。

编辑:我在对象中将 public 更改为 pub 以防 public 是保留字但它没有改变任何东西

标签: iosnspredicatensnumber

解决方案


带有示例代码:{"hid":"47","public":"1"}

newMyObject.pub = feedElement[@"public"]== nil ? @"0" : feedElement[@"public"];

如果publicJSON 中存在值,您将使用 设置pub属性feedElement[@"public"],这意味着它将是 @"1"(带有示例),这意味着您将放置一个NSString.
如果publicJSON 中存在值,您将pub使用 @"0" 设置属性,这意味着您将放置一个NSString.

不管它是否被声明@property (nonatomic, retain) NSNumber * pub;,你设置的是 a NSString,而不是 a NSNumber

想要一些代码测试?

@interface MyObject : NSObject

@property (nonatomic, retain) NSNumber *hid;
@property (nonatomic, retain) NSNumber *pub;

+(void)test;
@end

@implementation MyObject

-(id)initWithPub:(NSNumber *)pub andHID:(NSNumber *)hid {
    self = [super init];
    if (self) {
        self.pub = pub;
        self.hid = hid;
    }
    return self;
}

-(NSString *)description {
    return [NSString stringWithFormat:@"%@ pub: %@ - hid: %@", [super description], [self pub], [self hid]];
}

+(NSArray *)arrayList {
    return @[[[MyObject alloc] initWithPub:@1 andHID:@3], //Here with real NSNUmbner
             [[MyObject alloc] initWithPub:@"1" andHID:@"2"]]; //Here with NSString instead
}

+(void)test {
    NSArray *list = [MyObject arrayList];

    NSPredicate *predicateNSNumber = [NSPredicate predicateWithFormat:@"pub == %@", @1];
    NSArray *filteredNSNumber = [list filteredArrayUsingPredicate:predicateNSNumber];
    NSLog(@"Filtered-NSNumber: %@", filteredNSNumber);

    NSPredicate *predicateNSString = [NSPredicate predicateWithFormat:@"pub == %@", @"1"];
    NSArray *filteredNSString = [list filteredArrayUsingPredicate:predicateNSString];
    NSLog(@"Filtered-NSString: %@", filteredNSString);
}

输出:

$> Filtered-NSNumber: (
    "<MyObject: 0x60000024cba0> pub: 1 - hid: 3"
)
$> Filtered-NSString: (
    "<MyObject: 0x60000024d1e0> pub: 1 - hid: 2"
)

[[MyObject alloc] initWithPub:@"1" andHID:@"2"]你可以说:“是的,但是你在:中有一个警告Incompatible pointer types sending 'NSString *' to parameter of type 'NSNumber *',是的,我有。你也应该有它。

实际上,如果您编写了三元 if ,您也会拥有它:

if (feedElement[@"public"] == nil) {
    newMyObject.pub = @"0"; //Incompatible pointer types assigning to 'NSNumber * _Nonnull' from 'NSString *'
} else {
    newMyObject.pub = feedElement[@"public"]; //Here, no warning, because it's hope you know what you are doing and setting a NSNumber here.
}

如何使用它来检查您的代码:

for (MyObject *anObject in list) {
    NSLog(@"Testing: %@", anObject);
    if ([[anObject pub] isKindOfClass:[NSString class]]) {
        NSLog(@"Pub is a String");
    } else if ([[anObject pub] isKindOfClass:[NSNumber class]]) {
        NSLog(@"Pub is a NSNumber");
    }
    NSLog(@"Attempt to call -stringValue which is a NSNumber method, not a NSString one");
    NSLog(@"Attempt Call: %@\n", [[anObject pub] stringValue]);
}

你应该得到一个-[__NSCFConstantString stringValue]: unrecognized selector sent to instance错误,因为它真的是 a NSString,而不是 a NSNumber

解决方案:

您需要修复解析,或更改MyObject.

将财产保持为NSNumber

if ([feedElement[@"public"] isKindOfClass:[NSString class]]) {
     self.pub = @([feedElement[@"public"] integerValue]); //Transform it into a NSInteger, then into a NSNumber with @(someInteger)
} else ([feedElement[@"public"] isKindOfClass:[NSNumber class]]) {
    self.pub = feedElement[@"public"]; //It's already a NSNumber instance
} else {
    self.pub = @(0); //Default value because unknown class or not present 
}

推荐阅读