在开始时宣布,或在你去的时候宣布?

时间:2010-02-11 11:50:26

标签: objective-c cocoa-touch

我会说这几乎是一种风格/可读性的东西,虽然我确实看到几乎所有的Objective-c / cocoa按照“METHOD_002”进行格式化。我只是好奇如果“METHOD_001”被认为是坏的风格,将所有声明放在方法的顶部是有好处的,但是如果你没有声明使用它们的对象,那么在可读性方面又有缺点吗?

METHOD_001

-(IBAction)dateButtonPressed {

    NSDate      *dateSelected;
    NSString    *dateString;
    NSArray     *dateItems;
    NSString    *alertMessage;
    UIAlertView *alert;

    dateSelected = [datePicker date];
    dateString = [[NSString alloc] initWithFormat:@"%@", dateSelected];
    dateItems = [dateString componentsSeparatedByString:@" "];
    alertMessage = [[NSString alloc] initWithFormat:@"Date: %@ Time: %@",  [dateItems objectAtIndex:0], [dateItems objectAtIndex:1]];
    alert = [[UIAlertView alloc] initWithTitle:@"You Selected" 
                                       message:alertMessage 
                                      delegate:nil 
                             cancelButtonTitle:@"OK" 
                             otherButtonTitles:nil];
    [alert show];
    [alert release];
    [alertMessage release];
    [dateString release];

}

METHOD_002

-(IBAction)dateButtonPressed {

    NSDate *dateSelected = [datePicker date];
    NSString *dateString = [[NSString alloc] initWithFormat:@"%@", dateSelected];
    NSArray *dateItems = [dateString componentsSeparatedByString:@" "];
    NSString *alertMessage = [[NSString alloc] initWithFormat:@"Date: %@ Time: %@",  [dateItems objectAtIndex:0], [dateItems objectAtIndex:1]];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"You Selected" 
                                                    message:alertMessage 
                                                   delegate:nil 
                                          cancelButtonTitle:@"OK" 
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];
    [alertMessage release];
    [dateString release];

}

加里

6 个答案:

答案 0 :(得分:5)

METHOD_002肯定。虽然有些人可能会提出METHOD_001的理由,但它主要是出于技术和历史原因。较旧的C编译器需要在任何可执行代码之前定义的所有堆栈变量(局部变量)。这是ANSI标准的一部分。它不再是,而且应该被归为历史。

METHOD_002有几个优点:

  • 它鼓励块区域划分。通过在块内部定义变量(例如for()循环),该变量不能在其有意义的范围之外被意外使用。 ANSI通过在块的顶部定义变量来允许块作用域,但是我发现一旦人们习惯在函数的顶部进行声明,它很少以这种方式完成。

  • 它捕捉到其他意外重复使用。例如,您在函数顶部定义变量“result”并将其指定为nil。您的代码假定在某个循环开始时它为NULL。然后在函数顶部插入更多代码,并通过习惯重用变量“result”。您可能刚刚为后面的代码创建了意外的副作用。如果您使用METHOD_002,那么您将使前一个结果块本地化,或者当您在同一范围内重新声明另一个具有相同名称的变量时,您将收到编译器错误。

  • 它使得Extract重构更加容易,因为变量声明通常会接近使用它们的代码。提取也不太可能产生意想不到的副作用,因为变量不太可能在代码的不同区域重复使用。

  • 它减少了“残酷”的可能性。当删除使用它们的代码时,函数顶部的变量很少被删除。编译器可以优化它,但它仍然是代码残留。

  • 它通过较少的变量重用来鼓励更有意义的名称。在实践中,我发现当人们在函数顶部声明变量时,他们更可能只是通过函数重用一些名为“tmpValue”的变量用于几种不同的用途。没有理由这是真的,但我发现变量声明来自使用它的代码越远,人们就越不可能不厌其烦地宣布一个新变量。除了良好的命名之外,没有什么比防止错误更好的了。

我发现METHOD_002有一个缺点:

  • 找到变量的类型比较困难。这对于IDE来说不太重要,因为您通常可以轻松跳转到其声明。我认为变量的名称通常应该使其类型明显。但是,有时候很难找到这种类型。作为必然结果,有时可能难以确定变量的范围。

