У меня возникли проблемы с проверкой, содержит ли массив объект.
Массив @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 — не самый элегантный способ ее решения, поэтому еще раз спасибо за огромную помощь.
Вы получаете с сервера числа в двойных кавычках?