Especificaciones de desarrollo de iOS

Prefacio

Este artículo está compilado y escrito con referencia a algunas de mis propias especificaciones de código y las especificaciones de código de muchos otros socios en Internet.

Objetivo

Para facilitar el mantenimiento del proyecto y el desarrollo estandarizado, promover la eficiencia de la revisión del código entre los miembros, para lograr un código hermoso y para la armonía de los miembros, se proponen las siguientes especificaciones de desarrollo. Si tiene mejores sugerencias, no dude en enviarlas.

El público objetivo de este documento incluye: desarrolladores de iOS.

Ha comenzado, es muy largo.

Esta especificación se divide en tres partes:

1. Principios básicos: este artículo presenta los principios básicos seguidos por esta especificación de código.

2. Especificaciones universales: especificaciones de código universal que no se limitan a iOS (usando lenguaje C y lenguaje Swift).

3. Especificaciones de iOS: especificaciones de código solo aplicables a iOS (usando lenguaje Objective-C).

1. Principios fundamentales

Principio 1: el código debe ser conciso, fácil de entender y lógicamente claro

Porque el software necesita gente para mantenerlo. Es posible que esta persona no seas tú en el futuro. Así que escriba programas para personas primero y luego para computadoras: no busque demasiado las habilidades y reduzca la legibilidad del programa. El código conciso no deja lugar para que se oculten los errores. Escriba código que obviamente esté libre de errores, no código que esté libre de errores.

Principio 2: Programa para el cambio, no para requisitos.

Las necesidades son temporales, sólo el cambio es eterno. Esta iteración no puede ser solo para las necesidades actuales, es responsable de escribir un programa que sea altamente escalable y fácil de modificar.

Principio 3: primero asegúrese de que el programa sea correcto para evitar una ingeniería excesiva

Sobreingeniería: consideración excesiva de los problemas de extensión y reutilización antes de escribir el código correcto y utilizable, lo que hace que el proyecto sea demasiado complejo.

1. Primero resuelva el problema inmediato, resuélvalo bien y luego considere problemas de expansión futuros.

2. Primero escriba código utilizable, piense en él repetidamente y luego considere si es necesario reutilizarlo.

3. Primero escriba un código que sea utilizable, simple y obviamente libre de errores, y luego considere realizar pruebas.

2. Especificaciones generales

Acerca de los frenillos

En declaraciones de control (if, for, while, switch), el principio y el final de las llaves

Se recomienda escribir así:

white(someCondition) {
    
}

//函数
void function(param1, param2) {
    
}

operador

1. La brecha entre operadores y variables

1.1 No hay espacio entre el operador unario y la variable:

1.2 Debe haber un espacio entre el operador binario y la variable

!bValue
++iCount

fHeight = fWidth + fLength;
for(int i = 0; i < 10; i++)

variable

1. Una variable tiene una y sólo una función. Trate de no utilizar una variable para múltiples propósitos.

2. Las variables deben inicializarse antes de su uso para evitar que se haga referencia a variables no inicializadas.

3. Las variables locales deben estar lo más cerca posible del lugar donde se utilizan.

推荐这样写:
func someFunction() {
let index = ...;
//Do something With index
...
...
let count = ...;
//Do something With count
}

不推荐这样写:
func someFunction() {
let index = ...;
let count = ...;
//Do something With index
...
...
//Do something With count
}

si declaración

1. No utilice demasiadas sucursales y sea bueno usando el retorno para regresar temprano.

推荐这样写:
- (void)someMethod {
    if (!goodCondition) {
        return;
    }
    //Do something
}

不推荐这样写:
- (void)someMethod {
    if (goodCondition) {
        //Do something
    }
}

situación equivocada

Un ejemplo más típico que he encontrado en JSONModel:

-(id)initWithDictionary:(NSDictionary*)dict error:(NSError)err{
    //⽅法1.参数为nil
    if (!dict) {
        if (err) *err =[JSONModelError errorInputIsNil];
        return nil;
    }
    
    //⽅法2.参数不是nil,但也不是字典if (![dict isKindOfClass:[NSDictionary class]]) {
    if (err) *err =[JSONModelError errorInvalidDataWithMessage:@"Attempt
                    to initialize JSONModel object using initWithDictionary:error: but the
                    dictionary parameter was not an 'NSDictionary'."];
                    return nil;
}

//⽅法3.初始化
self =[self init];
if (!self) {
    //初始化失败
    if (err) *err =[JSONModelError errorModelIsInvalid];
    return nil;
}

//⽅法4.检查⽤户定义的模型⾥的属性集合是否⼤于传⼊的字典⾥的key集合(如果⼤于,则返回NO)
if (![self __doesDictionary:dict
    matchModelWithKeyMapper:self.__keyMapper error:err]) {
    return nil;
}
                    
//⽅法5.核⼼⽅法:字典的key与模型的属性的映射
if (![self __importDictionary:dict withKeyMapper:self.__keyMapper
                   validation:YES error:err]) {
    return nil;
}
                    
//⽅法6.可以重写[self validate:err]⽅法并返回NO,让⽤户⾃定义错误并阻拦model的返回
if (![self validate:err]) {
    return nil;
}
                    
//⽅法7.终于通过了!成功返回model
return self;
}