答案 1 :(得分:1)

我倾向于赞成“METHOD_002”。它似乎更简洁,更容易阅读,虽然这可能只是因为我已经习惯了。

我认为“METHOD_001”的优势在于,如果您决定将局部变量提升为实例变量,则只需删除方法顶部的本地声明,而不是寻找其声明。我只能预见这会成为非常大的方法的问题。

答案 2 :(得分:1)

绝对是METHOD_002。在我编写长,长,长的ASP代码块的那天,我被告知METHOD_001,然后将所有变量列在顶部似乎是有道理的,就像警告一样(在这个旅程中我们将遇到以下内容...... )。然而,在实践中,人们会盯着一种名为strFwdBck的东西,并想知道那天特定的咖啡是什么。我们当时没有“未使用的变量”警告,至少不是我所知道的。

现在我只是声明我真正需要的东西并立即使用它。即便如此,我经常回去收紧事情。

-(IBAction)dateButtonPressed {
     NSString *dateString = [[NSString alloc] initWithFormat:@"%@", [datePicker date]];
     NSArray *dateItems = [dateString componentsSeparatedByString:@" "];

     NSString *alertMessage = [[NSString alloc] initWithFormat:@"Date: %@ Time: %@",        [dateItems objectAtIndex:0], [dateItems objectAtIndex:1]];
    [dateString release];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"You Selected" 
                                                    message:alertMessage 
                                                   delegate:nil 
                                          cancelButtonTitle:@"OK" 
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];
    [alertMessage release];
}

答案 3 :(得分:1)

我通常将两者混合在一起。如果变量只分配一次,那么我使用method_002。这使声明保持在使用变量的位置。但是,如果变量被多次分配,我使用method_001,因为那时我不必寻找代码来查找定义。

后一种情况的例子:

使用method_002:

-(void) someMethod{
    //...some code
    SomeClass *myVar=[assign someValue];
    //...some more code
    if (someTest) {
        myVar=someValue;
    }else{
        myVar=someOtherValue;
    }
}

如果您回到代码并查看myVar=someOtherValue;,您将不得不重新编写代码来查找定义。相反,如果你使用method_001,你会得到:

-(void) someMethod{
    SomeClass *myVar;
    //...some code
    myVar=[assign someValue];
    //...some more code
    if (someTest) {
        myVar=someValue;
    }else{
        myVar=someOtherValue;
    }
}

您只需跳到顶部即可查看定义。

如果您始终如一地使用此样式,您将自动知道在函数/方法开头定义的任何变量将具有多个赋值,而在正文中定义的任何变量都不会。

这真的有助于理解,特别是如果你花了很多时间回到你已经完全忘记的旧代码。

答案 4 :(得分:0)

对于这两种风格都有很好的论据,但我建议你去做你曾经做过的事情,或者更重要的是,无论你的客户和/或雇主使用什么格式。

无论您为个人项目选择什么,只要始终如一地 - 当您试图避免引入恼人/愚蠢的语法错误时,一致性会有很大帮助。 (在没有外部指导的情况下,我使用google's style guide

答案 5 :(得分:0)

我认为你的方法2实际上是方法1和我称之为方法3之间的1/2方式

方法3是在代码中的任何地方声明变量的地方,就在它们第一次使用之前。如果那是在函数的末尾那么就是它。

示例中方法1和2之间的区别似乎主要是初始化问题。我认为在声明变量时输入变量是一个好主意,并且具有可读性。但是,我也倾向于认为在顶部声明变量使调试更容易。如果您没有从上到下阅读函数,那么弄清楚变量的声明位置以及变量的类型可能会很棘手。

当你有很长的功能(你不应该做什么,但它最终会发生),这大部分成为一个问题,所以20行进入你声明变量的函数,然后再使用它50行后再过20行。如果你只是去功能的开头,那就找出它的类型会更容易看看......

然而,正如你所说,这是一个风格问题,所以最终成为一个意见问题......