Cadeia isNullOrEmpty como uma categoria
-
14-12-2019 - |
Pergunta
Eu estou tentando criar um método que verifica a existência de um nulo/nulo/string vazia, e eu estou tentando fazê-lo funcionar como uma categoria, mas tendo nenhuma sorte.
Eu estou usando este código, baseadas no respostas este tópico:
@implementation NSString (NSStringExtension)
- (BOOL)isNullOrEmpty {
return self == nil ||
self == (id)[NSNull null] ||
[@"" isEqualToString:self] ||
[[self stringByReplacingOccurrencesOfString:@" " withString:@""] length] == 0||
[self isEqualToString:@"(null)"]
|| ([self respondsToSelector:@selector(length)] && [(NSData *) self length] == 0)
|| ([self respondsToSelector:@selector(count)] && [(NSArray *) self count] == 0)
|| [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0;
}
@end
No entanto, quando tento utilizar este é isso que eu recebo:
NSLog([@"" isNullOrEmpty] ? @"1":@"0"); // prints 1
NSString *s1 = nil;
NSLog([s1 isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([args.itemName isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([(NSString*)nil isNullOrEmpty] ? @"1":@"0"); // prints 0
Isso é desconcertante de mim, e eu só posso supor que a combinação do iOS5/ARCO está causando o nil objeto a ser coagido a uma seqüência de caracteres em branco/ponteiro.O depurador mostra a seqüência de caracteres como 0 x 0, mas quando eu uso o meu isNullOrEmpty
método, recebo falso.
Solução
return self == nil
Isso nunca pode acontecer.Se você tentar enviar isNullOrEmpty
(ou qualquer outra mensagem) para nil
, não acontece nada (objc_msgSend()
, a função responsável por envio de mensagem, verifica a existência de uma nil
receptor como uma das primeiras coisas que ele faz e anula).
self == (id)[NSNull null]
Isso também irá acontecer nunca.Se você enviar isNullOrEmpty
para um objeto que é uma instância de NSNull
, seu método aqui, que é um método NSString
, não será chamado.Em vez disso, NSNull
's versão (que provavelmente não existe) vai ser.
Da mesma forma, ([self respondsToSelector:@selector(count)] && [(NSArray *) self count])
nunca vai acontecer.Se o objeto é um NSArray
, e , em seguida, isNullOrEmpty
nunca será executado, pois, mais uma vez, é um método de NSString
.
Correspondentemente, [(NSData *) self length]
não faz o que você acha que ele faz. NSString
instâncias fazer responder length
, mas o elenco do objeto para NSData
não usar o NSData
versão do método -- ele ainda termina como a NSString
versão length
, porque o objeto na verdade, é um NSString
(fundição só acontece em tempo de compilação;ele não pode mudar nada em tempo de execução).
[self isEqualToString:@"(null)"]
Aqui você parecer ser de verificação para nil
novamente, mas você está sendo enganado pelos representação que NSLog
escolhe quando imprime nil
:
NSLog(@"%@", nil);
Este apresenta (null)
no console, mas isso não significa que o objeto em si é uma seqüência de caracteres com os personagens. NSLog
é só escolher a que a seqüência de caracteres para exibir para nil
.*
Várias das coisas que você está fazendo exigiria que este ser em uma categoria em NSObject
, de modo que o método gostaria de no fato de ser chamada, mesmo se o objeto não era uma NSString
.
Para verificar se uma string consistindo apenas de espaços em branco, tudo que você precisa é a comparação de seqüência de caracteres vazia @""
depois do corte de espaço em branco:
NSString * trimmedSelf = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
// Then either:
[trimmedSelf isEqualToString:@""];
// Or:
([trimmedSelf length] == 0);
*E melhor ainda, fazendo NSLog(@"%@", [NSNull null]);
apresenta <null>
(colchetes em vez de parênteses), maravilhosamente confuso nas primeiras vezes que você encontrar NSNull
.
Outras dicas
Outra abordagem pode definir uma macro simples.
#define NSStringIsNullOrEmpty(str) ((str==nil) || [(str) isEqualToString:@""])
É simples e eficaz.Se você não gosta de macros que você pode sempre convertê-lo para uma chamada de função, sem afetar o resto do seu código.
-- Update:
@Bryan levantou um bom ponto.Uma função in-line é uma ótima maneira de ir.Aqui está uma actualização macro que irá avaliar str apenas uma vez.
#define NSStringIsNullOrEmpty(str) ({ NSString *_str=(str); ((tmp==nil) || [tmp isEqualToString:@""]);})
Em objective-C, o envio de uma mensagem para nil sempre irá retornar 0 (ou NO
, uma zerado-out, struct, NULL, etc., dependendo do tipo de retorno declarado).O isNullOrEmpty
o método que você escreveu não, na verdade, ser invocada quando você enviar isNullOrEmpty
para nil
.Veja o aceite resposta O envio de uma mensagem para nil? para obter mais informações.
Talvez você pudesse mudar o seu método a ser isNotNullOrEmpty
.Em seguida, um valor de retorno de 0 ao enviar isNotNullOrEmpty
para nil
vai fazer sentido.
Você não está chamando o seu método, mas o envio de uma mensagem para nil.
Este é o comportamento esperado.Você está enviando uma mensagem para nil
depois de tudo.Então, ele está retornando ou nulo (ou algum outro valor 0).Que os curto-circuitos para false para que o " 0 " é impresso em casos mostrado abaixo:
NSLog([s1 isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([(NSString*)nil isNullOrEmpty] ? @"1":@"0"); // prints 0
Você pode até confirmar a sua mensagem não está sendo chamado para aqueles casos em que, por definição, um ponto de interrupção em sua nova categoria de método.
Como outros já disseram, chamando [nil isNullOrEmpty];
na verdade, não será executado o método.O nil
objeto é apenas isso :esvaziar-se.
Como uma solução, eu gostaria de dizer que não é porque você está em uma linguagem Orientada a Objeto que você nunca deve usar funções.
BOOL IsStringNilOrEmpty(NSString*)str
{
return str == nil ||
str == null ||
[@"" isEqualToString:str] ||
[[str stringByReplacingOccurrencesOfString:@" " withString:@""] length] == 0||
[str isEqualToString:@"(null)"]
|| ([str respondsToSelector:@selector(length)] && [(NSData *) str length] == 0)
|| ([str respondsToSelector:@selector(count)] && [(NSArray *) str count] == 0)
|| [[str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0;
}
na verdade, eu só corrigiu este problema girando em torno de como isso
-(BOOL) isNotNullOrWhiteSpace
{
return [self length] != 0 && [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] != 0;
}
assim, em vez de isNullOrWhiteSpace é isNotNullOrWhiteSpace.
Aqui está o meu método de verificação nulo/vazio
-(NSString*)NULLInputinitWithString:(NSString*)InputString {
if( (InputString == nil) ||(InputString ==(NSString*)[NSNull null])||([InputString isEqual:nil])||([InputString length] == 0)||([InputString isEqualToString:@""])||([InputString isEqualToString:@"(NULL)"])||([InputString isEqualToString:@"<NULL>"])||([InputString isEqualToString:@"<null>"]||([InputString isEqualToString:@"(null)"])||([InputString isEqualToString:@"NULL"]) ||([InputString isEqualToString:@"null"])))
return @"";
else
return InputString ;
}
Você já pensou em criar um método de classe em uma categoria que se estende NSString?
NSString+NSStringExtensions.h
#import <Foundation/Foundation.h>
@interface NSString(NSStringExtensions)
+(BOOL)isNilOrEmpty:(NSString*)string;
@end
NSString+NSStringExtensions.m
#import "NSString+NSStringExtensions.h"
@implementation NSString(NSStringExtensions)
+(BOOL)isNilOrEmpty:(NSString*)string
{
if (nil == string)
{
return YES;
}
if (string.length == 0)
{
return YES;
}
return NO;
}
@end
Em seguida, você usá-lo assim:
#import "NSString+NSStringExtensions.h"
...
NSLog([NSString isNilOrEmpty:@""] ? @"1":@"0");