Se puede ver que aquí primero se juzgan varias situaciones de error y luego se devuelven con anticipación, y la situación más correcta es

Regreso al final.

2. Si la expresión condicional es muy larga, debe extraerla y asignarle un valor BOOL.

推荐这样写:
let nameContainsSwift = sessionName.hasPrefix("Swift")
let isCurrentYear = sessionDateCompontents.year == 2014
let isSwiftSession = nameContainsSwift && isCurrentYear
if (isSwiftSession) {
// Do something
}
不推荐这样写:
if ( sessionName.hasPrefix("Swift") && (sessionDateCompontents.year ==
2014) ) {
// Do something
}

3. El juicio del enunciado condicional debe ser que las variables están a la izquierda y las constantes a la derecha.

推荐这样写:
if (count == 6) {
    
}
或者
if (object == nil) {
    
}
或者
if (!object) {
    
}

4. El código de implementación de cada rama debe estar entre llaves.

Declaración de cambio

1. Cada rama debe estar entre llaves

//推荐这样写:
switch (integer) {
    case 1: {
        // ...
    }
        break;
    case 2: {
        // ...
        break;
    }

    default:{
        // ...
        break;
    }
}

2. Cuando se utilizan tipos de enumeración, no puede haber una rama predeterminada, excepto cuando se utilizan tipos de enumeración, debe haber una rama predeterminada.

Cuando se usa un tipo de enumeración en una instrucción Switch, si se usa la rama predeterminada, el compilador no podrá verificar el tipo de enumeración recién agregado en el futuro.

función

1. La longitud de una función debe limitarse a 50 líneas.

En términos generales, al leer una función, si necesita abarcar una distancia vertical larga, afectará en gran medida la experiencia de lectura del código. Si necesita poner los ojos en blanco o codificar de un lado a otro para ver el método completo, afectará en gran medida la coherencia del pensamiento y tendrá un mayor impacto en la velocidad de lectura del código. La mejor situación es que todo el código del método se puede ver de un vistazo sin poner los ojos en blanco ni el código.

2. Una función sólo hace una cosa (principio único)

Las responsabilidades de cada función deben estar claramente definidas (como una clase).

// 推荐这样写:
dataConfiguration()
viewConfiguration()

// 不推荐这样写:
void dataConfiguration() {
    ...
    viewConfiguration()
}

3. Para funciones (métodos) con valores de retorno, cada rama debe tener un valor de retorno

// 推荐这样写:
int function() {
    if(condition1){
        return count1
    }else if(condition2){
        return count2
    }else{
        return defaultCount
    }
}

4. Verifique la exactitud y validez de los parámetros de entrada y regrese inmediatamente si ocurren errores de parámetros.

// 推荐这样写:
void function(param1,param2) {
    if(param1 is unavailable){
        return;
    }
    if(param2 is unavailable){
        return;
    }
 //Do some right thing
}

5. Si hay las mismas funciones dentro de diferentes funciones, las mismas funciones deben extraerse y usarse como otra función.

// 原来的调⽤:
void logic() {
    a();
    b();
    if (logic1 condition) {
        c();
    } else {
        d();
    }
}

// 将a,b函数抽取出来作为单独的函数
void basicConfig() {
    a();
    b();
}

void logic1() {
 basicConfig();
 c();
}

void logic2() {
 basicConfig();
 d();
}

6. Extraiga la lógica más compleja dentro de la función como una función separada.

El código poco claro en una función (más juicios lógicos y más líneas) a menudo se puede extraer para formar una nueva función y luego llamarlo en el lugar original para que pueda Utilice nombres de funciones significativos en lugar de comentarios para aumentar la legibilidad del programa.

Dé un ejemplo de envío de un correo electrónico:

openEmailSite();
login();
writeTitle(title);
writeContent(content);
writeReceiver(receiver);
addAttachment(attachment);
send();

// 中间的部分稍微⻓⼀些,我们可以将它们提取出来:
void writeEmail(title, content,receiver,attachment)
{
    writeTitle(title);
    writeContent(content);
    writeReceiver(receiver);
    addAttachment(attachment);
}

// 然后再看⼀下原来的代码:
openEmailSite();
login();
writeEmail(title, content,receiver,attachment)
send();

7. Evite el uso de variables globales y miembros de clase para transferir información y utilice variables y parámetros locales tanto como sea posible.

