iOS 生成七牛 Token

最近决定使用七牛云存储来管理app 中的资源文件。先吐槽一下七牛的文档那叫一个坑啊! 看文档,下载demo 看源码 全都说一半,看半天不明所以,三言两语说不完。

文章主要还是说一说在使用七牛sdk 中踩过得坑吧。七牛文件管理原理在此就不多说了。

七牛SDK 对文件的上传下载都需要一个token的玩意。文档只是说token通过服务器获取。一脸懵懂 ,哪个服务器啊,自己的还是七牛的不明所以。文档上也根本没说客服端怎么生成token,说是不安全,但七牛也不反对客服端生成token,只是说不安全原因,推荐服务器生成回传。但即便这样你别惜字如金至少也要写的清楚点才叫文档吧。最后找了半天总算找到七牛在线的token生成器:戳这里

1720EFBE-B166-43CC-B4E3-5060A0E5A6B6

几个有用的地方已经标出,都是必有的。

ak和sk在空的密钥里可以找到。如图:

Screen+Shot+2016-05-19+at+4.01.46+PM

buckename是之前申请的域名,比如我申请的测试域名是test.qiniudn.com,那么buckename就是test。key是上传的文件名,虽然这里属性是可选,但作为使用者上传了肯定要有个名字以便以后获取下载。填写好需要的信息就可以生成uploadtoken,下图是生成的效果图

AE401719-4130-4AAA-B2A5-6EAA29A3E66F

然后就是demo的修改,整个demo只需要修改两个地方就可以上传到个人申请的空间,不需要修改任何url,七牛是按照buckename找到你申请的空间的

1.- (void)viewDidLoad方法中修改self.token的值,修改为上图生成的token,

2.- (IBAction)simpleUpload:(id)sender上传触发方法修改_filePath和key

[self.sUploader uploadFile:_filePath key:@”daohanglan@2x.png” extra:nil];

_filePath确定是要上传文件的路径,key是要上传文件的文件名,我上传的是一张图片,这里写的应该比较清楚。

上传完成之后可以查询自己的空间

 

cocospod 安装和使用

安装前准备

ruby 安装

要安装coocspod 首先需要安装ruby,可以先安装xcode,在安装macport 下载地址,最后执行命令 port install ruby

安装CocoaPods

1、安装

CocoaPods是用Ruby实现的,要想使用它首先需要有Ruby的环境。幸运的是OS X系统默认的已经可以运行Ruby了,因此我们只需要执行以下命令:

sudo gem install cocoapods

CocoaPods是以Ruby gem包的形式被安装的。在安装执行的过程中,可能会问我们是不是更新rake,输入y即可。这是因为rake gem包会在安装的过程中检查更细,如果有可用的新版本就会出现刚才的选项。

在安装进程结束的时候,执行命令:

pod setup  

顺利执行完成 安装就成功了!

 

安装过程中可能遇到的问题

执行完install命令半天没反应

或报错

$ sudo gem install cocoapods
Password:
ERROR:  Could not find a valid gem 'cocoapods' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - Errno::ETIMEDOUT: Operation timed out - connect(2) (https://rubygems.org/latest_specs.4.8.gz)

这有可能是因为Ruby的默认源使用的是cocoapods.org,国内访问这个网址有时候会有问题,网上的一种解决方案是将远替换成淘宝的,替换方式如下:

第一步执行:

gem sources --remove https://rubygems.org/

返回结果:

https://rubygems.org/ removed from sources

第二步执行命令:

gem sources -a https://ruby.taobao.org/

返回:

https://ruby.taobao.org/ added to sources

验证是否执行成功

gem sources -l

结果:

*** CURRENT SOURCES ***

https://ruby.taobao.org/

 

升级gem

gem是管理Ruby库和程序的标准包,如果它的版本过低也可能导致安装失败,解决方案自然是升级gem,执行下述命令即可:

 sudo gem update --system  
sudo gem install cocoapods  

 

升级CocoaPods

升级很简单,再次执行安装命令即可:

 sudo gem install cocoapods  

需要注意的是,如果安装的时候使用了sudo,升级的时候一样需要使用该关键字,不然升级完了以后又会出现路径不匹配问题。

Homebrew的安装遇到400 Bad Request错误

本篇文章主要介绍了”Homebrew的安装遇到400 Bad Request错误”,主要涉及到方面的内容,对于IOS开发感兴趣的同学可以参考一下:

今天安装Homebrew时用如下命令:

ruby -e "$(curl -fsSL https://raw.github.com/mxcl/homebrew/go)"

出现

curl: (22) The requested URL returned error: 400 Bad Request

错误,修改如下命令就可以成功安装:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

 

Atom 安装插件报错 connect ETIMEDOUT

屏幕快照 2016-05-03 上午10.35.48

尝试了各种办法,翻墙也不行

最后找到了离线安装解决办法

cd ~/.atom/packages
git clone <你想安装的 Package 的仓库链接> # 比如:git clone https://atom.io/packages/emmet
cd <Package 路径> # cd emmet-atom
npm install

结果发现这个办法在 git clone 这一步又卡上了
屏幕快照 2016-05-03 上午11.29.47

总是提示失败

只好去git上把包下载下来

把下载好的安装包解压 活得到一个文件夹

把你下载好的package解压后放在

~/.atom/packages

路径下然后执行

npm install

离线安装成功

 

 

AFNetworking getting json value. URL doesn’t work

AFNetworking 请求时错误

Error Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/html" UserInfo=0x7fd35da285d0 {com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7fd35da37ea0> { URL: https://crm-staging.xiaoshouyi.com/mobile/pack/get-all-packs.action?_vs=1.0&appType=0&appVersion=1.0&inhouse=0&source=2 } { status code: 200, headers {

    "Cache-Control" = "no-cache";

    Connection = "keep-alive";

    "Content-Encoding" = gzip;

    "Content-Type" = "text/html;charset=UTF-8";

    Date = "Fri, 22 Apr 2016 08:23:14 GMT";

    Expires = "Thu, 01 Jan 1970 00:00:00 GMT";

    Pragma = "no-cache";

    Server = "nginx/1.8.0";

    "Set-Cookie" = "c-user=407138; Domain=.ingageapp.com; Path=/, JSESSIONID=AFDA5A7AB06D822234E740D5F9E3D0CE; Path=/mobile/; HttpOnly";

    "Transfer-Encoding" = Identity;

    Vary = "Accept-Encoding";

} }, NSErrorFailingURLKey=https://crm-staging.xiaoshouyi.com/mobile/pack/get-all-packs.action?_vs=1.0&appType=0&appVersion=1.0&inhouse=0&source=2, com.alamofire.serialization.response.error.data=<7b227363 6f646522 3a223022 2c22626f 6479223a 7b227365 6c656374 4964223a 31303031 2c227061 636b4c69 7374223a 5b7b2269 64223a31 35363839 382c226e 616d6522 3a224e65 77417070 222c2269 636f6e22 3a22706c 6174666f 726d5f69 636f5f79 696e6778 69616f22 7d2c7b22 6964223a 31303031 2c226e61 6d65223a 2243524d 222c2269 636f6e22 3a22706c 6174666f 726d5f69 636f5f63 726d227d 5d7d7d>, NSLocalizedDescription=Request failed: unacceptable content-type: text/html}

解决办法:

Serilization->AFURLResponseSerialization.m, 行数 215,

修改

以前代码

//    self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];

  self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil];

 

开发中遇到的路径问题

在工程师开发代码时或多或少都会遇到获取指定文件的路劲问题:

获取路劲一般有2种方法 相对路径和绝对路径

相对路径和绝对路径,往往都是初学者最困惑的知识点之一。

相对路径和绝对路径的定义:

(1)相对路径,就是在同一个网站下,不同文件之间的的位置定位。引用的文件是相对当前网页的位置而言的,根据这个相对位置得出相对路径。

(2)绝对路径,指的是完整的路径。

我画了一张简单路劲图表:

屏幕快照 2016-04-08 下午4.39.23

 

在找路劲时有几个符号,几个符号的含义:
/‘代表网站根目录:”/Images/SampleImage.jpg”
~‘代表应用程序根目录,~ 运算符只能为服务器控件识别,并且位于服务器代码中.不能将 ~ 运算符用于客户端元素. (根 root目录)
..‘代表上一级目录:”/Root/1/2″
.‘代表当前目录:”/Root/1/2/3″

‘../../’代表返回上上层目录 /Root

按照上图如果要找到 路劲中C 文件相对路劲写法

‘../../A/B/C’

 

 

 

使用ESLint做ReactNative的代码检查

使用ESLint做ReactNative的代码检查

效果如下:

官网:https://github.com/Intellicode/eslint-plugin-react-native

任意目录

1.安装eslint

npm install eslint

如果不行 绪执行全局命令

npm install -g eslint

 

2.安装eslint-plugin-react

npm install eslint-plugin-react

 

3.安装eslint-plugin-react-native

npm install eslint-plugin-react-native

安装后的目

/Users/当前用/platform/node_modules/eslint

4.在工程下增加配置文件

  eslint向模式:

eslint --init

行完后会生成 .eslintrc.js

5.编辑配置文件 .eslintrc.js

vi .eslintrc.js

按照官方文档配置:

增加plugins,增加react-native规则

module.exports = {

    "env": {

        "browser": false,

        "commonjs": true,

        "es6": true,

        "node": true

    },

    "extends": ["eslint:recommended","plugin:react/recommended"],

    "parserOptions": {

        "ecmaFeatures": {

            "experimentalObjectRestSpread": true,

            "jsx": true

        },

        "sourceType": "module"

    },

    "plugins": [

        "react",

        "react-native"

    ],

    "rules": {

        "indent": [

            "error",

            4

        ],

        "linebreak-style": [

            "error",

            "unix"

        ],

        "quotes": [

            "error",

            "single"

        ],

        "semi": [

            "error",

            "always"

        ],

        "react-native/no-unused-styles": 2,

         "react-native/split-platform-components": 2

    }

};

 6.覆盖

/Users/purple/platform/node_modules/eslint/lib/rules/ no-unused-vars.js

/**

* @fileoverview Rule to flag declared but unused variables

* @author Ilya Volodin

*/

"use strict";

//------------------------------------------------------------------------------

// Requirements

//------------------------------------------------------------------------------

var lodash = require("lodash");

//------------------------------------------------------------------------------

// Rule Definition

//------------------------------------------------------------------------------

module.exports = function(context) {

    var MESSAGE = "'{{name}}' is defined but never used";

    var config = {

        vars: "all",

        args: "after-used"

    };

    var firstOption = context.options[0];

    if (firstOption) {

        if (typeof firstOption === "string") {

            config.vars = firstOption;

        } else {

            config.vars = firstOption.vars || config.vars;

            config.args = firstOption.args || config.args;

            if (firstOption.varsIgnorePattern) {

                config.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern);

            }

            if (firstOption.argsIgnorePattern) {

                config.argsIgnorePattern = new RegExp(firstOption.argsIgnorePattern);

            }

        }

    }

    //--------------------------------------------------------------------------

    // Helpers

    //--------------------------------------------------------------------------

    /**

     * Determines if a given variable is being exported from a module.

     * @param {Variable} variable - EScope variable object.

     * @returns {boolean} True if the variable is exported, false if not.

     * @private

     */

    function isExported(variable) {

        var definition = variable.defs[0];

        if (definition) {

            var node = definition.node;

            if (node.type === "VariableDeclarator") {

                node = node.parent;

            } else if (definition.type === "Parameter") {

                return false;

            }

            return node.parent.type.indexOf("Export") === 0;

        } else {

            return false;

        }

    }

    /**

     * Determines if a reference is a read operation.

     * @param {Reference} ref - An escope Reference

     * @returns {Boolean} whether the given reference represents a read operation

     * @private

     */

    function isReadRef(ref) {

        return ref.isRead();

    }

    /**

     * Determine if an identifier is referencing an enclosing function name.

     * @param {Reference} ref - The reference to check.

     * @param {ASTNode[]} nodes - The candidate function nodes.

     * @returns {boolean} True if it's a self-reference, false if not.

     * @private

     */

    function isSelfReference(ref, nodes) {

        var scope = ref.from;

        while (scope) {

            if (nodes.indexOf(scope.block) >= 0) {

                return true;

            }

            scope = scope.upper;

        }

        return false;

    }

    /**

     * Determines if the variable is used.

     * @param {Variable} variable - The variable to check.

     * @param {Reference[]} references - The variable references to check.

     * @returns {boolean} True if the variable is used

     */

    function isUsedVariable(variable) {

        var functionNodes = variable.defs.filter(function(def) {

                return def.type === "FunctionName";

            }).map(function(def) {

                return def.node;

            }),

            isFunctionDefinition = functionNodes.length > 0;

        return variable.references.some(function(ref) {

            return isReadRef(ref) && !(isFunctionDefinition && isSelfReference(ref, functionNodes));

        });

    }

    /**

     * Gets an array of variables without read references.

     * @param {Scope} scope - an escope Scope object.

     * @param {Variable[]} unusedVars - an array that saving result.

     * @returns {Variable[]} unused variables of the scope and descendant scopes.

     * @private

     */

    function collectUnusedVariables(scope, unusedVars) {

        var variables = scope.variables;

        var childScopes = scope.childScopes;

        var i, l;

        if (scope.type !== "TDZ" && (scope.type !== "global" || config.vars === "all")) {

            for (i = 0, l = variables.length; i < l; ++i) {

                var variable = variables[i];

                // skip a variable of class itself name in the class scope

                if (scope.type === "class" && scope.block.id === variable.identifiers[0]) {

                    continue;

                }

                // skip function expression names and variables marked with markVariableAsUsed()

                if (scope.functionExpressionScope || variable.eslintUsed  || variables[i].eslintJSXUsed) {

                    continue;

                }

                // skip implicit "arguments" variable

                if (scope.type === "function" && variable.name === "arguments" && variable.identifiers.length === 0) {

                    continue;

                }

                // explicit global variables don't have definitions.

                var def = variable.defs[0];

                if (def) {

                    var type = def.type;

                    // skip catch variables

                    if (type === "CatchClause") {

                        continue;

                    }

                    if (type === "Parameter") {

                        // skip any setter argument

                        if (def.node.parent.type === "Property" && def.node.parent.kind === "set") {

                            continue;

                        }

                        // if "args" option is "none", skip any parameter

                        if (config.args === "none") {

                            continue;

                        }

                        // skip ignored parameters

                        if (config.argsIgnorePattern && config.argsIgnorePattern.test(def.name.name)) {

                            continue;

                        }

                        // if "args" option is "after-used", skip all but the last parameter

                        if (config.args === "after-used" && def.index < def.node.params.length - 1) {

                            continue;

                        }

                    } else {

                        // skip ignored variables

                        if (config.varsIgnorePattern && config.varsIgnorePattern.test(def.name.name)) {

                            continue;

                        }

                    }

                }

                if (!isUsedVariable(variable) && !isExported(variable)) {

                    unusedVars.push(variable);

                }

            }

        }

        for (i = 0, l = childScopes.length; i < l; ++i) {

            collectUnusedVariables(childScopes[i], unusedVars);

        }

        return unusedVars;

    }

    /**

     * Gets the index of a given variable name in a given comment.

     * @param {escope.Variable} variable - A variable to get.

     * @param {ASTNode} comment - A comment node which includes the variable name.

     * @returns {number} The index of the variable name's location.

     */

    function getColumnInComment(variable, comment) {

        var namePattern = new RegExp("[\\s,]" + lodash.escapeRegExp(variable.name) + "(?:$|[\\s,:])", "g");

        // To ignore the first text "global".

        namePattern.lastIndex = comment.value.indexOf("global") + 6;

        // Search a given variable name.

        var match = namePattern.exec(comment.value);

        return match ? match.index + 1 : 0;

    }

    /**

     * Creates the correct location of a given variables.

     * The location is at its name string in a `/*global` comment.

     *

     * @param {escope.Variable} variable - A variable to get its location.

     * @returns {{line: number, column: number}} The location object for the variable.

     */

    function getLocation(variable) {

        var comment = variable.eslintExplicitGlobalComment;

        var baseLoc = comment.loc.start;

        var column = getColumnInComment(variable, comment);

        var prefix = comment.value.slice(0, column);

        var lineInComment = (prefix.match(/\n/g) || []).length;

        if (lineInComment > 0) {

            column -= 1 + prefix.lastIndexOf("\n");

        } else {

            // 2 is for `/*`

            column += baseLoc.column + 2;

        }

        return {

            line: baseLoc.line + lineInComment,

            column: column

        };

    }

    //--------------------------------------------------------------------------

    // Public

    //--------------------------------------------------------------------------

    return {

        "Program:exit": function(programNode) {

            var unusedVars = collectUnusedVariables(context.getScope(), []);

            for (var i = 0, l = unusedVars.length; i < l; ++i) {

                var unusedVar = unusedVars[i];

                if (unusedVar.eslintExplicitGlobal) {

                    context.report({

                        node: programNode,

                        loc: getLocation(unusedVar),

                        message: MESSAGE,

                        data: unusedVar

                    });

                } else if (unusedVar.defs.length > 0) {

                    context.report({

                        node: unusedVar.identifiers[0],

                        message: MESSAGE,

                        data: unusedVar

                    });

                }

            }

        },

      "XJSIdentifier": function(node) {

         var scope = context.getScope(),

             variables = scope.variables,

             i,

             len;

         // mark XJSIdentifiers with a special flag

         for (i = 0, len = variables.length; i < len; i++) {

             if (variables[i].name === node.name) {

                 variables[i].eslintJSXUsed = true;

                 break;

             }

         }

     }

    };

};

module.exports.schema = [

    {

        "oneOf": [

            {

                "enum": ["all", "local"]

            },

            {

                "type": "object",

                "properties": {

                    "vars": {

                        "enum": ["all", "local"]

                    },

                    "varsIgnorePattern": {

                        "type": "string"

                    },

                    "args": {

                        "enum": ["all", "after-used", "none"]

                    },

                    "argsIgnorePattern": {

                        "type": "string"

                    }

                }

            }

        ]

    }

];

 

主要是解决es6下模块导入检查的BUG

增加了XJSIdentifier方法修复。

7.执行命令检查

eslint index.ios.js

 

规则命令:

"no-alert": 0,//禁止使用alert confirm prompt

"no-array-constructor": 2,//禁止使用数组构造器

"no-bitwise": 0,//禁止使用按位运算符

"no-caller": 1,//禁止使用arguments.caller或arguments.callee

"no-catch-shadow": 2,//禁止catch子句参数与外部作用域变量同名

"no-class-assign": 2,//禁止给类赋值

"no-cond-assign": 2,//禁止在条件表达式中使用赋值语句

"no-console": 2,//禁止使用console

"no-const-assign": 2,//禁止修改const声明的变量

"no-constant-condition": 2,//禁止在条件中使用常量表达式 if(true) if(1)

"no-continue": 0,//禁止使用continue

"no-control-regex": 2,//禁止在正则表达式中使用控制字符

"no-debugger": 2,//禁止使用debugger

"no-delete-var": 2,//不能对var声明的变量使用delete操作符

"no-div-regex": 1,//不能使用看起来像除法的正则表达式/=foo/

"no-dupe-keys": 2,//在创建对象字面量时不允许键重复 {a:1,a:1}

"no-dupe-args": 2,//函数参数不能重复

"no-duplicate-case": 2,//switch中的case标签不能重复

"no-else-return": 2,//如果if语句里面有return,后面不能跟else语句

"no-empty": 2,//块语句中的内容不能为空

"no-empty-character-class": 2,//正则表达式中的[]内容不能为空

"no-empty-label": 2,//禁止使用空label

"no-eq-null": 2,//禁止对null使用==或!=运算符

"no-eval": 1,//禁止使用eval

"no-ex-assign": 2,//禁止给catch语句中的异常参数赋值

"no-extend-native": 2,//禁止扩展native对象

"no-extra-bind": 2,//禁止不必要的函数绑定

"no-extra-boolean-cast": 2,//禁止不必要的bool转换

"no-extra-parens": 2,//禁止非必要的括号

"no-extra-semi": 2,//禁止多余的冒号

"no-fallthrough": 1,//禁止switch穿透

"no-floating-decimal": 2,//禁止省略浮点数中的0 .5 3.

"no-func-assign": 2,//禁止重复的函数声明

"no-implicit-coercion": 1,//禁止隐式转换

"no-implied-eval": 2,//禁止使用隐式eval

"no-inline-comments": 0,//禁止行内备注

"no-inner-declarations": [2, "functions"],//禁止在块语句中使用声明(变量或函数)

"no-invalid-regexp": 2,//禁止无效的正则表达式

"no-invalid-this": 2,//禁止无效的this,只能用在构造器,类,对象字面量

"no-irregular-whitespace": 2,//不能有不规则的空格

"no-iterator": 2,//禁止使用__iterator__ 属性

"no-label-var": 2,//label名不能与var声明的变量名相同

"no-labels": 2,//禁止标签声明

"no-lone-blocks": 2,//禁止不必要的嵌套块

"no-lonely-if": 2,//禁止else语句内只有if语句

"no-loop-func": 1,//禁止在循环中使用函数(如果没有引用外部变量不形成闭包就可以)

"no-mixed-requires": [0, false],//声明时不能混用声明类型

"no-mixed-spaces-and-tabs": [2, false],//禁止混用tab和空格

"linebreak-style": [0, "windows"],//换行风格

"no-multi-spaces": 1,//不能用多余的空格

"no-multi-str": 2,//字符串不能用\换行

"no-multiple-empty-lines": [1, {"max": 2}],//空行最多不能超过2行

"no-native-reassign": 2,//不能重写native对象

"no-negated-in-lhs": 2,//in 操作符的左边不能有!

"no-nested-ternary": 0,//禁止使用嵌套的三目运算

"no-new": 1,//禁止在使用new构造一个实例后不赋值

"no-new-func": 1,//禁止使用new Function

"no-new-object": 2,//禁止使用new Object()

"no-new-require": 2,//禁止使用new require

"no-new-wrappers": 2,//禁止使用new创建包装实例,new String new Boolean new Number

"no-obj-calls": 2,//不能调用内置的全局对象,比如Math() JSON()

"no-octal": 2,//禁止使用八进制数字

"no-octal-escape": 2,//禁止使用八进制转义序列

"no-param-reassign": 2,//禁止给参数重新赋值

"no-path-concat": 0,//node中不能使用__dirname或__filename做路径拼接

"no-plusplus": 0,//禁止使用++,--

"no-process-env": 0,//禁止使用process.env

"no-process-exit": 0,//禁止使用process.exit()

"no-proto": 2,//禁止使用__proto__属性

"no-redeclare": 2,//禁止重复声明变量

"no-regex-spaces": 2,//禁止在正则表达式字面量中使用多个空格 /foo bar/

"no-restricted-modules": 0,//如果禁用了指定模块,使用就会报错

"no-return-assign": 1,//return 语句中不能有赋值表达式

"no-script-url": 0,//禁止使用javascript:void(0)

"no-self-compare": 2,//不能比较自身

"no-sequences": 0,//禁止使用逗号运算符

"no-shadow": 2,//外部作用域中的变量不能与它所包含的作用域中的变量或参数同名

"no-shadow-restricted-names": 2,//严格模式中规定的限制标识符不能作为声明时的变量名使用

"no-spaced-func": 2,//函数调用时 函数名与()之间不能有空格

"no-sparse-arrays": 2,//禁止稀疏数组, [1,,2]

"no-sync": 0,//nodejs 禁止同步方法

"no-ternary": 0,//禁止使用三目运算符

"no-trailing-spaces": 1,//一行结束后面不要有空格

"no-this-before-super": 0,//在调用super()之前不能使用this或super

"no-throw-literal": 2,//禁止抛出字面量错误 throw "error";

"no-undef": 1,//不能有未定义的变量

"no-undef-init": 2,//变量初始化时不能直接给它赋值为undefined

"no-undefined": 2,//不能使用undefined

"no-unexpected-multiline": 2,//避免多行表达式

"no-underscore-dangle": 1,//标识符不能以_开头或结尾

"no-unneeded-ternary": 2,//禁止不必要的嵌套 var isYes = answer === 1 ? true : false;

"no-unreachable": 2,//不能有无法执行的代码

"no-unused-expressions": 2,//禁止无用的表达式

"no-unused-vars": [2, {"vars": "all", "args": "after-used"}],//不能有声明后未被使用的变量或参数

"no-use-before-define": 2,//未定义前不能使用

"no-useless-call": 2,//禁止不必要的call和apply

"no-void": 2,//禁用void操作符

"no-var": 0,//禁用var,用let和const代替

"no-warning-comments": [1, { "terms": ["todo", "fixme", "xxx"], "location": "start" }],//不能有警告备注

"no-with": 2,//禁用with

"array-bracket-spacing": [2, "never"],//是否允许非空数组里面有多余的空格

"arrow-parens": 0,//箭头函数用小括号括起来

"arrow-spacing": 0,//=>的前/后括号

"accessor-pairs": 0,//在对象中使用getter/setter

"block-scoped-var": 0,//块语句中使用var

"brace-style": [1, "1tbs"],//大括号风格

"callback-return": 1,//避免多次调用回调什么的

"camelcase": 2,//强制驼峰法命名

"comma-dangle": [2, "never"],//对象字面量项尾不能有逗号

"comma-spacing": 0,//逗号前后的空格

"comma-style": [2, "last"],//逗号风格,换行时在行首还是行尾

"complexity": [0, 11],//循环复杂度

"computed-property-spacing": [0, "never"],//是否允许计算后的键名什么的

"consistent-return": 0,//return 后面是否允许省略

"consistent-this": [2, "that"],//this别名

"constructor-super": 0,//非派生类不能调用super,派生类必须调用super

"curly": [2, "all"],//必须使用 if(){} 中的{}

"default-case": 2,//switch语句最后必须有default

"dot-location": 0,//对象访问符的位置,换行的时候在行首还是行尾

"dot-notation": [0, { "allowKeywords": true }],//避免不必要的方括号

"eol-last": 0,//文件以单一的换行符结束

"eqeqeq": 2,//必须使用全等

"func-names": 0,//函数表达式必须有名字

"func-style": [0, "declaration"],//函数风格,规定只能使用函数声明/函数表达式

"generator-star-spacing": 0,//生成器函数*的前后空格

"guard-for-in": 0,//for in循环要用if语句过滤

"handle-callback-err": 0,//nodejs 处理错误

"id-length": 0,//变量名长度

"indent": [2, 4],//缩进风格

"init-declarations": 0,//声明时必须赋初值

"key-spacing": [0, { "beforeColon": false, "afterColon": true }],//对象字面量中冒号的前后空格

"lines-around-comment": 0,//行前/行后备注

"max-depth": [0, 4],//嵌套块深度

"max-len": [0, 80, 4],//字符串最大长度

"max-nested-callbacks": [0, 2],//回调嵌套深度

"max-params": [0, 3],//函数最多只能有3个参数

"max-statements": [0, 10],//函数内最多有几个声明

"new-cap": 2,//函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用

"new-parens": 2,//new时必须加小括号

"newline-after-var": 2,//变量声明后是否需要空一行

"object-curly-spacing": [0, "never"],//大括号内是否允许不必要的空格

"object-shorthand": 0,//强制对象字面量缩写语法

"one-var": 1,//连续声明

"operator-assignment": [0, "always"],//赋值运算符 += -=什么的

"operator-linebreak": [2, "after"],//换行时运算符在行尾还是行首

"padded-blocks": 0,//块语句内行首行尾是否要空行

"prefer-const": 0,//首选const

"prefer-spread": 0,//首选展开运算

"prefer-reflect": 0,//首选Reflect的方法

"quotes": [1, "single"],//引号类型 `` "" ''

"quote-props":[2, "always"],//对象字面量中的属性名是否强制双引号

"radix": 2,//parseInt必须指定第二个参数

"id-match": 0,//命名检测

"require-yield": 0,//生成器函数必须有yield

"semi": [2, "always"],//语句强制分号结尾

"semi-spacing": [0, {"before": false, "after": true}],//分号前后空格

"sort-vars": 0,//变量声明时排序

"space-after-keywords": [0, "always"],//关键字后面是否要空一格

"space-before-blocks": [0, "always"],//不以新行开始的块{前面要不要有空格

"space-before-function-paren": [0, "always"],//函数定义时括号前面要不要有空格

"space-in-parens": [0, "never"],//小括号里面要不要有空格

"space-infix-ops": 0,//中缀操作符周围要不要有空格

"space-return-throw-case": 2,//return throw case后面要不要加空格

"space-unary-ops": [0, { "words": true, "nonwords": false }],//一元运算符的前/后要不要加空格

"spaced-comment": 0,//注释风格要不要有空格什么的

"strict": 2,//使用严格模式

"use-isnan": 2,//禁止比较时使用NaN,只能用isNaN()

"valid-jsdoc": 0,//jsdoc规则

"valid-typeof": 2,//必须使用合法的typeof的值

"vars-on-top": 2,//var必须放在作用域顶部

"wrap-iife": [2, "inside"],//立即执行函数表达式的小括号风格

"wrap-regex": 0,//正则表达式字面量用小括号包起来

"yoda": [2, "never"]//禁止尤达条件

 

终极 Shell 不同体验的 Terminal

终极 Shell
zsh – 给你的Mac不同体验的Terminal!

Shell介绍 点击这里

zsh 安装 戳这里

更换你的主题

 zsh系统默认主题

屏幕快照 2016-04-01 上午10.33.13

如果你要更换你的主题的话,只要修改 ~/.zshrc里的 ZSH_THEME=”prose” 引号部分主题名称即可。

修改命令

vi ~/.zshrc

修改文件中主题名称

ZSH_THEME=”prose”

重启

Terminal

iOS高级编程规范


iOS高级编程规范

* * *

# &lt;a name="1" id="1"&gt;iOS架构设计与分层&lt;/a&gt;

架构的几个原则,根据优先次序高低排列:

1.(逻辑)拆分越细越好
  1. 依赖关细越少越好
  2. 交互越少越好 … (交互是指项目中页面逻辑跳转并非交互设计) 这样做有如下几点好处:
  3. 对于大中型软件,层次越多,每一层就更单纯,更容易维护。
    `*   团队成员只需了解一小部分业务,就能顺利进行开发。
    *   相对底层的模块,可以更好的重用。
    *   层次分的越多,开发者对抽象的理解就更深入。
    
    `
* * *

项目工程目录MVC架构
  • 建立Request文件夹,存放网络请求
  • 建立Model工程 DataSource对于数据的抽象,不需要知道它是从网络、数据库还是缓存中得到的。 存放数据存储管理类 网络请求解析封装类
  • 建立Libs(Library)文件夹,存放第三方库
  • 建立Tools文件夹,存放自己封装的类库 通常在Tools文件下还会分为 扩展(categories)类与 自定义封装类
  • 建立Constant文件,放在底层目录,用于 存放常量, 宏定义文件, 全局单例等
  • 建立Views文件夹,分TableCell,与工程View 存放列表Cell,item, 工程所需View
  • 建立BaseViewController,放在底层公共目录
  • 建立ViewControllers文件夹,存放所有的ViewControl 每个Controller页面同样可有对应的管理文件
  • 在SupportingFiles文件夹下建立 Images、Music和Video等相关文件夹, 分别存放图片、 音频、 视频等资源。 示例:
* * *

iOS命名规则

* * *

代码命名基础知识
<pre>`**[苹果官方问的命名规范][1]**

**命名规范**

1、类名、协议名:遵循大驼峰命名法; 2、常量:这里的常量指的是宏(#define)、枚举(enum)、常量(const)等,使用小写”k“作为前缀,名称遵循大驼峰命名法。 3、方法
`</pre>
  • 方法名和方法参数遵循相同的规则,使用小写开头的小驼峰法;
  • 方法名和参数尽量读起来像是一句话;
  • 方法名不允许使用“get“前缀;
  • -或+与返回类型间留一个空格,但参数列表之间不要留间隔;
  • 如果参数过多,推荐每个参数各占一行; 4、变量: 类成员变量,属性,局部变量,使用小写开头的小驼峰法,其中类成员变量在名称最后加一个下划线,比如:myLovalVariable, myInstanceVariable ;变量名的名称尽量可以推测其用途,具有描述性。 例如:
    `    -(void)doSomethingWithString:(NSString

    )theString(NSInteger _)theInteger { … } ; ` 示例:

    <a name=”2.2″ id=”2.2″>代码命名原则</a>

    1.1 清晰

    尽量清晰又简洁,无法两全时清晰更重要 例如: 通常不应缩写名称,即使方法名很长也应完整拼写 你可能认为某个缩写众所周知,但其实未必,特别是你周围的开发者语言文化背景不同时 有一些历史悠久的缩写还是可以使用的 API命名避免歧义,例如一个方法名有多种理解

  • 1.2一致

    尽力保持Cocoa编程接口命名一致 如果有疑惑,请浏览当前头文件或者参考文档 当某个类的方法使用了多态时,一致性尤其重要 不同类里,功能相同的方法命名也应相同

    1.3 避免自引用(self Reference)

    命名不应自引用 这里的自引用指的是在词尾引用自身 Mask与Notification忽略此规则

    <a name=”2.3″ id=”2.3″>前缀</a>

    前缀是编程接口命名的重要部分,它们区分了软件的不同功能区域: 前缀可以防止第三方开发者与Apple的命名冲突 同样可以防止Apple内部的命名冲突 前缀有指定格式 它由二到三个大写字母组成,不使用下划线和子前缀 命名类、协议、函数、常量和typedef结构体时使用前缀 方法名不使用前缀(因为它存在于特定类的命名空间中) 结构体字段不使用前缀

    <a name=”2.4″ id=”2.4″>书写约定</a>

    在命名API元素时, 使用驼峰命名法(如runTheWordsTogether),并注意以下书写约定: 小驼峰命名法(CamelCase):第一个单词小写字母开头,其他单词首字母大写; 大驼峰命名法(PascalCase):所有首字母大写。

    方法名

    小写第一个字母,大写之后所有单词的首字母,不使用前缀 如果方法名以一个众所周知的大写缩略词开始,该规则不适用 避免使用下划线作为前缀,有意思私人的方法名(使用下划线字符作为一个实例变量名称的前缀是允许的) 。苹果公司保留使用这种约定。由第三方使用可能会导致命名空间冲突;他们可能会无意中覆盖现有的私有方法有一个属于自己的类,这会具有灾难性的后果。查看约定私有方法的建议,遵循私有API 。 如:

    `fileExistsAtPath:isDirectory:`

    对于函数和常量的名称,使用相同的前缀相关类和大写的​​单词首字母。

    `NSRunAlertPanel
     NSCellDisabled`

    #### 标点符号 由多个单词组成的名称,别使用标点符号作为名称的一部分 分隔符(下划线、破折号等)也不能使用 避免使用下划线作为私有方法的前缀,Apple保留这一方式的使用 强行使用可能会导致命名冲突,即Apple已有的方法被覆盖,这会导致灾难性后果 实例变量使用下划线作为前缀还是允许的 ## <a name=”2.5″ id=”2.5″>类和协议的名称</a> class class的名称应该包含一个名词,用以表明这个类是什么(或者做了什么),并拥有合适的前缀 如NSString、NSDate、NSScanner、UIApplication、UIButton 不关联class的protocol 大多数protocol聚集了一堆相关方法,并不关联class 这种protocol使用ing形式以和class区分开来 ![](http://192.168.0.102:7000/iOS/iOS/uploads/c940e72fa65be20b237e9e62ff193863/link-6.png) 关联class的protocol 一些protoco聚集了一堆无关方法,并试图与某个class关联在一起,由这个class来主导 这种protocol与class同名 如NSObject protocol ## <a name=”2.6″ id=”2.6″>头文件</a> 头文件的命名极其重要,因为它可以指出头文件包含的内容: 声明一个孤立的class或protocol 将声明放入单独的文件 使头文件名与声明的class/protocol相同 ![](http://192.168.0.102:7000/iOS/iOS/uploads/1cbbd16b788f47476100b105b5616d42/headerFile.png) 声明关联的class或protocol 将关联的声明(class/category/protocol)放入同一个头文件 头文件名与主要的class/category/protocol相同 图中能 NSString 包含了NSString 和NSMutableString Classes NSLock.h 包含NSLocking protocol 和NSLock,NSConditionLock,NSrecursiveLock Classes![](http://192.168.0.102:7000/iOS/iOS/uploads/4a9bc6226f8c686a9b8a7f9c423c3bdb/headerFile1.png) Framework头文件 每个framework都应该有一个同名头文件 Include了框架内其他所有头文件 ![](http://192.168.0.102:7000/iOS/iOS/uploads/1a4284f3baf9625c1d40e6a54a9d2d07/headerFile2.png) 添加API到另一个framework 如果要在一个framework中为另一个framework的class catetgory添加方法,加上单词“Additions” 如Application Kit的NSBundleAdditions.h 文件 关联的函数、数据类型 如果你有一组关联的函数、常量、结构体或其他数据类型,将它们放到一个名字合适的头文件中 如Application Kit的NSGraphics.h ## <a name=”2.7″ id=”2.7″>命名方法</a> #### 1.通用原则 以小写字母开始,之后单词的首字母大写 以众所周知的缩写开始可以大写,如TIFF、PDF 私有方法可以加前缀 如果方法代表对象接收的动作,以动词开始 不要使用 do 或 does 作为名字的一部分,因为助动词在这里很少有实际意义 同样的,也别在动词之前使用副词和形容词 如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用 do , does 这 种多余的关键字,动词本身的暗示就足够了:

    ` // 动词打头的方法表示让对象执行一个动作
    *   (void)invokeWithTarget:(id)target;
    
    • (void)selectTabViewItem:(NSTabViewItem *)tabViewItem; &lt;/pre&gt; 如果方法是为了获取对象的一个属性值,直接用属性名称来命名这个方法,注意不要添加 get 或者其他的动词前缀: 应该,使用属性名来命名方法 &lt;pre&gt; – (NSSize)cellSize; &lt;/pre&gt; 不应该,添加了多余的动词前缀 &lt;pre&gt; – (NSSize)calcCellSize;
    • (NSSize)getCellSize; &lt;/pre&gt; 对于有多个参数的方法,务必在每一个参数前都添加关键词,关键词应当清晰说明参数的作用 &lt;pre&gt; // 应该,保证每个参数都有关键词修饰
    • (void)sendAction:(SEL)aSelector toObject:(id)anObject forAllCells:(BOOL)flag; // 不应该,遗漏关键词
    • (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag; // 应该
    • (id)viewWithTag:(NSInteger)aTag; // 不应该,关键词的作用不清晰
    • (id)taggedView:(int)aTag; &lt;/pre&gt; 不要用 and 来连接两个参数,通常 and 用来表示方法执行了两个相对独立的操作(从设计上来说,这时候应 &lt;pre&gt; // 应该,不要使用 “and” 来连接参数
    • (int)runModalForDirectory:(NSString )path andFile:(NSString )name andTypes:(NSArray *)fileTypes; // 不应该,使用 “and” 来表示两个相对独立的操作
    • (BOOL)openFile:(NSString )fullPath withApplication:(NSString )appName andDeactivate:(BOOL)flag; `

      <a name=”2.8″ id=”2.8″>方法的参数</a>

      方法的参数命名也有一些需要注意的地方 :

  • 和方法名类似,参数的第一个字母小写,后面的每一个单词首字母大写
    *   不要再方法名中使用类似 pointer,ptr这样的字眼去表示指针,参数本身的类型足以说明
    *   不要使用只有一两个字母的参数名
    *   不要使用简写,拼出完整的单词
    
    • 下面列举了一些常用参数名:
      ...action:(SEL)aSelector
      ...alignment:(int)mode
      ...atIndex:(int)index
      ...content:(NSRect)aRect
      ...doubleValue:(double)aDouble
      ...floatValue:(float)aFloat
      ...font:(NSFont *)fontObj
      ...frame:(NSRect)frameRect
      ...intValue:(int)anInt
      ...keyEquivalent:(NSString *)charCode
      ...length:(int)numBytes
      ...point:(NSPoint)aPoint
      ...stringValue:(NSString *)aString
      ...tag:(int)anInt
      ...target:(id)anObject
      ...title:(NSString *)aString

      <a name=”2.9″ id=”2.9″>委托方法</a>

      委托方法 (或委派方法) 是指那些对象调用在其委托 (如果委托实现他们) 发生某些事件时。他们有一种独特的形式,这同样适用于调用对象的数据源中的方法: 开始通过确定发送消息的对象的类的名称: 省略了前缀的类名和首字母小写

      ` - (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
          *   (BOOL)application:(NSApplication _)sender openFile:(NSString _)filename; `&lt;/pre&gt; 类名称省略前缀,第一个字母是小写。 除非该方法仅有一个参数,发件人一个冒号被贴的类别名称 (参数对委托对象的引用)。 以发送消息的对象开始的规则不适用下列两种情况 只有一个sender参数的方法 &lt;pre&gt;` - (BOOL)applicationOpenUntitledFile:(NSApplication _)sender; `&lt;/pre&gt; 响应notification的方法(方法的唯一参数就是notification) &lt;pre&gt;` - (void)windowDidChangeScreen:(NSNotification _)notification; `&lt;/pre&gt; 使用单词 did 和 will 来通知delegate "did"will"用于调用以通知委托, did 表示某些事已发生 will 表示某些事将要发生 &lt;pre&gt;` - (void)browserDidScroll:(NSBrowser *)sender;
      
      • (NSUndoManager )windowWillReturnUndoManager:(NSWindow )window; &lt;/pre&gt; 虽然您可以使用"did"或"will"方法被调用时,要问要做代表另一个对象的委托,"should"是首选。 &lt;pre&gt; – (BOOL)windowShouldClose:(id)sender; ` 询问delegate是否可以执行某个行为时可以使用 did 或 will,不过 should 更完美

        <a name=”3.0″ id=”3.0″>集合方法</a>

        为了管理集合中的元素,集合应该有这几个方法

  • (void)addElement:(elementType)anObj;
  • (void)removeElement:(elementType)anObj;
  • (NSArray )elements;例如:
    ` - (void)addLayoutManager:(NSLayoutManager

    )obj;

    *   (void)removeLayoutManager:(NSLayoutManager *)obj;
    
    • (NSArray )layoutManagers; &lt;/pre&gt; 如果集合是无序的,返回一个NSSet比NSarray更好 如果需要在集合中的特定位置插入元素,使用类似下面的方法 &lt;pre&gt; – (void)insertLayoutManager:(NSLayoutManager )obj atIndex:(int)index;
    • (void)removeLayoutManagerAtIndex:(int)index; &lt;/pre&gt; 有对与的实现细节要牢记集合方法: 这些方法通常意味着插入对象的所有权,因此添加或插入他们的代码必须保留它们,并删除他们的代码也必须释放他们。 如果插入的对象需要有指针恢复为主要对象,你这样做 (通常) 一套...方法设置回指针,但不会保留。在 insertLayoutManager:atIndex: NSLayoutManager 类的方法,就是这样在这些方法中: &lt;pre&gt; – (void)setTextStorage:(NSTextStorage *)textStorage;
    • (NSTextStorage )textStorage; &lt;/pre&gt; 你通常不会将 setTextStorage: 直接,但可能要重写它。 收集方法的上述约定的另一个例子来自 NSWindow 类: &lt;pre&gt; – (void)addChildWindow:(NSWindow )childWin ordered:(NSWindowOrderingMode)place;
    • (void)removeChildWindow:(NSWindow *)childWin;
    • (NSArray *)childWindows;
    • (NSWindow *)parentWindow;
    • (void)setParentWindow:(NSWindow *)window; `

      <a name=”3.1″ id=”3.1″>getter和setter方法( Accessor Methods )</a>

      getter和setter方法是指用来获取和设置类属性值的方法,属性的不同类型,对应着不同的存取方法规范:

      ` // 属性是一个名词时的存取方法范式
    • (type)noun;
    • (void)setNoun:(type)aNoun; // 例子
    • (NSString *)title;
    • (void)setTitle:(NSString *)aTitle; // 属性是一个形容词时存取方法的范式
    • (NSString *)title;
    • (void)setTitle:(NSString *)aTitle; // 例子
    • (BOOL)isAdjective;
    • (void)setAdjective:(BOOL)flag; // 属性是一个动词时存取方法的范式
    • (BOOL)verbObject;
    • (void)setVerbObject:(BOOL)flag; // 例子
    • (BOOL)showsAlpha;
    • (void)setShowsAlpha:(BOOL)flag; &lt;/pre&gt; getter和setter方法时不要将动词转化为被动形式来使用: &lt;pre&gt; // 正确
    • (void)setAcceptsGlyphInfo:(BOOL)flag;
    • (BOOL)acceptsGlyphInfo; // 错误,不要使用动词的被动形式
    • (void)setGlyphInfoAccepted:(BOOL)flag;
    • (BOOL)glyphInfoAccepted; `

      <a name=”3.2″ id=”3.2″>私有方法</a>

      不要使用下划线作为私有方法的前缀,Apple保留这一使用方式 因为若是你的私有方法名已被Apple使用,覆盖它将会产生极难追踪的BUG 如果继承自大型Cocoa框架(如UIView),请确保子类的私有方法名与父类不一样 可以为私有方法加一个前缀,如公司名或项目名:XX_ 例如你的项目叫做Byte Flogger,那么前缀可能是:BF_addObject 总之,为子类的私有方法添加前缀是为了不覆盖其父类的私有方法

      <a name=”3.3″ id=”3.3″>函数</a>

      函数的命名类似方法,但有两点要注意 你使用的类和常量拥有相同的前缀 前缀后的首字母大写 许多函数名以描述其作用的动词开始

      NSHighlightRect
      NSDeallocateObjec

      查询属性的函数有进一步的命名规则 如果函数返回首个参数的属性,省略动词

      unsigned int NSEventMaskFromType(NSEventType type)
      float NSHeight(NSRect aRect)

      如果通过reference返回了值,使用 “Get”

      const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)

      如果返回的是boolean值,应该灵活使用动词

      BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)

      <a name=”A1″ id=”A1″>声明属性和实例变量</a>

      <a name=”A1.1″ id=”A1.1″>Property</a>

      Property命名规则与第二章accessor methods一样(因为两者紧密联系) 如果property表示为一个名词或动词,格式如下 @property (…) 类型 名词/动词 ;

      @property (strong) NSString *title;
      @property (assign) BOOL showsAlpha;

      如果property表示为一个形容词 可省略 ”is” 前缀 但要指定getter方法的惯用名称

      @property (assign, getter=isEditable) BOOL editable;

      <a name=”A1.2″ id=”A1.2″>实例变量</a>

      通常不应该直接访问实例变量 init、dealloc、accessor methods等方法内部例外 实例变量以下划线 “_” 开始 确保实例变量描述了所存储的属性

      @implementation MyClass {
      BOOL _showsTitle;
      }

      如果想要修改property的实例变量名,使用 @synthesize语句

      @implementation MyClass
      @synthesize showsTitle=_showsTitle;

      为一个class添加实例变量时,有几点需要注意: 避免声明公有实例变量 开发者关注的应该是对象接口,而不是其数据细节 你可以通过使用property来避免声明实例变量 如果需要声明实例变量,指定关键字@private 或 @protected 如果你希望子类可以直接访问某个实例变量,使用 @protected 关键字 如果一个实例变量是某个类可访问的属性,确保写了accessor methods 如果有可能,还是使用property

      <a name=”A2″ id=”A2″>常量</a>

      <a name=”A2.1″ id=”A2.1″>枚举常量</a>

      使用枚举来关联一组integer常量 枚举常量和typedef遵循函数的命名规范,下面的例子是 NSMatrix.h

      typedef enum _NSMatrixMode {
      NSRadioModeMatrix = 0,
      NSHighlightModeMatrix = 1,
      NSListModeMatrix = 2,
      NSTrackModeMatrix = 3
      } NSMatrixMode;

      Typedef 标记 (在上述示例中的 _NSMatrixMode) 是不必要的注意。 你可以为bit masks之类的东西创建一个匿名枚举

      enum {
      NSBorderlessWindowMask = 0,
      NSTitledWindowMask = 1 &amp;amp;lt;&amp;amp;lt; 0,
      NSClosableWindowMask = 1 &amp;amp;lt;&amp;amp;lt; 1,
      NSMiniaturizableWindowMask = 1 &amp;amp;lt;&amp;amp;lt; 2,
      NSResizableWindowMask = 1 &amp;amp;lt;&amp;amp;lt; 3
      };

      <a name=”A2.2″ id=”A2.2″>使用const创建的常量</a>

      使用const关键字的常量 使用const关键字来创建一个float常量 你可以使用const关键字来创建一个与其他常量不相关的integer常量,否则,使用枚举 使用const关键字的常量也遵循函数的命名规则

      const float NSLightGray;

      <a name=”A2.3″ id=”A2.3″>其他类型的常量</a>

      通常不应使用 #define 预编译指令来创建常量 integer常量,使用枚举 float常量,使用 const 修饰符 对 #define 预编译指令,大写所有字母 比如 DEBUG 判断

      #ifdef DEBUG

      注意的时,cocoa官网宏 字首和字尾都有双下划线

      __MACH__

      定义NSString常量来作为Notification和Key值 这样做可以有效防止拼写错误

      APPKIT_EXTERN NSString *NSPrintCopies;

      <a name=”A3″ id=”A3″>通知和异常</a>

      <a name=”A3.1″ id=”A3.1″>通知</a>

      Notification的格式 类/头文件名+进行状态+通知名称+Notification

      [Name of associated class] + [Did | Will] + [UniquePartOfName] + Notification

      如:

      NSApplicationDidBecomeActiveNotification
      NSWindowDidMiniaturizeNotification
      NSTextViewDidChangeSelectionNotification
      NSColorPanelColorDidChangeNotificatio

      <a name=”A3.2″ id=”A3.2″>异常</a>

      异常格式 头+定义名称+Exception

      [Prefix] + [UniquePartOfName] + Exception

      例如

      NSColorListIOException
      NSColorListNotEditableException
      NSDraggingException
      NSFontUnavailableException
      NSIllegalSelectorException

      <a name=”A3.3″ id=”A3.3″>ios缩写</a>

      <a name=”A4″ id=”A4″>iOS代码规范</a>

      指针 “ * ” 号的位置

      如:

      NSString *varName;

      <a name=”A4.1″ id=”A4.1″>代码书写格式</a>

  • 使用空格而不是制表符 Tab 不要在工程里使用 Tab 键,使用空格来进行缩进。在 Xcode > Preferences > Text Editing 将 Tab 和自动缩进都设置为 2 个空格。(Google 的标准是使用两个空格来缩进,但这里还是推荐使用 Xcode 默认的设置。)方法大括号和其他大括号(if/else/switch/while 等.)总是在同一行语句打开但在新行中关闭。
    应该
     if (user.isHappy) {
     //Do something
     } else {
     //Do something else
     }
    不应该:
     if (user.isHappy)
     {
     //Do something
     }
     else {
     //Do something else
     }

    在方法之间应该有且只有一行,这样有利于在视觉上更清晰和更易于组织。在方法内的空白应该分离功能,但通常都抽离出来成为一个新方法。 优先使用auto-synthesis。但如果有必要,@synthesize和@dynamic应该在实现中每个都声明新的一行。 应该避免以冒号对齐的方式来调用方法。因为有时方法签名可能有3个以上的冒号和冒号对齐会使代码更加易读。请不要这样做,尽管冒号对齐的方法包含代码块,因为Xcode的对齐方式令它难以辨认。

    ` 应该
     // blocks are easily readable
     [UIView animateWithDuration:1.0 animations:^{
     // something
     } completion:^(BOOL finished) {
     // something
     }];
    `
    ` 不应该
     // colon-aligning makes the block indentation hard to read
     [UIView animateWithDuration:1.0
     animations:^{
     // something
     }
     completion:^(BOOL finished) {
     // something
     }];
    `

    ## <a name=”A4.2″ id=”A4.2″>每一行的最大长度</a> 在 Xcode > Preferences > Text Editing > Page guide at column: 中将最大行长设置为80,过长的一行代码将会导致可读性问题。 参考图: ![架构](http://192.168.0.102:7000/iOS/iOS/uploads/2379c1d6f6e288127f4c338b82e9442f/2EDA2C84-6E08-4CDC-AC8C-337F73CF7F79.png) ## <a name=”A4.3″ id=”A4.3″>书写断行</a> 一个典型的 Objective-C 函数应该是这样的:

    ` - (void)writeVideoFrameWithData:(NSData*)frameData timeStamp:(int)timeStamp {
     ...
     }
    `

    在 – 和 (void) 之间应该有一个空格,第一个大括号 { 的位置在函数所在行的末尾,同样应该有一个空格。(我司的 C 语言规范要求是第一个大括号单独占一行,但考虑到 OC 较长的函数名和苹果 SDK 代码的风格,还是将大括号放在行末。) 如果一个函数有特别多的参数或者名称很长,应该将其按照 : 来对齐分行显示:

    ` -(id)initWithModel:(IPCModle)model
     connectType :(IPCConnectType)connectType
     resolution :(IPCResolution)resolution
     authName :(NSString *)authName
     password :(NSString *)password
     /Animate the icon
     animationTimer = [[NSTimer scheduledTimerWithTimeInterval:ANIMATION_DELAY
     target:self
     selector:@selector(animateIcon:)
     userInfo:nil
     repeats:YES] retain];
     if (some_long_condition &amp;&amp;
     some_other_long_condition ||
     some_completely_different_long_condition)
    `

    如果方法名比参数名短,每个参数占用一行,至少缩进4个字符,且为垂直对齐(而非使用冒号对齐)。如:

    ` - (void)short:(GTMFoo *)theFoo
     longKeyword:(NSRect)theRect
     evenLongerKeyword:(float) theInterval {
     ...
     }
    `

    ## <a name=”A4.4″ id=”A4.4″>函数调用</a> 函数调用的格式和书写差不多,可以按照函数的长短来选择写在一行或者分成多行:

    ` // 写在一行
     [myObject doFooWith:arg1 name:arg2 error:arg3];
     // 分行写,按照 ':' 对齐
     [myObject doFooWith:arg1
     name:arg2
     error:arg3];
     // 和方法的声明一样,如果无法使用冒号对齐时,每个参数一行、缩进4个字符、垂直对其(而非使用冒号对齐)。如:
     [myObj short:arg1
     longKeyword:arg2
     evenLongerKeyword:arg3
     error:arg4];
    `

    以下写法是错误的:

    ` // 错误,要么写在一行,要么全部分行
     [myObject doFooWith:arg1 name:arg2
     error:arg3];
     [myObject doFooWith:arg1
     name:arg2 error:arg3];
     // 错误,按照 ':' 来对齐,而不是关键字
     [myObject doFooWith:arg1
     name:arg2
     error:arg3];
    `

    ## <a name=”A4.5″ id=”A4.5″>@public 和 @private 标记符</a> @public 和 @private 标记符应该以一个空格来进行缩进:

    ` @interface MyClass : NSObject {
     @public
     ...
     @private
     ...
     }
     @end
    `

    ## <a name=”A4.6″ id=”A4.6″>预编译常量/宏</a> 和ANSI C类似, 预编译定义必须全部大写。

    ` #define MAX_ENTRIES 20
     #ifdef ENABLE_BINDINGS_SUPPORT
    `

    常量是容易重复被使用和无需通过查找和代替就能快速修改值。常量应该使用static来声明而不是使用#define,除非显式地使用宏。整形常数用枚举,浮点型常数用const修饰 。

    ` 应该
     static NSString * const RWTAboutViewControllerCompanyName = @"RayWenderlich.com";
     static CGFloat const RWTImageThumbnailHeight = 50.0;
     不应该
     #define CompanyName @"RayWenderlich.com"
     #define thumbnailHeight 2
    `

    注意由编译器定义的宏,有前后各俩个下划线 。例如:**MACH**; ## <a name=”A4.7″ id=”A4.7″>枚举类型/宏</a> 当使用enum时,推荐使用新的固定基本类型规格,因为它有更强的类型检查和代码补全。现在SDK有一个宏NS_ENUM()来帮助和鼓励你使用固定的基本类型。 例如

    ` typedef NS_ENUM(NSInteger, RWTLeftMenuTopItemType) {
     RWTLeftMenuTopItemMain,
     RWTLeftMenuTopItemShows,
     RWTLeftMenuTopItemSchedule
     };
    `

    你也可以显式地赋值(展示旧的k-style常量定义):

    ` typedef NS_ENUM(NSInteger, RWTGlobalConstants) {
     RWTPinSizeMin = 1,
     RWTPinSizeMax = 5,
     RWTPinCountMin = 100,
     RWTPinCountMax = 500,
     };
    `

    旧的k-style常量定义应该避免除非编写Core Foundation C的代码。 不应该:

    ` enum GlobalConstants {
     kMaxPinSize = 5,
     kMaxPinCount = 500,
     };
    `

    ## Case语句 大括号在case语句中并不是必须的,除非编译器强制要求。当一个case语句包含多行代码时,大括号应该加上。

    ` switch (condition) {
     case 1:
     // ...
     break;
     case 2: {
     // ...
     // Multi-line example using braces
     break;
     }
     case 3:
     // ...
     break;
     default:
     // ...
     break;
     }
    `

    有很多次,当相同代码被多个cases使用时,一个fall-through应该被使用。一个fall-through就是在case最后移除’break’语句,这样就能够允许执行流程跳转到下一个case值。为了代码更加清晰,一个fall-through需要注释一下。

    ` switch (condition) {
     case 1:
     // ** fall-through! **
     case 2:
     // code executed for values 1 and 2
     break;
     default:
     // ...
     break;
     }
     当在switch使用枚举类型时,'default'是不需要的。
     例如:
     RWTLeftMenuTopItemType menuType = RWTLeftMenuTopItemMain;
     switch (menuType) {
     case RWTLeftMenuTopItemMain:
     // ...
     break;
     case RWTLeftMenuTopItemShows:
     // ...
     break;
     case RWTLeftMenuTopItemSchedule:
     // ...
     break;
     }
    `

    ## <a name=”A4.8″ id=”A4.8″>布尔值</a> Objective-C使用YES和NO。因为true和false应该只在CoreFoundation,C或C++代码使用。既然nil解析成NO,所以没有必要在条件语句比较。不要拿某样东西直接与YES比较,因为YES被定义为1和一个BOOL能被设置为8位。 这是为了在不同文件保持一致性和在视觉上更加简洁而考虑。 应该

    ` if (someObject) {}
     if (![anotherObject boolValue]) {}
    `

    不应该

    ` if (someObject == nil) {}
     if ([anotherObject boolValue] == NO) {}
     if (isAwesome == YES) {} // Never do this.
     if (isAwesome == true) {} // Never do this.
    `

    如果BOOL属性的名字是一个形容词,属性就能忽略”is”前缀,但要指定get访问器的惯用名称。例如:

    ` @property (assign, getter=isEditable) BOOL editable;
    `

    ## <a name=”A4.9″ id=”A4.9″>条件语句</a> 条件语句主体为了防止出错应该使用大括号包围,即使条件语句主体能够不用大括号编写(如,只用一行代码)。这些错误包括添加第二行代码和期望它成为if语句;还有,even more dangerous defect可能发生在if语句里面一行代码被注释了,然后下一行代码不知不觉地成为if语句的一部分。除此之外,这种风格与其他条件语句的风格保持一致,所以更加容易阅读。 应该

    ` if (!error) {
     return success;
     }
    `

    不应该

    ` if (!error)
     return success;
    `

    ` if (!error) return success;
    `

    ## <a name=”A5.0″ id=”A5.0″>三元操作符(条件判断语句)</a> 当需要提高代码的清晰性和简洁性时,三元操作符?:才会使用。单个条件求值常常需要它。多个条件求值时,如果使用if语句或重构成实例变量时,代码会更加易读。一般来说,最好使用三元操作符是在根据条件来赋值的情况下。 Non-boolean的变量与某东西比较,加上括号()会提高可读性。如果被比较的变量是boolean类型,那么就不需要括号。 应该

    ` NSInteger value = 5;
     result = (value != 0) ? x : y;
     BOOL isHorizontal = YES;
     result = isHorizontal ? x : y;
    `

    不应该

    ` result = a &gt; b ? x = c &gt; d ? c : d : y;
    `

    ## <a name=”A5.1″ id=”A5.1″>Init方法</a> 在初始化方法中,不要将变量初始化为“0”或“nil”,那是多余的 内存中所有的新创建的对象(isa除外)都是0,所以不需要重复初始化为“0”或“nil” Init方法应该遵循Apple生成代码模板的命名规则,返回类型应该使用instancetype而不是id。

    ` - (instancetype)init {
     self = [super init];
     if (self) {
     // ...
     }
     return self;
     }
    `

    ## <a name=”A5.2″ id=”A5.2″>类构造方法</a> 当类构造方法被使用时,它应该返回类型是instancetype而不是id。这样确保编译器正确地推断结果类型。[参考资料][3] 代码更加一致,可读性更强。它们返回相同的东西,这一点一目了然。 应该

    ` 1 :
     @interface Airplane
     + (instancetype)airplaneWithType:(RWTAirplaneType)type;
     @end
     2:
     - (instancetype)initWithBar:(NSInteger)bar;
     3:
     + (instancetype)fooWithBar:(NSInteger)bar;
    `

    不应该

    ` - (id)initWithBar:(NSInteger)bar;
     + (id)fooWithBar:(NSInteger)bar;
    `

    ## <a name=”A5.3″ id=”A5.3″>CGRect函数</a> 当访问CGRect里的x, y, width, 或 height时,应该使用CGGeometry函数而不是直接通过结构体来访问。引用Apple的CGGeometry 官方介绍 在这个参考文档中所有的函数,接受CGRect结构体作为输入,在计算它们结果时隐式地标准化这些rectangles。因此,你的应用程序应该避免直接访问和修改保存在CGRect数据结构中的数据。相反,使用这些函数来操纵rectangles和获取它们的特性。 应该

    ` CGRect frame = self.view.frame;
     CGFloat x = CGRectGetMinX(frame);
     CGFloat y = CGRectGetMinY(frame);
     CGFloat width = CGRectGetWidth(frame);
     CGFloat height = CGRectGetHeight(frame);
     CGRect frame = CGRectMake(0.0, 0.0, width, height);
    `

    不应该

    ` CGRect frame = self.view.frame;
     CGFloat x = frame.origin.x;
     CGFloat y = frame.origin.y;
     CGFloat width = frame.size.width;
     CGFloat height = frame.size.height;
     CGRect frame = (CGRect){ .origin = CGPointZero, .size = frame.size };
    `

    ## <a name=”A5.4″ id=”A5.4″>错误处理</a> 当方法通过引用来返回一个错误参数,判断返回值而不是错误变量。 应该:

    ` NSError *error;
     if (![self trySomethingWithError:&amp;error]) {
     // Handle Error
     }
    `

    不应该

    ` NSError *error;
     [self trySomethingWithError:&amp;error];
     if (error) {
     // Handle Error
     }
    `

    在成功的情况下,有些Apple的APIs记录垃圾值(garbage values)到错误参数(如果non-NULL),那么判断错误值会导致false负值和crash。 这会防止重复引用造成crashes,或者调用alloc与init造成单例并不唯一 ## <a name=”A5.5″ id=”A5.5″>下划线</a> 当使用属性时,实例变量应该使用self.来访问和改变。这就意味着所有属性将会视觉效果不同,因为它们前面都有self.。 但有一个特例:在初始化方法里,实例变量(例如,_variableName)应该直接被使用来避免getters/setters潜在的副作用。 局部变量不应该包含下划线。 ## <a name=”A5.6″ id=”A5.6″>协议( Protocols )</a> 在书写协议的时候注意用 <> 括起来的协议和类型名之间是没有空格的,比如IPCConnectHandler(), 这个规则适用所有书写协议的地方,包括函数声明、类声明、实例变量等等:

    ` @interface MyProtocoledClass : NSObject {
     @private
     id&lt;MyFancyDelegate&gt; _delegate;
     }
     @property (nonatomic,assign)id&lt;MyFancyDelegate&gt;delegate;
     //或者写成这样
     - (void)setDelegate:(id)aDelegate;
     @end
    `

    如果类声明中包含多个protocal,每个protocal占用一行,缩进2个字符。如:

    ` @interface CustomViewController : ViewController &lt;
     AbcDelegate,
     DefDelegate
     &gt; {
     ...
     }
    `

    ## <a name=”A5.7″ id=”A5.7″>闭包( Blocks )</a> 根据 block 的长度,有不同的书写规则: 较短的 block 可以写在一行内。如果分行显示的话, block 的右括号 }应该和调用block那行代码的第一个非空字符对齐。 block 内的代码采用 4 个空格 的缩进。 如果 block 过于庞大,应该单独声明成一个变量来使用。 ^ 和 ( 之间, ^ 和 { 之间都没有空格,参数列表的右括号 ) 和 { 之间有一个空格。

    ` operation setCompletionBlock:^{ [self onOperationDone]; }];
     // 分行书写的 block ,内部使用 4 空格缩进
     [operation setCompletionBlock:^{
     [self.delegate newDataAvailable];
     }];
    // 使用 C 语言 API 调用的 block 遵循同样的书写规则
     dispatch_async(_fileIOQueue, ^{
     NSString* path = [self sessionFilePath];
     if (path) {
     // ...
     }
     });
    // 较长的 block 关键字可以缩进后在新行书写,注意 block 的右括号 '}' 和调用 block 那行代码的第一个非空字符对齐
     [[SessionService sharedService]
     loadWindowWithCompletionBlock:^(SessionWindow *window) {
     if (window) {
     [self windowDidLoad:window];
     } else {
     [self errorLoadingWindow];
     }
     }];
    // 较长的 block 参数列表同样可以缩进后在新行书写
     [[SessionService sharedService]
     loadWindowWithCompletionBlock:
     ^(SessionWindow *window) {
     if (window) {
     [self windowDidLoad:window];
     } else {
     [self errorLoadingWindow];
     }
     }];
    // 庞大的 block 应该单独定义成变量使用
     void (^largeBlock)(void) = ^{
     // ...
     };
     [_operationQueue addOperationWithBlock:largeBlock];
     // 在一个调用中使用多个 block ,注意到他们不是像函数那样通过 ':' 对齐的,而是同时进行了 4 个空格的缩进
     [myObject doSomethingWith:arg1
     firstBlock:^(Foo *a) {
     // ...
     }
     secondBlock:^(Bar *b) {
     // ...
     }];
    `

    ## 数据结构的语法 应该使用可读性更好的语法来构造 NSArray , NSDictionary 等数据结构,避免使用冗长的 alloc,init 方法。 如果构造代码写在一行,需要在括号两端留有一个空格,使得被构造的元素于与构造语法区分开来:

    `
    `

    // 正确,在语法糖的 “[]” 或者 “{}” 两端留有空格 NSArray _array = @[ [foo description], @”Another String”, [bar description] ]; NSDictionary _dict = @{ NSForegroundColorAttributeName : [NSColor redColor] }; // 不正确,不留有空格降低了可读性 NSArray_ array = @[[foo description], [bar description]]; NSDictionary_ dict = @{NSForegroundColorAttributeName: [NSColor redColor]};

    ` 如果构造代码不写在一行内,构造元素需要使用两个空格来进行缩进,右括号 ] 或者 } 写在新的一行,并且与调用语法糖那行代码的第一个非空字符对齐:
    `

    NSArray _array = @[ @”This”, @”is”, @”an”, @”array” ]; NSDictionary _dictionary = @{ NSFontAttributeName : [NSFont fontWithName:@”Helvetica-Bold” size:12], NSForegroundColorAttributeName : fontColor };

    `
    构造字典时,字典的 Key 和 Value 与中间的冒号 : 都要留有一个空格,多行书写时,也可以将 Value 对齐:
    `

    // 正确,冒号 ‘:’ 前后留有一个空格 NSDictionary _option1 = @{ NSFontAttributeName : [NSFont fontWithName:@”Helvetica-Bold” size:12], NSForegroundColorAttributeName : fontColor }; // 正确,按照 Value 来对齐 NSDictionary _option2 = @{ NSFontAttributeName : [NSFont fontWithName:@”Arial” size:12], NSForegroundColorAttributeName : fontColor }; // 错误,冒号前应该有一个空格 NSDictionary _wrong = @{ AKey: @”b”, BLongerKey: @”c”, }; // 错误,每一个元素要么单独成为一行,要么全部写在一行内 NSDictionary _alsoWrong= @{ AKey : @”a”, BLongerKey : @”b” }; // 错误,在冒号前只能有一个空格,冒号后才可以考虑按照 Value 对齐 NSDictionary *stillWrong = @{ AKey : @”b”, BLongerKey : @”c”, };

    `
    &lt;a name="A5.8" id="A5.8"&gt;代码组织&lt;/a&gt;
    ` ---
     在函数分组和protocol/delegate实现中使用#pragma mark -来分类方法,要遵循以下一般结构:
    `</pre>
    # pragma mark - Lifecycle
    `
  • (instancetype)init {}
  • (void)dealloc {}
  • (void)viewDidLoad {}
  • (void)viewWillAppear:(BOOL)animated {}
  • (void)didReceiveMemoryWarning {}

    pragma mark – Custom Accessors

  • (void)setCustomProperty:(id)value {}
  • (id)customProperty {}

    pragma mark – IBActions

  • (IBAction)submitData:(id)sender {}

    pragma mark – Public

  • (void)publicMethod {}

    pragma mark – Private

  • (void)privateMethod {}

    pragma mark – Protocol conformance

    pragma mark – UITextFieldDelegate

    pragma mark – UITableViewDataSource

    pragma mark – UITableViewDelegate

    pragma mark – NSCopying

  • (id)copyWithZone:(NSZone *)zone {}

    pragma mark – NSObject

  • (NSString )description {} `` &amp;lt;a name="A5.9" id="A5.9"&amp;gt;单例模式&amp;lt;/a&amp;gt;&lt;pre&gt; 单例对象应该使用线程安全模式来创建共享实例。 标准单例示例 <pre>` static AppContext * dataEngineInstance=nil;
    *   (AppContext*)sharedInstance{ static dispatch_once_t onceToken; dispatch_once(&amp;amp;amp;onceToken, ^{ dataEngineInstance=[[[self class] alloc] init]; }); return dataEngineInstance; }
    
    • (instancetype)allocWithZone:(NSZone )zone{ if(dataEngineInstance==nil){ dataEngineInstance=[super allocWithZone:zone]; } return dataEngineInstance; } -(instancetype)copyWithZone:(NSZone )zone{ return dataEngineInstance; }
    • (instancetype)init{ @synchronized(dataEngineInstance) { return dataEngineInstance; } return dataEngineInstance; } `</pre>

      &lt;a name=”6″ id=”6″&gt;注释规范&lt;/a&gt;

      每一个文件都必须写文件注释,文件注释通常包含 `

  • 文件所在模块
  • 作者信息
  • 历史版本信息
  • 版权信息
  • 文件包含的内容,作用 Xcode注释插件 [VVDocumenter-Xcode][4] 一段良好文件注释的例子:
    /*******************************************************************************
     Copyright (C), 2011-2013, Andrew Min Chang
     File name: AMCCommonLib.h
     Author: Andrew Chang (Zhang Min)
     E-mail: LaplaceZhang@126.com
     Description:
     This file provide some covenient tool in calling library tools. One can easily include
     library headers he wants by declaring the corresponding macros.
     I hope this file is not only a header, but also a useful Linux library note.
     History:
     2012-??-??: On about come date around middle of Year 2012, file created as "commonLib.h"
     2012-08-20: Add shared memory library; add message queue.
     2012-08-21: Add socket library (local)
     2012-08-22: Add math library
     2012-08-23: Add socket library (internet)
     2012-08-24: Add daemon function
     2012-10-10: Change file name as "AMCCommonLib.h"
     2012-12-04: Add UDP support in AMC socket library
     2013-01-07: Add basic data type such as "sint8_t"
     2013-01-18: Add CFG_LIB_STR_NUM.
     2013-01-22: Add CFG_LIB_TIMER.
     2013-01-22: Remove CFG_LIB_DATA_TYPE because there is already AMCDataTypes.h
     Copyright information:
     This file was intended to be under GPL protocol. However, I may use this library
     in my work as I am an employee. And my company may require me to keep it secret.
     Therefore, this file is neither open source nor under GPL control.
     ********************************************************************************/

    文件注释的格式通常不作要求,能清晰易读就可以了,但在整个工程中风格要统一。

    <a name=”6″.1 id=”6.1″>头文件注释</a>

    header : 头文件基本信息。这个用在每个源代码文件的头文件的最开头。 例如:

    `/*!
     @header 这里的信息应该与该源代码文件的名字一致
     @abstract 关于这个源代码文件的一些基本描述
     @author Kevin Wu (作者信息)
     @version 1.00 2012/01/20 Creation (此文档的版本信息)
     */`

    ## <a name=”6.2″ id=”6.2″>类注释</a> class: 类信息。此注释用在类声明的开头。 例如:

    `/*!
     @class
     @abstract 这里可以写关于这个类的一些描述。
     */
     @interface MyClass : NSObject {
     }`

    ## <a name=”6.3″ id=”6.3″>属性注释</a> property: property的相关注释。

    `/*!
     @property
     @abstract 这里可以写关于这个Property的一些基本描述。
     */
     @property (nonatomic,readonly) NSString *helloDocText_;`

    或者

    `/** 这里可以写关于这个Property的一些基本描述。 */
     @property (nonatomic,readonly) NSString *helloDocText_;`

    建议使用第二种方式,这样在类中引用是可以看到当前属性注释信息 ## <a name=”6.4″ id=”6.4″>函数(方法)注释</a> method: 函数(方法)的相关注释。 例如:

    ` /_!
     @method
     @abstract 这里可以写一些关于这个方法的一些简要描述
     @discussion 这里可以具体写写这个方法如何使用,注意点之类的。如果你是设计一个抽象类或者一个
     共通类给给其他类继承的话,建议在这里具体描述一下怎样使用这个方法。
     @param text 文字 (这里把这个方法需要的参数列出来)
     @param error 错误参照
     @result 返回结果
     _/
    *   (BOOL)showText:(NSString _)text error:(NSError *_)error; `
    

    <a name=”6.5″ id=”6.5″>枚举注释</a>

    enum: enum的相关注释。 例如:

    `/!
    @enum
    @abstract 关于这个enum的一些基本信息
    @constant 枚举变量描述信息
    @constant 枚举变量描述信息
    ...
    /
    typedef NS_ENUM(NSInteger, HelloDocEnumDocDemo){
    HelloDocEnumDocDemoTagNumberPopupView = 100,
    HelloDocEnumDocDemoTagNumberOKButton,
    ...
    };

<a name=”6.6″ id=”6.6″>协议注释</a>

category: category的相关注释。 例如:

` /_!
@category
@abstract NSString的Category
_/
@interface KevinNSString (NSString)

<a name=”6.7″ id=”6.7″>委托注释</a>

protocol: protocol的相关注释 例如:

` /_!
 @protocol
 @abstract 这个HelloDoc类的一个protocol
 @discussion 具体描述信息可以写在这里
 _/
 @protocol HelloDocDelegate <NSObject>

<a name=”7″ id=”7″>项目管理工具(git,SVN)使用</a>

git 工具

mac 版本: GitHub Desktop

SourceThree 及时更是,多同步管理平台上的代码 在ios 项目多人联合开发容易出现代码合并冲突问题,在项目开发上如果添加了新文件或者修改工程设置都会改动 .xcodeproj文件,当修改了工程文件时应及时提交 如遇到了代码冲突应该先查看冲突原因再合并。

<a name=”8″ id=”8″>iOS更多编码规范参考资料参考资料:</a>

googol object-c编码规范

  1. [Google Objective-C Style Guide][5] 官网 object-c编码规范
  2. [Coding Guidelines for Cocoa][6] [1]: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingBasics.html#//apple_ref/doc/uid/20001281-BBCHBFAH [2]: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.pdf [3]: http://nshipster.com/instancetype/ [4]: https://github.com/onevcat/VVDocumenter-Xcode [5]: https://google-styleguide.googlecode.com/svn/trunk/objcguide.xml?showone=Line_Length#Line_Length [6]: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.pdf![2EDA2C84-6E08-4CDC-AC8C-337F73CF7F79]