![](/img/trans.png)
[英]Which way is better to send data by POST method in objective-C?
[英]Which is the best way to check method arguments in Objective-C?
编码方法或函数时,检查输入参数以响应任何可能的失败方案是一种很好的做法。
例如:
-(void)insertNameInDictionary:(NSString*)nameString
{
[myDictionary setObject:nameString forKey:@"Name"];
}
这看起来不错,但如果nameString
为nil
,则应用程序将崩溃。 所以,我们可以检查它是否nil
,对吧? 我们还可以检查它是否是NSString而不是NSNumber,或者它是否响应我们的方法需要调用的方法。
所以我的问题是:检查这些论点最完整,最优雅的方法是什么?
有多种方法可以实现这种保护:
NSParameterAssert
__attribute__((nonnull))
if
测试。 [编辑]自最新的Xcode版本(Xcode 6)以来,Apple添加了可空性注释 ,这是另一种 - 更好 - 表达参数是否nil
/ null
。 您应该迁移到该表示法而不是使用__attribute__((nonnull))
来使您的API更具可读性。
详情如下:
NSParameterAssert
是Apple的专用宏,用于检查方法参数的条件,如果失败则抛出专用异常。
nil
作为参数是一个编程/概念错误 ,考虑到由于你的应用程序工作流程,它通常应该永远不会发生(由于其他条件确保param永远不会是nil
),如果它不是真的出错。 @try/@catch
),但它有一个优点,即抛出的异常更明确(告诉参数预期不会是nil
而不是与丑陋的崩溃)难以理解的callstack / message)。 如果你想让你的代码用nil
调用你的方法但在这种情况下什么也不做,你可以简单地在函数/方法的开头if (!param) return
。
nil
不是编程/概念错误,因此有时可能由于应用程序的工作流程而发生,因此这是一个可以发生并且不应该崩溃的可接受的情况。 不太常见的是 , 有__attribute__((nonnull))
GCC / LLVM属性 , 专用于告诉编译器函数/方法的某些参数应该不为null 。 这样,如果编译器在编译时可以检测到您尝试使用nil
/ NULL
参数调用方法/函数(比如直接调用insertNameInDitionary:nil
而不是使用在编译时无法确定该值的变量) ,它会立即发出编译错误,让你尽快修复它。
[编辑]从最新的Xcode 6开始,您可以(并且应该)使用可空性注释而不是__attribute__((nonnull))
。 请参阅Apple博客文章中的示例。
总结如下:
如果你想标记你的方法,希望你的参数是不nil
,从而表明随着称之为nil
是一个逻辑错误,你应该做到以下几点:
- (void)insertNameInDictionary:(NSString*)nameString __attribute__((nonnull))
{
// __attribute__((nonnull)) allows to check obvious cases (directly passing nil) at compile time
NSParameterAssert(nameString); // NSParameterAssert allows to check other cases (passing a variable that may or may not be nil) at runtime
[myDictionary setObject:nameString forKey:@"Name"];
}
如果你认为用nil
调用你的方法可以发生并且是可以接受的 ,并且你只是想在这些情况下避免崩溃,那么只需执行以下操作:
-(BOOL)insertNameInDictionary:(NSString*)nameString
{
if (nameString == nil) return NO;
[myDictionary setObject:nameString forKey:@"Name"];
return YES;
}
如果您认为您应该能够在字典中插入nil
对象 ,则可以在该特定情况下将nil
值转换为NSNull
,以便插入专用于此类用法的NSNull
单例(我使用的是使用?:
三元运算符使代码更紧凑):
-(void)insertNameInDictionary:(NSString*)nameString
{
[myDictionary setObject:nameString?:[NSNull null] forKey:@"Name"];
}
最后一种情况,如果你想在那个特定的例子中传递nil
只是从myDictionary
删除 Name
,你可以简单地做一个简单的if
测试并调用removeObjectForKey:@"Name"
如果nameString
是nil
并且调用setObject:forKey:
if if's不...或者你可以使用KVC和泛型setValue:forKey:
KVC方法,根本不特定于NSDictionary,所以不要与setObject:forKey:
混淆,在NSDictionary的情况下确实具有相同的行为(删除如果我们为值参数传递nil
,则从字典中键入。
- (void)insertNameInDictionary:(NSString *)nameString
{
if ([nameString isKindOfClass:[NSString class]]) {
[myDictionary setObject:nameString forKey:@"Name"];
}
}
Apple建议使用NSAssert
:
NSAssert(nameString, @"nil nameString is not allowed");
此断言将终止您的程序,并生成一条错误消息,说明发生了什么。
上面, != nil
部分是隐式的,因为Objective-C允许它。 您可以明确说明它以获得更好的可读性:
NSAssert(nameString != nil, @"nil nameString is not allowed");
断言不仅限于nil
检查,因为它们可以采取任意复杂的条件。 您可以检查参数是否为预期类型,它是否响应特定选择器,依此类推。 可以在发布代码中禁用断言以节省CPU周期和电池。
我在这看到几个问题。 NSMutableDictionary没有“ setObject
”方法。 您需要指定一个键。
-(void)insertNameInDictionary:(NSString*)nameString
{
if(nameString)
[myDictionary setObject:nameString forKey: @"someKey"];
}
你也可以通过我的例子中的“ if(nameString)
”位进行零检查。 如果你想要一个空字符串,请使用@""
而不是nil。
这一切都取决于你想要发生什么的语义,如果你想要删除KV对,如果值为nil,那么你可以使用setValue:forKey:
喜欢:
-(void)insertNameInDictionary:(NSString*)nameString
{
[myDictionary setValue:nameString forKey:@"Name"];
}
或者如果要存储表示nil值的值,可以使用NSNull
-(void)insertNameInDictionary:(NSString*)nameString
{
[myDictionary setObject:nameString? :[NSNull null] forKey:@"Name"];
}
-(NSString *)nameInDictionary
{
NSString * retVal = [myDictionary objectForKey:@"Name"];
return (retVal==[NSNull null]) ? nil : retVal;
}
或者您可能只想记录它。
-(void)insertNameInDictionary:(NSString*)nameString
{
if(!nameString)
{
NSLog(@"expected nameString to be not null... silly me %s",__PRETTY_FUNCTION__);
return;
}
[myDictionary setObject:nameString forKey:@"Name"];
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.