Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
Work
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
陈俊泳
Work
Commits
6b09772c
Commit
6b09772c
authored
Sep 06, 2022
by
陈俊泳
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(更新):更新
parent
cbf0ff74
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1371 additions
and
49 deletions
+1371
-49
.DS_Store
.DS_Store
+0
-0
OC-代码规范.md
OC-代码规范.md
+988
-0
OC代码分析.md
OC代码分析.md
+275
-0
交接事项.md
交接事项.md
+64
-49
开发注意.md
开发注意.md
+44
-0
No files found.
.DS_Store
0 → 100644
View file @
6b09772c
File added
OC-代码规范.md
0 → 100644
View file @
6b09772c
# OC-代码规范
##
## 代码基本要求
-
基本要求
+
成员属性基本格式:@property (nonatomic, copy) NSString
*
thumb;逗号前面没有空格,后面有空格
+
变量名,方法名之类命名尽量不缩写
+
方法的声明、实现: - (void)viewDidLoad { ,-/+号前空格,{ 前有空格,{和代码写在同一行;
+
关于遵守协议:@interface GBConversationViewController ()
\<
UITableViewDataSource, UITableViewDelegate
\>
,逗号后面有空格
<br>
-
.m文件
+
\#
pragma标注顺序
*
LifeCycle
*
DataSource,Delegate
*
Event Response
*
其它的一些Method(Public Method等等)
*
Property Method (所有的懒加载之类有关property的初始化)
*
NavigationBar Configuration ,导航栏颜色之类
*
Navigation(prepareSegue)
*
Private Method()
*
\#
pragma 一般都是英文就可以了
+
在.m文件中非必要的话,不会在函数上注释,一般在h文件注释好就可以了。
+
\#
important引用头文件基本顺序,Controller,View,Request
Request的h文件里面会import对应model的h文件
<br>
## 代码格式
### 使用空格而不是制表符Tab
不要在工程里使用Tab键,使用空格来进行缩进。在
`Xcode > Preferences > Text Editing`
将Tab和自动缩进都设置为
**4**
个空格。(_Google的标准是使用两个空格来缩进,但这里还是推荐使用Xcode默认的设置。_)
### 每一行的最大长度
同样的,在
`Xcode > Preferences > Text Editing > Page guide at column:`
中将最大行长设置为
**80**
,过长的一行代码将会导致可读性问题。
###
一个典型的Objective-C函数应该是这样的:
```
objective-c
- (void)writeVideoFrameWithData:(NSData *)frameData timeStamp:(int)timeStamp {
...
}
```
在
`-`
和
`(void)`
之间应该有一个空格,第一个大括号
`{`
的位置在函数所在行的末尾,同样应该有一个空格。(_我司的C语言规范要求是第一个大括号单独占一行,但考虑到OC较长的函数名和苹果SDK代码的风格,还是将大括号放在行末。_)
如果一个函数有特别多的参数或者名称很长,应该将其按照
`:`
来对齐分行显示:
```
objective-c
-(id)initWithModel:(IPCModle)model
ConnectType:(IPCConnectType)connectType
Resolution:(IPCResolution)resolution
AuthName:(NSString *)authName
Password:(NSString *)password
MAC:(NSString *)mac
AzIp:(NSString *)az_ip
AzDns:(NSString *)az_dns
Token:(NSString *)token
Email:(NSString *)email
Delegate:(id<IPCConnectHandlerDelegate>)delegate;
```
在分行时,如果第一段名称过短,后续名称可以以Tab的长度(4个空格)为单位进行缩进:
```
objective-c
- (void)short:(GTMFoo *)theFoo
longKeyword:(NSRect)theRect
evenLongerKeyword:(float)theInterval
error:(NSError **)theError {
...
}
```
### 函数调用
函数调用的格式和书写差不多,可以按照函数的长短来选择写在一行或者分成多行:
```
objective-c
//写在一行
[myObject doFooWith:arg1 name:arg2 error:arg3];
//分行写,按照':'对齐
[myObject doFooWith:arg1
name:arg2
error:arg3];
//第一段名称过短的话后续可以进行缩进
[myObj short:arg1
longKeyword:arg2
evenLongerKeyword:arg3
error:arg4];
```
以下写法是错误的:
```
objective-c
//错误,要么写在一行,要么全部分行
[myObject doFooWith:arg1 name:arg2
error:arg3];
[myObject doFooWith:arg1
name:arg2 error:arg3];
//错误,按照':'来对齐,而不是关键字
[myObject doFooWith:arg1
name:arg2
error:arg3];
```
###@public和@private标记符
@public和@private标记符应该以
**一个空格**
来进行缩进:
```
objective-c
@interface MyClass : NSObject {
@public
...
@private
...
}
@end
```
### 协议(Protocols)
在书写协议的时候注意用
`<>`
括起来的协议和类型名之间是没有空格的,比如
`IPCConnectHandler()<IPCPreconnectorDelegate>`
,这个规则适用所有书写协议的地方,包括函数声明、类声明、实例变量等等:
```
objective-c
@interface MyProtocoledClass : NSObject<NSWindowDelegate> {
@private
id<MyFancyDelegate> _delegate;
}
- (void)setDelegate:(id<MyFancyDelegate>)aDelegate;
@end
```
### 闭包(Blocks)
根据block的长度,有不同的书写规则:
-
较短的block可以写在一行内。
-
如果分行显示的话,block的右括号
`}`
应该和调用block那行代码的第一个非空字符对齐。
-
block内的代码采用
**4个空格**
的缩进。
-
如果block过于庞大,应该单独声明成一个变量来使用。
-
`^`
和
`(`
之间,
`^`
和
`{`
之间都没有空格,参数列表的右括号
`)`
和
`{`
之间有一个空格。
```
objective-c
//较短的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`
方法。
如果构造代码写在一行,需要在括号两端留有一个空格,使得被构造的元素于与构造语法区分开来:
```
objective-c
//正确,在语法糖的"[]"或者"{}"两端留有空格
NSArray *array = @[ [foo description], @"Another String", [bar description] ];
NSDictionary *dict = @{ NSForegroundColorAttributeName : [NSColor redColor] };
//不正确,不留有空格降低了可读性
NSArray* array = @[[foo description], [bar description]];
NSDictionary* dict = @{NSForegroundColorAttributeName: [NSColor redColor]};
```
如果构造代码不写在一行内,构造元素需要使用
**两个空格**
来进行缩进,右括号
`]`
或者
`}`
写在新的一行,并且与调用语法糖那行代码的第一个非空字符对齐:
```
objective-c
NSArray *array = @[
@"This",
@"is",
@"an",
@"array"
];
NSDictionary *dictionary = @{
NSFontAttributeName : [NSFont fontWithName:@"Helvetica-Bold" size:12],
NSForegroundColorAttributeName : fontColor
};
```
构造字典时,字典的Key和Value与中间的冒号
`:`
都要留有一个空格,多行书写时,也可以将Value对齐:
```
objective-c
//正确,冒号':'前后留有一个空格
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",
};
```
##命名规范
###基本原则
####清晰
命名应该尽可能的清晰和简洁,但在Objective-C中,清晰比简洁更重要。由于Xcode强大的自动补全功能,我们不必担心名称过长的问题。
```
objective-c
//清晰
insertObject:atIndex:
//不清晰,insert的对象类型和at的位置属性没有说明
insert:at:
//清晰
removeObjectAtIndex:
//不清晰,remove的对象类型没有说明,参数的作用没有说明
remove:
```
不要使用单词的简写,拼写出完整的单词:
```
objective-c
//清晰
destinationSelection
setBackgroundColor:
//不清晰,不要使用简写
destSel
setBkgdColor:
```
然而,有部分单词简写在Objective-C编码过程中是非常常用的,以至于成为了一种规范,这些简写可以在代码中直接使用,下面列举了部分:
```
objective-c
alloc == Allocate max == Maximum
alt == Alternate min == Minimum
app == Application msg == Message
calc == Calculate nib == Interface Builder archive
dealloc == Deallocate pboard == Pasteboard
func == Function rect == Rectangle
horiz == Horizontal Rep == Representation (used in class name such as NSBitmapImageRep).
info == Information temp == Temporary
init == Initialize vert == Vertical
int == Integer
```
命名方法或者函数时要避免歧义
```
objective-c
//有歧义,是返回sendPort还是send一个Port?
sendPort
//有歧义,是返回一个名字属性的值还是display一个name的动作?
displayName
```
#### 一致性
整个工程的命名风格要保持一致性,最好和苹果SDK的代码保持统一。不同类中完成相似功能的方法应该叫一样的名字,比如我们总是用
`count`
来返回集合的个数,不能在A类中使用
`count`
而在B类中使用
`getNumber`
。
###使用前缀
如果代码需要打包成Framework给别的工程使用,或者工程项目非常庞大,需要拆分成不同的模块,使用命名前缀是非常有用的。
-
前缀由大写的字母缩写组成,比如Cocoa中
`NS`
前缀代表Founation框架中的类,
`IB`
则代表Interface Builder框架。
-
可以在为类、协议、函数、常量以及typedef宏命名的时候使用前缀,但注意
**不要**
为成员变量或者方法使用前缀,因为他们本身就包含在类的命名空间内。
-
命名前缀的时候不要和苹果SDK框架冲突。
### 命名类和协议(Class&Protocol)
类名以大写字母开头,应该包含一个
*名词*
来表示它代表的对象类型,同时可以加上必要的前缀,比如
`NSString`
,
`NSDate`
,
`NSScanner`
,
`NSApplication`
等等。
而协议名称应该清晰地表示它所执行的行为,而且要和类名区别开来,所以通常使用
`ing`
词尾来命名一个协议,比如
`NSCopying`
,
`NSLocking`
。
有些协议本身包含了很多不相关的功能,主要用来为某一特定类服务,这时候可以直接用类名来命名这个协议,比如
`NSObject`
协议,它包含了id对象在生存周期内的一系列方法。
### 命名头文件(Headers)
源码的头文件名应该清晰地暗示它的功能和包含的内容:
-
如果头文件内只定义了单个类或者协议,直接用类名或者协议名来命名头文件,比如
`NSLocale.h`
定义了
`NSLocale`
类。
-
如果头文件内定义了一系列的类、协议、类别,使用其中最主要的类名来命名头文件,比如
`NSString.h`
定义了
`NSString`
和
`NSMutableString`
。
-
每一个Framework都应该有一个和框架同名的头文件,包含了框架中所有公共类头文件的引用,比如
`Foundation.h`
-
Framework中有时候会实现在别的框架中类的类别扩展,这样的文件通常使用
`被扩展的框架名`
+
`Additions`
的方式来命名,比如
`NSBundleAdditions.h`
。
###命名方法(Methods)
Objective-C的方法名通常都比较长,这是为了让程序有更好地可读性,按苹果的说法
*“好的方法名应当可以以一个句子的形式朗读出来”*
。
方法一般以小写字母打头,每一个后续的单词首字母大写,方法名中不应该有标点符号(
*包括下划线*
),有两个例外:
-
可以用一些通用的大写字母缩写打头方法,比如
`PDF`
,
`TIFF`
等。
-
可以用带下划线的前缀来命名私有方法或者类别中的方法。
如果方法表示让对象执行一个动作,使用动词打头来命名,注意不要使用
`do`
,
`does`
这种多余的关键字,动词本身的暗示就足够了:
```
objective-c
//动词打头的方法表示让对象执行一个动作
- (void)invokeWithTarget:(id)target;
- (void)selectTabViewItem:(NSTabViewItem *)tabViewItem;
```
如果方法是为了获取对象的一个属性值,直接用属性名称来命名这个方法,注意不要添加
`get`
或者其他的动词前缀:
```
objective-c
//正确,使用属性名来命名方法
- (NSSize)cellSize;
//错误,添加了多余的动词前缀
- (NSSize)calcCellSize;
- (NSSize)getCellSize;
```
对于有多个参数的方法,务必在每一个参数前都添加关键词,关键词应当清晰说明参数的作用:
```
objective-c
//正确,保证每个参数都有关键词修饰
- (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;
```
不要用
`and`
来连接两个参数,通常
`and`
用来表示方法执行了两个相对独立的操作(
*从设计上来说,这时候应该拆分成两个独立的方法*
):
```
objective-c
//错误,不要使用"and"来连接参数
- (int)runModalForDirectory:(NSString *)path andFile:(NSString *)name andTypes:(NSArray *)fileTypes;
//正确,使用"and"来表示两个相对独立的操作
- (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;
```
方法的参数命名也有一些需要注意的地方:
-
和方法名类似,参数的第一个字母小写,后面的每一个单词首字母大写
-
不要再方法名中使用类似
`pointer`
,
`ptr`
这样的字眼去表示指针,参数本身的类型足以说明
-
不要使用只有一两个字母的参数名
-
不要使用简写,拼出完整的单词
下面列举了一些常用参数名:
```
objective-c
...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
```
### 存取方法(Accessor Methods)
存取方法是指用来获取和设置类属性值的方法,属性的不同类型,对应着不同的存取方法规范:
```
objective-c
//属性是一个名词时的存取方法范式
- (type)noun;
- (void)setNoun:(type)aNoun;
//栗子
- (NSString *)title;
- (void)setTitle:(NSString *)aTitle;
//属性是一个形容词时存取方法的范式
- (BOOL)isAdjective;
- (void)setAdjective:(BOOL)flag;
//栗子
- (BOOL)isEditable;
- (void)setEditable:(BOOL)flag;
//属性是一个动词时存取方法的范式
- (BOOL)verbObject;
- (void)setVerbObject:(BOOL)flag;
//栗子
- (BOOL)showsAlpha;
- (void)setShowsAlpha:(BOOL)flag;
```
命名存取方法时不要将动词转化为被动形式来使用:
```
objective-c
//正确
- (void)setAcceptsGlyphInfo:(BOOL)flag;
- (BOOL)acceptsGlyphInfo;
//错误,不要使用动词的被动形式
- (void)setGlyphInfoAccepted:(BOOL)flag;
- (BOOL)glyphInfoAccepted;
```
可以使用
`can`
,
`should`
,
`will`
等词来协助表达存取方法的意思,但不要使用
`do`
,和
`does`
:
```
objective-c
//正确
- (void)setCanHide:(BOOL)flag;
- (BOOL)canHide;
- (void)setShouldCloseDocument:(BOOL)flag;
- (BOOL)shouldCloseDocument;
//错误,不要使用"do"或者"does"
- (void)setDoesAcceptGlyphInfo:(BOOL)flag;
- (BOOL)doesAcceptGlyphInfo;
```
为什么Objective-C中不适用
`get`
前缀来表示属性获取方法?因为
`get`
在Objective-C中通常只用来表示从函数指针返回值的函数:
```
objective-c
//三个参数都是作为函数的返回值来使用的,这样的函数名可以使用"get"前缀
- (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase;
```
### 命名委托(Delegate)
当特定的事件发生时,对象会触发它注册的委托方法。委托是Objective-C中常用的传递消息的方式。委托有它固定的命名范式。
一个委托方法的第一个参数是触发它的对象,第一个关键词是触发对象的类名,除非委托方法只有一个名为
`sender`
的参数:
```
objective-c
//第一个关键词为触发委托的类名
- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(int)row;
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename;
//当只有一个"sender"参数时可以省略类名
- (BOOL)applicationOpenUntitledFile:(NSApplication *)sender;
```
根据委托方法触发的时机和目的,使用
`should`
,
`will`
,
`did`
等关键词
```
objective-c
- (void)browserDidScroll:(NSBrowser *)sender;
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window;、
- (BOOL)windowShouldClose:(id)sender;
```
### 集合操作类方法(Collection Methods)
有些对象管理着一系列其它对象或者元素的集合,需要使用类似“增删查改”的方法来对集合进行操作,这些方法的命名范式一般为:
```
objective-c
//集合操作范式
- (void)addElement:(elementType)anObj;
- (void)removeElement:(elementType)anObj;
- (NSArray *)elements;
//栗子
- (void)addLayoutManager:(NSLayoutManager *)obj;
- (void)removeLayoutManager:(NSLayoutManager *)obj;
- (NSArray *)layoutManagers;
```
注意,如果返回的集合是无序的,使用
`NSSet`
来代替
`NSArray`
。如果需要将元素插入到特定的位置,使用类似于这样的命名:
```
objective-c
- (void)insertLayoutManager:(NSLayoutManager *)obj atIndex:(int)index;
- (void)removeLayoutManagerAtIndex:(int)index;
```
如果管理的集合元素中有指向管理对象的指针,要设置成
`weak`
类型以防止引用循环。
下面是SDK中
`NSWindow`
类的集合操作方法:
```
objective-c
- (void)addChildWindow:(NSWindow *)childWin ordered:(NSWindowOrderingMode)place;
- (void)removeChildWindow:(NSWindow *)childWin;
- (NSArray *)childWindows;
- (NSWindow *)parentWindow;
- (void)setParentWindow:(NSWindow *)window;
```
### 命名函数(Functions)
在很多场合仍然需要用到函数,比如说如果一个对象是一个单例,那么应该使用函数来代替类方法执行相关操作。
函数的命名和方法有一些不同,主要是:
-
函数名称一般带有缩写前缀,表示方法所在的框架。
-
前缀后的单词以“驼峰”表示法显示,第一个单词首字母大写。
函数名的第一个单词通常是一个动词,表示方法执行的操作:
```
objective-c
NSHighlightRect
NSDeallocateObject
```
如果函数返回其参数的某个属性,省略动词:
```
objective-c
unsigned int NSEventMaskFromType(NSEventType type)
float NSHeight(NSRect aRect)
```
如果函数通过指针参数来返回值,需要在函数名中使用
`Get`
:
```
objective-c
const char *NSGetSizeAndAlignment(const char *typePtr, unsigned int *sizep, unsigned int *alignp)
```
函数的返回类型是BOOL时的命名:
```
objective-c
BOOL NSDecimalIsNotANumber(const NSDecimal *decimal)
```
### 命名属性和实例变量(Properties&Instance Variables)
属性和对象的存取方法相关联,属性的第一个字母小写,后续单词首字母大写,不必添加前缀。属性按功能命名成名词或者动词:
```
objective-c
//名词属性
@property (strong) NSString *title;
//动词属性
@property (assign) BOOL showsAlpha;
```
属性也可以命名成形容词,这时候通常会指定一个带有
`is`
前缀的get方法来提高可读性:
```
objective-c
@property (assign, getter=isEditable) BOOL editable;
```
命名实例变量,在变量名前加上
`_`
前缀(
*有些有历史的代码会将`_`放在后面*
),其它和命名属性一样:
```
objective-c
@implementation MyClass {
BOOL _showsTitle;
}
```
一般来说,类需要对使用者隐藏数据存储的细节,所以不要将实例方法定义成公共可访问的接口,可以使用
`@private`
,
`@protected`
前缀。
*按苹果的说法,不建议在除了`init`和`dealloc`方法以外的地方直接访问实例变量,但很多人认为直接访问会让代码更加清晰可读,只在需要计算或者执行操作的时候才使用存取方法访问,我就是这种习惯,所以这里不作要求。*
### 命名常量(Constants)
如果要定义一组相关的常量,尽量使用枚举类型(enumerations),枚举类型的命名规则和函数的命名规则相同。
建议使用
`NS_ENUM`
和
`NS_OPTIONS`
宏来定义枚举类型,参见官方的
[
Adopting Modern Objective-C
](
https://developer.apple.com/library/ios/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html
)
一文:
```
objective-c
//定义一个枚举
typedef NS_ENUM(NSInteger, NSMatrixMode) {
NSRadioModeMatrix,
NSHighlightModeMatrix,
NSListModeMatrix,
NSTrackModeMatrix
};
```
定义bit map:
```
objective-c
typedef NS_OPTIONS(NSUInteger, NSWindowMask) {
NSBorderlessWindowMask = 0,
NSTitledWindowMask = 1 << 0,
NSClosableWindowMask = 1 << 1,
NSMiniaturizableWindowMask = 1 << 2,
NSResizableWindowMask = 1 << 3
};
```
使用
`const`
定义浮点型或者单个的整数型常量,如果要定义一组相关的整数常量,应该优先使用枚举。常量的命名规范和函数相同:
```
objective-c
const float NSLightGray;
```
不要使用
`#define`
宏来定义常量,如果是整型常量,尽量使用枚举,浮点型常量,使用
`const`
定义。
`#define`
通常用来给编译器决定是否编译某块代码,比如常用的:
```
objective-c
#ifdef DEBUG
```
注意到一般由编译器定义的宏会在前后都有一个
`__`
,比如
*`__MACH__`*
。
### 命名通知(Notifications)
通知常用于在模块间传递消息,所以通知要尽可能地表示出发生的事件,通知的命名范式是:
[
触发通知的类名
]
+
[
Did | Will
]
+
[
动作
]
+ Notification
栗子:
```
objective-c
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification
```
## 注释
读没有注释代码的痛苦你我都体会过,好的注释不仅能让人轻松读懂你的程序,还能提升代码的逼格。注意注释是为了让别人看懂,而不是仅仅你自己。
### 文件注释
每一个文件都
**必须**
写文件注释,文件注释通常包含
-
文件所在模块
-
作者信息
-
历史版本信息
-
版权信息
-
文件包含的内容,作用
一段良好文件注释的栗子:
```
objective-c
/*******************************************************************************
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.
********************************************************************************/
```
*文件注释的格式通常不作要求,能清晰易读就可以了,但在整个工程中风格要统一。*
### 代码注释
好的代码应该是“自解释”(self-documenting)的,但仍然需要详细的注释来说明参数的意义、返回值、功能以及可能的副作用。
方法、函数、类、协议、类别的定义都需要注释,推荐采用Apple的标准注释风格,好处是可以在引用的地方
`alt+点击`
自动弹出注释,非常方便。
有很多可以自动生成注释格式的插件,推荐使用
[
VVDocumenter
](
https://github.com/onevcat/VVDocumenter-Xcode
)
:

一些良好的注释:
```
objective-c
/**
* Create a new preconnector to replace the old one with given mac address.
* NOTICE: We DO NOT stop the old preconnector, so handle it by yourself.
*
* @param type Connect type the preconnector use.
* @param macAddress Preconnector's mac address.
*/
- (void)refreshConnectorWithConnectType:(IPCConnectType)type Mac:(NSString *)macAddress;
/**
* Stop current preconnecting when application is going to background.
*/
-(void)stopRunning;
/**
* Get the COPY of cloud device with a given mac address.
*
* @param macAddress Mac address of the device.
*
* @return Instance of IPCCloudDevice.
*/
-(IPCCloudDevice *)getCloudDeviceWithMac:(NSString *)macAddress;
// A delegate for NSApplication to handle notifications about app
// launch and shutdown. Owned by the main app controller.
@interface MyAppDelegate : NSObject {
...
}
@end
```
协议、委托的注释要明确说明其被触发的条件:
```
objective-c
/** Delegate - Sent when failed to init connection, like p2p failed. */
-(void)initConnectionDidFailed:(IPCConnectHandler *)handler;
```
如果在注释中要引用参数名或者方法函数名,使用
`||`
将参数或者方法括起来以避免歧义:
```
objective-c
// Sometimes we need |count| to be less than zero.
// Remember to call |StringWithoutSpaces("foo bar baz")|
```
**定义在头文件里的接口方法、属性必须要有注释!**
## 编码风格
每个人都有自己的编码风格,这里总结了一些比较好的Cocoa编程风格和注意点。
### 不要使用new方法
尽管很多时候能用
`new`
代替
`alloc init`
方法,但这可能会导致调试内存时出现不可预料的问题。Cocoa的规范就是使用
`alloc init`
方法,使用
`new`
会让一些读者困惑。
### Public API要尽量简洁
共有接口要设计的简洁,满足核心的功能需求就可以了。不要设计很少会被用到,但是参数极其复杂的API。如果要定义复杂的方法,使用类别或者类扩展。
### \#import和\#include
`#import`
是Cocoa中常用的引用头文件的方式,它能自动防止重复引用文件,什么时候使用
`#import`
,什么时候使用
`#include`
呢?
-
当引用的是一个Objective-C或者Objective-C++的头文件时,使用
`#import`
-
当引用的是一个C或者C++的头文件时,使用
`#include`
,这时必须要保证被引用的文件提供了保护域(#define guard)。
栗子:
```
objective-c
#import <Cocoa/Cocoa.h>
#include <CoreFoundation/CoreFoundation.h>
#import "GTMFoo.h"
#include "base/basictypes.h"
```
为什么不全部使用
`#import`
呢?主要是为了保证代码在不同平台间共享时不出现问题。
### 引用框架的根头文件
上面提到过,每一个框架都会有一个和框架同名的头文件,它包含了框架内接口的所有引用,在使用框架的时候,应该直接引用这个根头文件,而不是其它子模块的头文件,即使是你只用到了其中的一小部分,编译器会自动完成优化的。
```
objective-c
//正确,引用根头文件
#import <Foundation/Foundation.h>
//错误,不要单独引用框架内的其它头文件
#import <Foundation/NSArray.h>
#import <Foundation/NSString.h>
```
### BOOL的使用
BOOL在Objective-C中被定义为
`signed char`
类型,这意味着一个BOOL类型的变量不仅仅可以表示
`YES`
(1)和
`NO`
(0)两个值,所以永远
**不要**
将BOOL类型变量直接和
`YES`
比较:
```
objective-c
//错误,无法确定|great|的值是否是YES(1),不要将BOOL值直接与YES比较
BOOL great = [foo isGreat];
if (great == YES)
// ...be great!
//正确
BOOL great = [foo isGreat];
if (great)
// ...be great!
```
同样的,也不要将其它类型的值作为BOOL来返回,这种情况下,BOOL变量只会取值的最后一个字节来赋值,这样很可能会取到0(NO)。但是,一些逻辑操作符比如
`&&`
,
`||`
,
`!`
的返回是可以直接赋给BOOL的:
```
objective-c
//错误,不要将其它类型转化为BOOL返回
- (BOOL)isBold {
return [self fontTraits] & NSFontBoldTrait;
}
- (BOOL)isValid {
return [self stringValue];
}
//正确
- (BOOL)isBold {
return ([self fontTraits] & NSFontBoldTrait) ? YES : NO;
}
//正确,逻辑操作符可以直接转化为BOOL
- (BOOL)isValid {
return [self stringValue] != nil;
}
- (BOOL)isEnabled {
return [self isValid] && [self isBold];
}
```
另外BOOL类型可以和
`_Bool`
,
`bool`
相互转化,但是
**不能**
和
`Boolean`
转化。
### 使用ARC
除非想要兼容一些古董级的机器和操作系统,我们没有理由放弃使用ARC。在最新版的Xcode(6.2)中,ARC是自动打开的,所以直接使用就好了。
### 在init和dealloc中不要用存取方法访问实例变量
当
`init``dealloc`
方法被执行时,类的运行时环境不是处于正常状态的,使用存取方法访问变量可能会导致不可预料的结果,因此应当在这两个方法内直接访问实例变量。
```
objective-c
//正确,直接访问实例变量
- (instancetype)init {
self = [super init];
if (self) {
_bar = [[NSMutableString alloc] init];
}
return self;
}
- (void)dealloc {
[_bar release];
[super dealloc];
}
//错误,不要通过存取方法访问
- (instancetype)init {
self = [super init];
if (self) {
self.bar = [NSMutableString string];
}
return self;
}
- (void)dealloc {
self.bar = nil;
[super dealloc];
}
```
### 按照定义的顺序释放资源
在类或者Controller的生命周期结束时,往往需要做一些扫尾工作,比如释放资源,停止线程等,这些扫尾工作的释放顺序应当与它们的初始化或者定义的顺序保持一致。这样做是为了方便调试时寻找错误,也能防止遗漏。
### 保证NSString在赋值时被复制
`NSString`
非常常用,在它被传递或者赋值时应当保证是以复制(copy)的方式进行的,这样可以防止在不知情的情况下String的值被其它对象修改。
```
objective-c
- (void)setFoo:(NSString *)aFoo {
_foo = [aFoo copy];
}
```
### 使用NSNumber的语法糖
使用带有
`@`
符号的语法糖来生成NSNumber对象能使代码更简洁:
```
objective-c
NSNumber *fortyTwo = @42;
NSNumber *piOverTwo = @(M_PI / 2);
enum {
kMyEnum = 2;
};
NSNumber *myEnum = @(kMyEnum);
```
### nil检查
因为在Objective-C中向nil对象发送命令是不会抛出异常或者导致崩溃的,只是完全的“什么都不干”,所以,只在程序中使用nil来做逻辑上的检查。
另外,不要使用诸如
`nil == Object`
或者
`Object == nil`
的形式来判断。
```
objective-c
//正确,直接判断
if (!objc) {
...
}
//错误,不要使用nil == Object的形式
if (nil == objc) {
...
}
```
### 属性的线程安全
定义一个属性时,编译器会自动生成线程安全的存取方法(Atomic),但这样会大大降低性能,特别是对于那些需要频繁存取的属性来说,是极大的浪费。所以如果定义的属性不需要线程保护,记得手动添加属性关键字
`nonatomic`
来取消编译器的优化。
###点分语法的使用
不要用点分语法来调用方法,只用来访问属性。这样是为了防止代码可读性问题。
```
objective-c
//正确,使用点分语法访问属性
NSString *oldName = myObject.name;
myObject.name = @"Alice";
//错误,不要用点分语法调用方法
NSArray *array = [NSArray arrayWithObject:@"hello"];
NSUInteger numberOfItems = array.count;
array.release;
```
### Delegate要使用弱引用
一个类的Delegate对象通常还引用着类本身,这样很容易造成引用循环的问题,所以类的Delegate属性要设置为弱引用。
```
objective-c
/** delegate */
@property (nonatomic, weak) id <IPCConnectHandlerDelegate> delegate;
```
\ No newline at end of file
OC代码分析.md
0 → 100644
View file @
6b09772c
```
shell
xcodebuild:
//执行查看
$
xcodebuild
-list
//执行Build指定
$
xcodebuild
-workspace
Project.xcworkspace
-scheme
Project
//执行Showsdks
$
xcodebuild
-showsdks
//执行清理
$
xcodebuild
-workspace
Project.xcworkspace
-scheme
Project clean
//执行Build
$
xcodebuild
-scheme
Project
-workspace
Project.xcworkspace
-sdk
iphonesimulator
-destination
'platform=iOS Simulator,name=iPhone 12 Pro Max'
-configuration
Debug
```
```
shell
xcpretty 格式化
-r
,
--report
指定生成的报告格式可选为junit, html, json-compilation-database。
-o
,
--output
指定生成的文件名称。
这里我们使用json-compilation-database格式,输出文件名为compile_commands.json
(注意输出名称不能更改,否则后面oclint会报错,因为oclint源码中内置了校验名称,具体可查看源码)
//安装
$
gem
install
xcpretty
//用法
$
xcodebuild
[
flags] | xcpretty
//结合tee
$
xcodebuild
[
flags] |
tee
xcodebuild.log | xcpretty
///执行完整命令生成compile_commands.json文件
$
xcodebuild
-scheme
Project
-workspace
Project.xcworkspace
-sdk
iphonesimulator
-destination
'platform=iOS Simulator,name=iPhone 12 Pro Max'
-configuration
Debug
GCC_PRECOMPILE_PREFIX_HEADER
=
YES
CLANG_ENABLE_MODULE_DEBUGGING
=
NO
COMPILER_INDEX_STORE_ENABLE
=
NO
OTHER_CFLAGS
=
"-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable"
|
tee
xcodebuild.log | xcpretty
-r
json-compilation-database
-o
compile_commands.json
```
```
shell
OCLint 是基于 Clang Tooling 开发的静态分析工具,主要用来发现编译器检查不到的那些潜在的关键技术问题。是进行OC代码分析的核心工具,主要对上一步生成的compile_commands.json进行分析,生成报告
//安装
$
brew tap oclint/formulae
$
brew
install
oclint
我建议使用安装包来安装OCLint,Homebrew 安装只能安装到20.11版本,最新Xcode 版本对应的是22.02。如果安装版本不符合,OClint分析出来只有一堆compiler error。
//安装包地址:https://github.com/oclint/oclint/releases
//配置环境变量:
export
PATH
=
"/Users/csdn/oclint-22.02/bin:
$PATH
"
source
~/.zshrc
//验证是否安装成功
$
oclint
--version
//如果我们使用.oclint最终我们将.oclint放在与compile_commands.json相同的路径下,并在该路径下执行命令
$
oclint-json-compilation-database
-v
-e
Pods
//或者生成oclint.xml
$
oclint-json-compilation-database
-e
Pods
--
-report-type
pmd
\
-rc
=
LONG_CLASS
=
1500
\
-rc
=
NESTED_BLOCK_DEPTH
=
5
\
-rc
=
LONG_VARIABLE_NAME
=
80
\
-rc
=
LONG_METHOD
=
200
\
-rc
=
LONG_LINE
=
300
\
-disable-rule
ShortVariableName
\
-disable-rule
ObjCAssignIvarOutsideAccessors
\
-disable-rule
AssignIvarOutsideAccessors
\
-allow-duplicated-violations
=
false
\
-max-priority-1
=
100000
\
-max-priority-2
=
100000
\
-max-priority-3
=
100000
>>
oclint.xml
```
```
shell
Infer 代码扫描软件
//安装
$
brew
install
infer
//验证
$
infer
--version
//Infer与OCLint一样,都是分析compile_commands.json文件。在compile_commands.json文件相同路径下执行命令:
# --skip-analysis-in-path 是忽略扫描目录
$
infer run
--skip-analysis-in-path
Pods
--keep-going
--compilation-database
compile_commands.json
注意:命令中一定要有--keep-going 不然会有错误导致无法进行分析。
另外需要在xcodebuild命令中添加OTHER_CFLAGS
=
"-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable"
。
```
```
shell
sonarqube 代码静态分析平台
sonarqube是一个提供代码静态分析的平台,提供了一套完整的静态分析方案,包括后端及前端页面,可以结合jenkins、gitlab等平台来进行代码分析。sonarqube分社区版本和商业化版本,能扫描多种语言并且开源。官网地址。
因为其底层源码为java开发的,所以对java代码支持比较完善,但是免费的社区版并不支持OC,所以我们如果要借助此平台的话,有以下两种方式:
开源插件sonar-swift
,支持Objective-C和Swift / Java,支持导入 SwiftLint、Infer、OCLint、Lizard、Fauxpas 工具的扫描分析结果。最新v1.6版本,兼容SonarQube 8.9LTS版本。该插件是好未来研发团队研发并且开源。
付费使用社区版plus,提供了SonarCFamily
for
C插件
sonar-swift https://github.com/sonar-next/sonar-swift
通过GitHub 下载对应插件 image 下载插件放到/extensions/plugins 目录下。重启sonarqube服务,就可以了。
sonar-scanner 用来扫描本地代码,并且上传到SonarQube平台中。
//配置环境变量
$
vim ~/.bash_profile
#sonar-scanner for cli
export
PATH
=
$PATH
:/Users/csdn/scanner/bin:
$PATH
$
source
~/.bash_profile
//sonar-scanner 分为两种使用方式:
//配置文件方式:
//在需要扫描项目根目录下新建sonar-project.properties 文件,内容如下:
sonar.projectKey
=
Project
sonar.projectName
=
Project
sonar.language
=
objc
sonar.sources
=
/Users/csdn/.jenkins/workspace/csdn_build_ios/
sonar.objectivec.workspace
=
Project.xcworkspace
sonar.objectivec.appScheme
=
Project
sonar.sourceEncoding
=
UTF-8
sonar.junit.reportsPath
=
sonar-reports/
sonar.objectivec.oclint.report
=
sonar-reports/oclint.xml
sonar.swift.infer.report
=
infer-out/report.json
进入项目根目录下,然后输入sonar-scanner命令,执行代码分析。
//命令行方式:
$
sonar-scanner
-Dsonar
.projectKey
=
Project
-Dsonar
.projectName
=
Project
-Dsonar
.projectName
=
Project
-Dsonar
.projectVersion
=
5.1.0
//忽略指定文件目录或者文件
sonar.exclusions
=
**
/Resource/
**
,
**
/
*
.py
//或者可以在命令中设置参数,例如:
sonar-scanner
-Dsonar
.exclusions
=
**
/Resource/
**
,
**
/
*
.py
-Dsonar
.projectKey
=
Project
-Dsonar
.projectName
=
Project
-Dsonar
.projectName
=
Project
-Dsonar
.projectVersion
=
5.1.0
这里的核心便是在上面步骤中由OCLint生成的oclint.xml文件与Infer生成的report.json,另外注意oclint.xml必须放至sonar-reports文件下。report.json在Infer生成的infer-out目录下。
```
```
shell
Jekins
//构建Shell命令中,增加OCLint相关命令
if
[
"
$MODE
"
x
=
"OCLint"
x
]
then
sh /Users/csdn/.jenkins/workspace/csdn_build_ios/fastlane/oclint.sh
"
$GIT_BRANCH
"
fi
```
```
shell
oclint.sh
#!/bin/bash
COLOR_ERR="
\0
33
[
1;31m" #出错提示
COLOR_SUCC="
\0
33
[
0;32m" #成功提示
COLOR_QS="
\0
33
[
1;37m" #问题颜色
COLOR_AW="
\0
33
[
0;37m" #答案提示
COLOR_END="
\0
33
[
1;34m" #颜色结束符
# 寻找项目的 ProjectName
function searchProjectName () {
# maxdepth 查找文件夹的深度
find . -maxdepth 1 -name "
*
.xcodeproj"
}
function oclintForProject () {
# 预先检测所需的安装包是否存在
if which xcodebuild 2>/dev/null; then
echo 'xcodebuild exist'
else
echo 'xcodebuild 未安装,请安装Xcode'
fi
if which oclint 2>/dev/null; then
echo 'oclint exist'
else
echo 'oclint 未安装,请安装OCLint'
fi
if which xcpretty 2>/dev/null; then
echo 'xcpretty exist'
else
gem install xcpretty
fi
# 指定编码
export LANG="zh_CN.UTF-8"
export LC_COLLATE="zh_CN.UTF-8"
export LC_CTYPE="zh_CN.UTF-8"
export LC_MESSAGES="zh_CN.UTF-8"
export LC_MONETARY="zh_CN.UTF-8"
export LC_NUMERIC="zh_CN.UTF-8"
export LC_TIME="zh_CN.UTF-8"
export xcpretty=/usr/local/bin/xcpretty # xcpretty 的安装位置可以在终端用 which xcpretty找到
searchFunctionName=
`searchProjectName`
path=${searchFunctionName}
# 字符串替换函数。//表示全局替换 /表示匹配到的第一个结果替换。
path=${path//.
\/
/} # ./BridgeLabiPhone.xcodeproj -> BridgeLabiPhone.xcodeproj
path=${path//.xcodeproj/} # BridgeLabiPhone.xcodeproj -> BridgeLabiPhone
myworkspace=$path".xcworkspace" # workspace名字
myscheme=$path # scheme名字
# 清除上次编译数据
if
[
-d ./derivedData
]
; then
echo -e $COLOR_SUCC'-----清除上次编译数据derivedData-----'$COLOR_SUCC
rm -rf ./derivedData
fi
# xcodebuild clean
xcodebuild -scheme $myscheme -workspace $myworkspace clean
# # 生成编译数据
xcodebuild -scheme $myscheme -workspace $myworkspace -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 12 Pro Max' -configuration Debug GCC_PRECOMPILE_PREFIX_HEADER=YES CLANG_ENABLE_MODULE_DEBUGGING=NO COMPILER_INDEX_STORE_ENABLE=NO OTHER_CFLAGS="-DNS_FORMAT_ARGUMENT(A)= -D_Nullable_result=_Nullable" | tee xcodebuild.log | xcpretty -r json-compilation-database -o compile_commands.json
if [ -f ./compile_commands.json ]; then
echo -e $COLOR_SUCC'编译数据生成完毕'$COLOR_SUCC
else
echo -e $COLOR_ERR'编译数据生成失败'$COLOR_ERR
return -1
fi
echo -e $COLOR_SUCC'OCLint代码分析开始'$COLOR_SUCC
# 生成报表
oclint-json-compilation-database -e Pods -- -report-type pmd \
-rc=LONG_CLASS=1500 \
-rc=NESTED_BLOCK_DEPTH=5 \
-rc=LONG_VARIABLE_NAME=80 \
-rc=LONG_METHOD=200 \
-rc=LONG_LINE=300 \
-disable-rule ShortVariableName \
-disable-rule ObjCAssignIvarOutsideAccessors \
-disable-rule AssignIvarOutsideAccessors \
-allow-duplicated-violations=false\
-max-priority-1=100000 \
-max-priority-2=100000 \
-max-priority-3=100000 >> oclint.xml
echo -e $COLOR_SUCC'Infer代码分析开始'$COLOR_SUCC
# --skip-analysis-in-path 是忽略扫描目录
infer run --skip-analysis-in-path Pods --keep-going --compilation-database compile_commands.json
product_name=`sed -n '/PRODUCT_NAME/{s/PRODUCT_NAME = //;s/;//;s/^[[:space:]]*//;s/\"//g;p;q;}' ./$myscheme.xcodeproj/project.pbxproj`
version_number=`sed -n '/MARKETING_VERSION/{s/MARKETING_VERSION = //;s/;//;s/^[[:space:]]*//;s/\"//g;p;q;}' ./$myscheme.xcodeproj/project.pbxproj`
if [ -f ./oclint.xml -a -f ./infer-out/report.json ]; then
rm compile_commands.json
echo -e $COLOR_SUCC'代码分析完毕'$COLOR_SUCC
mv oclint.xml sonar-reports/
echo -e $COLOR_SUCC'移动至sonar-reports完毕'$COLOR_SUCC
echo -e $COLOR_SUCC'开始执行sonar-scanner扫描文件'$COLOR_SUCC
echo -e $COLOR_SUCC'版本号:'${version_number}''$COLOR_SUCC
sonar-scanner -Dsonar.projectVersion=$version_number
else
echo -e $COLOR_ERR'分析失败'$COLOR_ERR
fi
}
oclintForProject $1
```
交接事项.md
View file @
6b09772c
...
@@ -4,41 +4,67 @@
...
@@ -4,41 +4,67 @@
## 账号
## 账号
-
邮箱
-
coding
-
- junyong.chen@shengyc.com
-
- Shengyc_2022
-
邮箱
-
junyong.chen@shengyc.com
-
junyong.chen@shengyc.com
-
Kangaroo
-
Kangaroo
5566324415272839 02/23 084
-
[
Appid
](
https://developer.apple.com/account/#/overview/C77C4Z7YUK
)
「App打包密码:
aesw-kpag-preb-byxo
」
-
[
Appid
](
https://developer.apple.com/account/#/overview/C77C4Z7YUK
)
「App打包密码:
vwks-bbxa-onno-futv
」
-
446467926@qq.com
-
446467926@qq.com
-
SHENGyc34583
232
-
SHENGyc34583
131
-
[
蒲公英
](
https://www.pgyer.com/my
)
-
张总:用于CMS
绑定手机号-17701929135「施婷」
appid账号: saas@shengyc.com
appid密码:Shengyc_1212
网易邮箱密码:syc888168
-
测试appid:
-
- 账号:
[
info@shengyc.com
](
mailto:info@shengyc.com
)
-
密码:Shengyc168.
-
ShengYc2022 公司网盘密码
-
[
蒲公英
](
https://www.pgyer.com/my
)
-
测试
-
测试
-
17701929130
-
17701929130
-
Syc34583232
-
Syc34583232
-
测试2号
-
18028681368
-
Syc34583232.
-
e4a9556c9fdbe55d63f28b5f579bfba9
-
正式
-
正式
-
账号:
info@shengyc.com
-
账号:
[
info@shengyc.com
](
mailto:info@shengyc.com
)
-
密码:shengyc888
-
密码:shengyc888
-
TestFlight 公开链接
-
TestFlight 公开链接
-
https://testflight.apple.com/join/ZMkkPeuK
-
https://testflight.apple.com/join/ZMkkPeuK
-
盛云平台
-
盛云平台
-
http://139.159.212.187:2800/w/sycloud/sycadmin/index.html
-
http://139.159.212.187:2800/w/sycloud/sycadmin/index.html
-
syc_admin
-
syc_admin
SYC_202
0
@admin
SYC_202
1
@admin
-
微信
-
微信
-
微信公众平台
-
微信公众平台
2093181845@qq.com
2093181845@qq.com
Sy2019123
Sy2019123
微信开发平台
微信开发平台
operation@shengyc.com
operation@shengyc.com
Sy2019123
Sy2019123
...
@@ -47,33 +73,39 @@
...
@@ -47,33 +73,39 @@
盛原成SYC
盛原成SYC
shengyc2@!9
shengyc2@!9
-
[
友盟测试帐号
](
https://www.umeng.com/
)
-
友盟
盛原成测试/syC9229&63
-
测试
-
盛原成测试/syC9229&63
-
正式
-
zhantian.su@shengyc.com
Syc34583232
-
百度SDK
-
百度SDK
-
账号:17701929135
-
账号:17701929135
-
密码:shengyc888.
-
密码:shengyc888.
-
接口文档
-
接口文档
-
http://139.159.254.185:2400/doc.html
-
http://139.159.254.185:2400/doc.html
-
盛云平台
-
盛云平台
-
syc_admin SYC_2020@admin
-
syc_admin SYC_2020@admin
-
上传更新/dc/apk/v2
-
上传更新/dc/apk/v2
-
access_key「 LTAItOdVqarCl7gg」
-
access_key「 LTAItOdVqarCl7gg」
-
删除更新/dc/apk
-
删除更新/dc/apk
-
access_key「 LTAItOdVqarCl7gg」
-
access_key「 LTAItOdVqarCl7gg」
---
---
## 代码基本要求
## 代码基本要求
...
@@ -87,8 +119,9 @@
...
@@ -87,8 +119,9 @@
<br>
<br>
-
.m文件
-
.m文件
+
\#
MARK 标注顺序
+
\#
MARK 标注顺序
*
LifeCycle
*
LifeCycle
*
DataSource,Delegate
*
DataSource,Delegate
*
Event Response
*
Event Response
...
@@ -97,38 +130,20 @@
...
@@ -97,38 +130,20 @@
*
NavigationBar Configuration ,导航栏颜色之类
*
NavigationBar Configuration ,导航栏颜色之类
*
Private Method()
*
Private Method()
*
\#
MARK 一般都是英文就可以了
*
\#
MARK 一般都是英文就可以了
+
在.m文件中非必要的话,不会在函数上注释,一般在h文件注释好就可以了。
+
在.m文件中非必要的话,不会在函数上注释,一般在h文件注释好就可以了。
+
\#
important引用头文件基本顺序,
+
\#
important引用头文件基本顺序,
*
Controller
*
Controller
*
View
*
View
*
ViewModel
*
ViewModel
*
Request
*
Request
*
Mgr
*
Mgr
一般有ViewModel的类不会直接引用Request
一般有ViewModel的类不会直接引用Request
「ViewModel的h会import使用到的数据源h文件」
「ViewModel的h会import使用到的数据源h文件」
Request的h文件里面会import对应model的h文件
Request的h文件里面会import对应model的h文件
<br>
<br>
-
-
开发注意.md
0 → 100644
View file @
6b09772c
```objective-c
\#TODO
修改完关键字之后
静态库中采用Objective-C++实现,因此需要您保证您工程中至少有一个.mm后缀的源文件(您可以将任意一个.m后缀的文件改名为.mm),或者在工程属性中指定编译方式,即在Xcode的TARGETS -> Build Setting -> Apple LLVM9.0 - Language中找到 Compile Sources As,并将其设置为"Objective-C++",
需要修改项目中的关键字以使用bitcode打包模式。
```
```
shell
#启动jenkins
brew services start jenkins
#停止jenkins
brew services stop jenkins
#重启jenkins
brew services restart jenkins
```
```
shell
#下面附上脚本其他命令,以便管理showdoc时可以用得上。
#停止
./showdoc stop
#重启
./showdoc restart
#升级showdoc到最新版
./showdoc update
#卸载showdoc
./showdoc uninstall
```
~~客户反馈~~
~~服务单列表权限~~
##### 流程注意点
-
需求缺失「说明缺失、规则缺失、规范缺失」
```
接下来提的bug,影响测试主流程的标1,功能性问题标2,内容显示错位有被遮挡类标3, 可后期优化的标4,,,你们按这个来修复哈,晚上统计bug的时候,只统计级别123的
```
<iframe
height=
498
width=
510
src=
'https://player.youku.com/embed/XNDk5MDMyNDM2MA=='
frameborder=
0
'
allowfullscreen
'
></iframe>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment