String isNullOrEmpty come categoria
-
14-12-2019 - |
Domanda
Sto cercando di creare un metodo che controlli una stringa nulla/nil/vuota e sto cercando di farlo funzionare come categoria ma senza fortuna.
Sto usando questo codice, in base alle risposte in questo argomento:
@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
Eppure quando provo a usarlo questo è ciò che ottengo:
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
Questo mi sconcerta e posso solo supporre che una qualche combinazione di iOS5/ARC stia costringendo l'oggetto nil a una stringa/puntatore vuoto.Il debugger mostra la stringa come 0x0, ma quando utilizzo my isNullOrEmpty
metodo, ottengo falso.
Soluzione
return self == nil
Questo non potrà mai accadere.Se provi a inviare isNullOrEmpty
(o qualsiasi altro messaggio) a nil
, non accade nulla (objc_msgSend()
, la funzione preposta all'invio dei messaggi, verifica a nil
ricevitore come una delle prime cose che fa e interrompe).
self == (id)[NSNull null]
Anche questo non accadrà mai.Se invii isNullOrEmpty
a un oggetto di cui è un'istanza NSNull
, il tuo metodo qui, che è un metodo attivo NSString
, non verrà chiamato.Invece, NSNull
sarà la versione di (che probabilmente non esiste).
Allo stesso modo, ([self respondsToSelector:@selector(count)] && [(NSArray *) self count])
non accadrà mai.Se l'oggetto È UN NSArray
, Poi isNullOrEmpty
non verrà mai eseguito, perché, ancora una volta, è un metodo di NSString
.
Di conseguenza, [(NSData *) self length]
non fa quello che pensi che faccia. NSString
istanze Fare rispondere a length
, ma lanciando l'oggetto a NSData
non utilizza il NSData
versione del metodo: finisce comunque come NSString
versione di length
, perché l'oggetto in realtà lo è UN NSString
(il casting avviene solo in fase di compilazione;non può cambiare nulla in fase di esecuzione).
[self isEqualToString:@"(null)"]
Qui sembra che tu stia controllando nil
ancora una volta, ma vieni ingannato dal rappresentazione Quello NSLog
sceglie quando stampare nil
:
NSLog(@"%@", nil);
Questo viene visualizzato (null)
nella console, ma ciò non significa che l'oggetto stesso sia una stringa con quei caratteri. NSLog
sceglie semplicemente la stringa da visualizzare nil
.*
Molte delle cose che stai facendo richiederebbero che questo fosse in una categoria NSObject
, in modo che il metodo volevo infatti essere chiamato anche se l'oggetto non era an NSString
.
Per verificare la presenza di una stringa composta solo da spazi bianchi, tutto ciò che serve è il confronto con la stringa vuota @""
dopo aver tagliato gli spazi bianchi:
NSString * trimmedSelf = [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
// Then either:
[trimmedSelf isEqualToString:@""];
// Or:
([trimmedSelf length] == 0);
*E ancora meglio, farlo NSLog(@"%@", [NSNull null]);
visualizza <null>
(parentesi angolari invece di parentesi), meravigliosamente confuse le prime volte che incontri NSNull
.
Altri suggerimenti
Un altro approccio può essere quello di definire una semplice macro.
#define NSStringIsNullOrEmpty(str) ((str==nil) || [(str) isEqualToString:@""])
.
È semplice ed efficace.Se non ti piacciono i macro, puoi sempre convertirlo in una chiamata funzione senza influire sul resto del codice.
- Aggiornamento:
@bryan ha sollevato un buon punto.Una funzione in linea è un ottimo modo per andare.Ecco una macro aggiornata che valuterà ST solo una volta.
#define NSStringIsNullOrEmpty(str) ({ NSString *_str=(str); ((tmp==nil) || [tmp isEqualToString:@""]);})
. In OBIETTIVE-C, l'invio di un messaggio a nil restituirà sempre 0 (o NO
, uno struct zero-out, null, ecc., A seconda del tipo di ritorno dichiarato).Il metodo isNullOrEmpty
che hai scritto non verrà effettivamente invocato quando si invia isNullOrEmpty
a nil
.Vedere la risposta accettata a inviando un messaggio a nil? per ulteriori informazioni. Forse potresti cambiare il tuo metodo per essere isNotNullOrEmpty
.Quindi un valore di ritorno di 0 quando si invia isNotNullOrEmpty
a nil
ha senso.
Non stai chiamando il tuo metodo, ma Invio di un messaggio a Nil .
Questo è il comportamento previsto.Stai inviando un messaggio a nil
dopo tutto.Quindi sta restituendo né nil (o qualche altro valore 0).Quali cortocircuiti per false, in modo che '0' sia stampato nei casi indicati di seguito:
NSLog([s1 isNullOrEmpty] ? @"1":@"0"); // prints 0
NSLog([(NSString*)nil isNullOrEmpty] ? @"1":@"0"); // prints 0
.
È anche possibile confermare il messaggio non viene chiamato per quei casi impostando un punto di interruzione nel tuo nuovo metodo di categoria.
Come altri hanno detto, chiamare [nil isNullOrEmpty];
non eseguirà effettivamente il tuo metodo.L'oggetto nil
è solo quello: vuoto stesso.
Come soluzione, vorrei dire che non è perché sei in una lingua orientata agli oggetti che non devi mai usare le funzioni.
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;
}
. In realtà ho appena riparato questo problema ruotandolo come così
-(BOOL) isNotNullOrWhiteSpace
{
return [self length] != 0 && [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] != 0;
}
.
Quindi invece di isnoulrorwhithace è il suo isnotnullrorwhitespace.
Ecco il mio metodo di controllo null / vuoto
- (NSString *) NULLINPUTINITWithString: (NSString *) Inspstring {
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 ;
.
}
Hai pensato di creare un metodo di classe su una categoria che estende NSString?
nsstring + nstringextensions.h
#import <Foundation/Foundation.h>
@interface NSString(NSStringExtensions)
+(BOOL)isNilOrEmpty:(NSString*)string;
@end
.
nsstring + nstringextensions.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
.
Allora lo usi come questo:
#import "NSString+NSStringExtensions.h"
...
NSLog([NSString isNilOrEmpty:@""] ? @"1":@"0");
.