En una clase, muchas veces es necesario pasar ciertas variables. Y si la variable que se debe pasar es una variable o atributo global, a algunos amigos no les gusta usarlos como parámetros, sino que acceden a ellos directamente dentro del método:

class A {
    var x;
    func updateX() {
        ...
        x = ...;
    }
    func printX() {
        updateX();
        print(x);
    }
}

Podemos ver que en el método printX no hay transferencia de valores entre los métodos updateX e print, a primera vista es posible que no sepamos de dónde viene x, lo que reduce la legibilidad del programa. Y si usa variables locales en lugar de miembros de la clase para pasar información, entonces estas dos funciones no necesitan depender de una clase determinada, son más fáciles de entender y menos propensas a errores:

func updateX() -> String{
    x = ...;
    return x;
}
func printX() {
    String x = updateX();
    print(x);
}

Comentario

La mayor parte del código excelente es autodescriptivo. Podemos utilizar el código del programa mismo para expresar lo que está haciendo sin la ayuda de comentarios. Pero esto no significa que no debas escribir comentarios, hay tres situaciones en las que es más adecuado escribir comentarios:

1. Interfaz pública (los comentarios deben decirle a las personas que leen el código qué funciones puede lograr la clase actual).

2. Código que implica un conocimiento profesional más profundo (los comentarios deben reflejar los principios e ideas de implementación).

3. Código propenso a la ambigüedad (pero estrictamente hablando, no se permite que exista código propenso a la ambigüedad).

Además de las tres situaciones anteriores, si otros solo pueden confiar en los comentarios para comprender su código, deben reflexionar sobre el problema del código.

Finalmente, para el contenido de la anotación, "por qué lo hiciste" debería ser más importante que "qué hiciste".

4. Formato de comentario.

Comentarios de archivo: utilice el formato de comentarios generado automáticamente por Xcode.

//
//  AppDelegate.h
//  项目名称
//
//  Created by 开发者姓名 on 2018/6/8.
//  Copyright © 2018年 公司名称. All rights reserved.
//

Comentarios de importación: si hay más de una declaración de importación, estas declaraciones se agrupan. Los comentarios para cada grupo son opcionales .

// Framework
#import <UIKit/UIKit.h>

// Model
#import "WTUser.h"

// View
#import "WTView.h"

Comentario del método: después de Xcode8, la tecla de acceso directo se genera automáticamente (opción + comando + /).

/**
* <#Description#>
* @param application <#application description#>
* @param launchOptions <#launchOptions description#>
* @return <#return value description#>
*/
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

/// <#Description#> 
/// @param application <#application description#>
/// @param launchOptions <#launchOptions description#>
/// @return <#return value description#>

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

Comentarios del bloque de código: una sola línea comienza con "// + espacio o /// + espacio", y varias líneas usan "/* */".

/// + Espacios y /* */ métodos de comentarios aparecerán al llamar

Estructura y diseño del código.

  • Archivo de declaración: el orden de los métodos debe ser coherente con el orden del archivo de implementación. Utilice "#pragma mark -" para agrupar los métodos según sea necesario.
  • Archivo de implementación: los métodos deben agruparse con "#pragma mark -". Prioridad antes y después de la agrupación: método de ciclo de vida > método público > método de interfaz de usuario > método de datos > método de evento > método privado (procesamiento lógico, etc.) > método de delegado > método de anulación parcial > método de establecimiento > método de captador
#pragma mark - Lifecycle

- (instancetype)init {}
- (void)viewDidLoad {}
- (void)viewWillAppear:(BOOL)animated {}
- (void)viewDidAppear:(BOOL)animated {}
- (void)viewWillDisappear:(BOOL)animated {}
- (void)viewDidDisappear:(BOOL)animated {}
- (void)didReceiveMemoryWarning {}
- (void)dealloc {}

#pragma mark - Public

- (void)refreshData {}

#pragma mark - UI

- (void)initSubViews {}

#pragma mark - Data

- (void)initData {}
- (void)constructData {}

#pragma mark - Event

- (void)clickButton:(UIButton *)button {}

#pragma mark - Private

- (CGFloat)calculateHeight {}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {}

#pragma mark - Override

- (BOOL)needNavigationBar {}

#pragma mark - Setter

- (void)setWindow:(UIWindow *)window {}

#pragma mark - Getter

- (UIWindow *)window {}

Revisión de código

Los saltos de línea, los comentarios, la longitud del método, la duplicación de código, etc. son problemas que detectan las máquinas y no es necesario que los resuelvan los humanos.

Además de revisar el grado de implementación de los requisitos y si los errores no tienen dónde esconderse, también debes prestar más atención al diseño del código. Por ejemplo, el grado de acoplamiento entre clases, la escalabilidad y reutilización del diseño, si ciertos métodos se pueden extraer como interfaces, etc.

Supongo que te gusta

Origin blog.csdn.net/yezuiqingxin/article/details/120367074
Recomendado
Clasificación