У меня возникли проблемы с проверкой, содержит ли массив объект.
Массив @property(nonatomic) NSArray<NSNumber*>* apiArray;
возвращается как параметр из модели API, а объект, наличие которого я хочу проверить в массиве, возвращается из другой модели API @property(nonatomic) NSNumber* localObject;
.
Когда я проверяю это [apiArray containsObject: localObject]
, он выводит 0, хотя значение есть..
Итак, я проверил типы, и на localObject
тип фактически является NSNumber, в то время как, если я не ошибаюсь, результаты массива представляют собой массив NSString, как показано на рисунках ниже.
NSLog(@"$$$$$$$$$$$ [apiArray containsObject: localObject]: %d", [apiArray containsObject: localObject] );
NSLog(@"apiArray types are: %@", [apiArray valueForKey:@"class"]);
NSLog(@"localObject type is: %@", [localObject valueForKey:@"class"]);
NSLog(@"apiArray is: %@", apiArray);
NSLog(@"localObject is: %@", localObject);
$$$$$$$$$$$ [apiArray containsObject: localObject]: 0
apiArray types are: (
"__NSCFString"
)
localObject type is: __NSCFNumber
apiArray is: (
5717271485874176
)
localObject is: 5717271485874176
API NSNumber array types are: (
"__NSCFString"
)
Модели генерируются с помощью swagger-codegen.jar, но, как показывают параметры, они оба кажутся правильными.
В качестве теста я сам создал массив, и действительно, типы NSNumber и containsObject действительно работают так, как ожидалось.
NSMutableArray<NSNumber*>* apiArray = [NSMutableArray<NSNumber*> array];
NSNumber *localObject = [NSNumber numberWithInt: -1];
[apiArray addObject: localObject];
NSLog(@"$$$$$$$$$$$ [apiArray containsObject: localObject]: %d", [apiArray containsObject: localObject] );
NSLog(@"apiArray types are: %@", [apiArray valueForKey:@"class"]);
NSLog(@"localObject type is: %@", [localObject valueForKey:@"class"]);
NSLog(@"apiArray is: %@", apiArray);
NSLog(@"localObject is: %@", localObject);
$$$$$$$$$$$ [apiArray containsObject: localObject]: 1
apiArray types are: (
"__NSCFNumber"
)
localObject type is: __NSCFNumber
apiArray is: (
"-1"
)
localObject is: -1
API NSNumber array types are: (
"__NSCFNumber"
)
Можете ли вы определить, в чем может быть проблема?
@ Cy-4AH Cy-4AH Я обновил вопрос, добавив отпечатки значений. Видимо, я получаю массив NSNumber с сервера, но до сих пор не понимаю, почему containsObject возвращает 0, когда объект действительно присутствует, а тип массива печатает NSString.
Ваш сервер отправляет строки вместо чисел.
да, это выглядело бы так
Один из них — строка, другой — число, и чтобы иметь возможность «полностью сравнить» NSNumber
, я бы вместо этого использовал integerValue
.
@Larme Я не уверен, что слежу за тобой. В моем первом фрагменте кода я использую значения модели API, печать массива не показывает значение между "
, его тип значений — NSString, а containsObject возвращает 0. Во втором фрагменте я использую массив, который заполняю сам, и значение печатается между "
, его тип значения действительно NSNumber, а containsObject правильно возвращает 1. где мне использовать integerValue
? по объекту я хочу знать, присутствует ли он в массиве из API или где?
@Larme, ок... Я разобрался благодаря твоему предложению. Я начал с установки BOOL containsObject
на false. Затем я перебираю значения массива и только когда containsObject
имеет значение false (чтобы не переопределять возможное совпадение), я сравниваю их .integerValue
с локальным объектом .integerValue
и присваиваю полученное значение BOOL самому containsObject
. Это работает и соответствует моей цели, но я все еще не могу понять, почему типы значений массива, возвращаемые с сервера, являются NSString, тогда как и модель, и json, которые мы получаем для ее компиляции, не являются таковыми.
Вы можете создать расширение для NSArray
: -(BOOL)containsWhere:(BOOL (^)(id obj))predicate { NSInteger index = [self indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { return predicate(obj); }]; return index != NSNotFound; }
, а затем назвать его так: BOOL contains = [array containsWhere:^BOOL(id _Nonnull obj) { return [obj integerValue] == [localObject integerValue]; }];
Другое значение модели API (то, которое я хочу узнать, присутствует ли в массиве) компилируется как тест SNNumber.
@Vincenzo Как на самом деле извлекается apiArray
? В Objective-C все элементы массива будут NSArray<NSNumber*>*
не потому, что NSNumber
, это скорее предложение/напоминание, на самом деле проверки НЕТ.
Чтобы быть в большей безопасности в моем предложении containsWhere
, позвоните, вы можете сделать if ([obj respondsToSelector:@selector(integerValue)]) { return [obj integerValue] == [@2 integerValue]; } else { NSLog(@"Element %@ from array to analyze doesn't responds to integerValue -> Skipped", obj); return FALSE; }
, иначе вы можете получить unrecognized selector sent to
ошибку сбоя.
@Larme OOH Понятно... спасибо за разъяснения по поводу типа массива. Мне пришлось внести изменения в наше приложение Objective-c, но я в этом очень новичок. Так что, я думаю, проблема может заключаться в компиляции API с swaggerм. Ребята из серверной части сказали мне, что они отправляют длинные значения, а не строки, и проверяют полученный json для компиляции API, параметр apiArray равен "apiArray":{"type":"array","items":{"type":"integer","format":"int64"}}
.
Используйте xml: в нем нет проблем с числами в строках
В Objective-C NSArray<NSNumber*>* apiArray
будет содержать только apiArray
не потому, что он объявлен как таковой NSNumber
:
NSArray<NSNumber*>* apiArray;
NSArray *t = @[@[], @"", @2];
apiArray = t;`
Это скомпилируется нормально, а элементами apiArray
являются массив, строка и число.
Это распространенная причина сбоя unrecognized selector sent to instance
.
NSArray<NSNumber*>* apiArray
— это всего лишь маленький помощник:
Он сообщает вам, что apiArray
ДОЛЖЕН содержать только NSNumber
элементы (даже если это не так), поэтому, когда вы его заполняете, заполняйте его соответствующим образом, а при извлечении из него элементов он будет ожидать, что они будут NSNumber
.
Итак, NSArray *first = [apiArray firstObject];
выдаст предупреждение Incompatible pointer types initializing 'NSArray *' with an expression of type 'NSNumber * _Nullable'
, но это всё, просто предупреждение. И в моем случае первый элемент на самом деле — это NSArray
, а не NSNumber
.
После нескольких отзывов с вашей стороны кажется, что серверная часть отправляет NSString
вместо NSNumber
.
Вам решать, менять его при анализе JSON или нет, или изменить локальную модель на localObject
, чтобы она была NSString
.
Если вы хотите сохранить оба API/local как таковые, поскольку у вас есть NSString
и NSNumber
для сравнения, возможный способ — использовать integerValue
.
Это немного более подробно, но это должно помочь:
NSInteger index = [self indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
return [obj integerValue] == [localObject integerValue];
}];
BOOL contains = index != NSNotFound;
Если вы хотите создать contains(where:)
(в более «быстром» коде), вы можете создать категорию в NSArray:
NSArray+Custom.h
@interface NSArray<ObjectType> (Addon)
-(BOOL)containsWhere:(BOOL (^)(id obj))predicate;
@end
NSArray+Custom.m
@implementation NSArray (Addon)
-(BOOL)containsWhere:(BOOL (^)(id obj))predicate
{
NSInteger index = [self indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
return predicate(obj);
}];
return index != NSNotFound;
}
@end
Затем в использовании:
NSNumber *localObject = @2;
BOOL contains = [array containsWhere:^BOOL(id _Nonnull obj) {
if ([obj respondsToSelector:@selector(integerValue)]) {
return [obj integerValue] == [localObject integerValue];
} else {
NSLog(@"Element %@ from array to analyze doesn't respond to integerValue -> Skipped", obj);
return FALSE;
}
}];
NSLog(@"%@ contains localObject: %d", array, localObject, contains);
Ух ты! Большое спасибо за ответ, мне очень приятно такое подробное объяснение. Я еще раз проверил с ребятами из серверной части, и они действительно отправляют массив строк ... хотя этого не должно быть, и они изучают это, потому что этого не должно быть, глядя на yaml OpenAPi, они используем для генерации конечных точек
Тем временем я просто искал расширение для NSArray, чтобы решить проблему, поскольку мое решение цикла for — не самый элегантный способ ее решения, поэтому еще раз спасибо за огромную помощь.
Вы получаете с сервера числа в двойных кавычках?