iOS開發(fā)規(guī)范
目錄
編寫目的
制定開發(fā)規(guī)范,可以在團隊內部形成統(tǒng)一的開發(fā)習慣,減少協(xié)作的理解成本辫愉。
此開發(fā)規(guī)范主要制定了以下方面的規(guī)范:
1. 統(tǒng)一開發(fā)環(huán)境、代碼格式将硝、注釋習慣恭朗、命名規(guī)則;
2. 推薦常見性能優(yōu)化解決方案;
3. 規(guī)范化 SVN/GIT 提交習慣;
適用范圍
1. 客戶端研發(fā)組,iOS 開發(fā)需要遵守此開發(fā)規(guī)范依疼。
2. 客戶端研發(fā)組的其他平臺開發(fā)人員痰腮,在 GIT 提交習慣方面可以參考此規(guī)范。
開發(fā)環(huán)境
下載更新地址:
AppStore
編程規(guī)約
一律罢、命名規(guī)范
統(tǒng)一要求
含義清楚膀值,盡量做到不需要注釋也能了解其作用棍丐,若做不到,就加注釋沧踏。
使用全稱歌逢,不適用縮寫
類的命名
大駝峰式命名:每個單詞的首字母都采用大寫字母
例子:RSHomeController
后綴要求
ViewController: 使用Controller做后綴
例子: RSHomeController
View: 使用View做后綴
例子: JLBAlertView
UITableCell:使用Cell做后綴
例子: OrderListTitleCell
Protocol: 使用Delegate或者DataSource作為后綴
例子: UITableViewDelegate
UI控件依次類推
私有變量
小駝峰式命名:第一個單詞以小寫字母開始,后面的單詞的首字母全部大寫翘狱。
例子:firstName秘案、lastName
以下劃線 _ 開頭,第一個單詞首字母小寫
例子:NSString * _myPrivateVariable
私有變量放在 .m 文件中聲明
property變量
小駝峰式命名:
例子:
/**注釋*/
@property (nonatomic, copy) NSString *userName;
注:禁止使用synthesize關鍵詞
宏命名
全部大寫潦匈,單詞間用 下劃線_ 分隔阱高。[不帶參數(shù)]
例子: #define THIS_IS_AN_MACRO @"THIS_IS_AN_MACRO"
以字母 k 開頭,后面遵循大駝峰命名茬缩。[不帶參數(shù)]
例子:#define kScreenHeight ([UIScreen mainScreen].bounds.size.height)
小駝峰命名赤惊。[帶參數(shù)]
例子:#define rgbColor(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1]
Enum
Enum類型的命名與類的命名規(guī)則一致
Enum中枚舉內容的命名需要以該Enum類型名稱開頭
例子:
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,
AFNetworkReachabilityStatusNotReachable = 0,
AFNetworkReachabilityStatusReachableViaWWAN = 1,
AFNetworkReachabilityStatusReachableViaWiFi = 2
};
位掩碼
當用到位掩碼時,使用 NS_OPTIONS 宏寒屯。
舉例:
typedef NS_OPTIONS(NSUInteger, NYTAdCategory) {
NYTAdCategoryAutos = 1 << 0,
NYTAdCategoryJobs = 1 << 1,
NYTAdCategoryRealState = 1 << 2,
NYTAdCategoryTechnology = 1 << 3
};
Delegate命名
- 類的實例必須為回調方法的參數(shù)之一, 如:
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
- 回調方法的參數(shù)只有類自己的情況荐捻,方法名要符合實際含義, 如:
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
- 以類的名字開頭(回調方法存在兩個以上參數(shù)的情況)以表明此方法是屬于哪個類的, 如:
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- 使用did和will通知Delegate已經發(fā)生的變化或將要發(fā)生的變化, 如:
-(NSIndexPath*)tableView:(UITableView*)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath;
-(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath;
切圖命名規(guī)范
為了降低設計和開發(fā)之間的交流成本,所以在此確定一下 iOS 項目切圖的命名標準寡夹。
我們的命名規(guī)則的基本思想是把文件名分成三部分处面,第一部分是圖片的邏輯歸屬分類,第二部分是圖片的表現(xiàn)內容菩掏,第三部分是圖片的內容的類型魂角,有些圖片還會有第四部分,表示圖片表現(xiàn)的狀態(tài)智绸。
首先有幾個規(guī)則是:
1. 用英文命名野揪,不用拼音
2. 每一部分用下劃線分隔
3. 圖片名中兩倍圖在名字最后要加@2x,三倍圖在名字最后要加@3x
邏輯分類
邏輯分類即是這張圖片所屬的分組瞧栗,在 iOS 中大多的項目是以 Tab bar 的形式進行邏輯上的分組斯稳,以下圖為例:
[圖片上傳失敗...(image-60ebae-1519622380933)]
這張圖中的 Showtime
客戶端就是使用 Tab bar
進行分組的,可以看出內容分成了五個部分:Home
迹恐,Categories
挣惰,Live TV
,My List
和 Search
殴边。
所以例如在這個界面中憎茂,右上角的設置按鈕,那么它的切圖命名的 第一部分就是 Home
锤岸。
但是仔細看看上面這個界面的話有一些圖其實是不屬于某個分類的竖幔,比如 Tab bar
中的圖標文件和 Navigation Bar
中的 Showtime
圖標,對于這兩種內容來講是偷,它們命名的規(guī)范是第一部分顯示的是 navigationbar
或者是 tabbar
拳氢。
表現(xiàn)內容
表現(xiàn)內容就是這個圖片表現(xiàn)的內容募逞,同樣以上圖為例,界面中右上角的按鈕表現(xiàn)的是設置按鈕馋评,那么它的表現(xiàn)內容就是設置凡辱,所以這個按鈕在第二部分顯示的就是 settings
。
而在上圖的 Tab bar
中第二部分的名字就是它們在程序中顯示的名字 ,而 Navigation Bar
中的圖標的第二部分命名因為表現(xiàn)的內容就是 Showtime
盈简,所以顯示的就是 showtime
公般。
內容類型
同樣以 Showtime
的圖為例,在 Navigation Bar
中的圖標歉眷,它的內容類型是 icon
,所以這個圖片文件的兩倍圖完整命名就是 navigationbar_showtime_icon@2x.png
。
而右上角的設置按鈕的話市咆,它的類型是按鈕,所以第三部分即是 button
的縮寫 btn
再来,即是 navigationbar_settings_button
蒙兰,下面五個 Tab bar
的圖片名分別是 tabbar_home_icon
,tabbar_categories_icon
,tabbar_livetv_icon
,tabbar_mylist_icon
和 tabbar_search_icon
。
圖片狀態(tài)
對于某些類型的切圖芒篷,它可能代表的只是某個控件的一種狀態(tài)搜变,以按鈕為例,正常的狀態(tài)就是 normal
针炉,而點擊中的狀態(tài)是 highlighted
挠他,選中的狀態(tài)則是 selected
。
Showtime
的圖中篡帕,右上角的設置圖標是正常的狀態(tài)殖侵,所以加入圖片的狀態(tài)之后,它的兩倍圖的完整命名應該是 navigationbar_settings_btn_normal@2x.png
镰烧。
而下方的 Tab bar
來講拢军,選中的是 Home
,那么當前這張圖片的兩倍圖的完整命名就應該是 tabbar_home_icon_selected@2x.png
怔鳖。
切圖規(guī)則
我們都知道一套完整的 App 通常會有很多張切圖茉唉,不管是 iPhone 需要 1x、2x败砂、3x 圖檔赌渣,Android 需要至少 3 種 hdpi、xhdpi昌犹、xxhdpi坚芜。
在龐大的數(shù)量下如何讓負責套圖的 RD 快速找到所需圖檔,檔名的命令方式就需要雙方統(tǒng)一格式方便大家作業(yè)斜姥。
所以鸿竖,制定一套非常有效而方便的APP切圖命名規(guī)范非常有用的沧竟。
目前iPhone有10種型號,5種屏幕尺寸缚忧,再加上6plus的“降采樣”(Downsampling)(1080-1920)悟泵,還有iPhone6和6+上的放大模式(1125-2001)和默認模式(1242-2208),是不是感覺好恐怖闪水?
但是不用怕糕非,我分享一套超簡單的適配方法,看完你都不信有這么簡單~
美術交付給開發(fā)的資料有
標注圖(以640為寬度尺寸為基準標注)
2x切圖(以640為寬度尺寸為基準切圖)
3x切圖(以1280為寬度尺寸為基準切圖)
[圖片上傳失敗...(image-e8f09a-1519622380933)]
開發(fā)看到這份標注圖球榆,可以自己用上面的數(shù)字朽肥,乘以1.5得出3X的數(shù)字。
為什么3x切圖要以1280來為寬度持钉?
其實iPhone6+的尺寸1242*2208作為3X衡招,怎么算都又難記又不能整除,
我們直接640*2得到1280跟1242相差也沒幾十個像素每强,最重要的是不虛
邊啊始腾,放在真機上看(處女座除外)看不出差別的。
為什么只設寬度空执?
為了保持長寬比例浪箭。iPhone的這幾個尺寸不是正好的,寬度放大后高度總差那么幾個像素辨绊,這不要緊山林,千萬別去改高度,
手機屏幕是可以上下滑動的嘛邢羔。不可以滑動必須保證一屏顯示的除外驼抹,手動去調整好了。
為什么開發(fā)不是乘以2而是乘以1.5來算尺寸和字號拜鹤?
因為大屏手機就是要顯示更多內容而存在的框冀。
純等比放大界面看起來傻大傻大的,實驗證明1.5倍是正好的敏簿。
二明也、私有方法及變量聲明
聲明位置</h>
- 在.m文件中最上方,定義空的category進行聲明
例子:
@interface OrderListTitleFrame ()
// 屬性
@property (nonatomic, strong) UIBarButtonItem *backBtn;
// 私有方法
- (CGFloat)cellHeight;
@end
@implementation OrderListTitleFrame
// 私有方法的實現(xiàn)
- (CGFloat)cellHeight
{
//some code
}
@end
點語法
應該始終使用 點語法 來訪問或者修改屬性惯裕,訪問其他實例時首選括號温数。
推薦:
view.backgroundColor = [UIColor orangeColor];
[UIApplication sharedApplication].delegate;
反對:
[view setBackgroundColor:[UIColor orangeColor]];
UIApplication.sharedApplication.delegate;
條件判斷
條件判斷主體部分應該始終使用大括號括住來防止出錯,即使它可以不用大括號(例如它只需要一行)蜻势。這些錯誤包括添加第二行(代碼)并希望它是 if 語句的一部分時撑刺。還有另外一種更危險的,當 if 語句里面的一行被注釋掉握玛,下一行就會在不經意間成為了這個 if 語句的一部分够傍。此外甫菠,這種風格也更符合所有其他的條件判斷,因此也更容易檢查冕屯。
推薦:
if (!error) {
return success;
}
反對:
if (!error)
return success;
或者:
if (!error) return success;
三目運算符
三目運算符寂诱,? ,只有當它可以增加代碼清晰度或整潔時才使用安聘。單一的條件都應該優(yōu)先考慮使用痰洒。多條件時通常使用 if 語句會更易懂,或者重構為實例變量浴韭。
推薦:
result = a > b ? x : y;
反對:
result = a > b ? x = c > d ? c : d : y;
錯誤處理
當引用一個返回錯誤參數(shù)(error parameter)的方法時带迟,應該針對返回值,而非錯誤變量囱桨。
推薦:
NSError *error;
if (![self trySomethingWithError:&error]) {
// 處理錯誤
}
反對:
NSError *error;
[self trySomethingWithError:&error];
if (error) {
// 處理錯誤
}
變量
變量名應該盡可能命名為描述性的。除了 for() 循環(huán)外嗅绰,其他情況都應該避免使用單字母的變量名舍肠。星號表示指針屬于變量,例如:
NSString *text
不要寫成NSString* text
或者NSString * text
窘面,常量除外翠语。
盡量定義屬性來代替直接使用實例變量。除了初始化方法
init财边, initWithCoder:
等肌括,dealloc
方法和自定義的setters
和getters
內部,應避免直接訪問實例變量酣难。
推薦:
@interface NYTSection: NSObject
@property (nonatomic) NSString *headline;
@end
反對:
@interface NYTSection : NSObject {
NSString *headline;
}
變量限定符
當涉及到在 ARC 中被引入變量限定符時谍夭,
限定符 (__strong, __weak, __unsafe_unretained, __autoreleasing)
應該位于星號和變量名之間,如:NSString * __weak text憨募。
init 和 dealloc
dealloc
方法應該放在實現(xiàn)文件的最上面紧索,并且剛好在@synthesize
和@dynamic
語句的后面。在任何類中菜谣,init
都應該直接放在dealloc
方法的下面珠漂。
init
方法的結構應該像這樣:
- (instancetype)init {
self = [super init]; // 或者調用指定的初始化方法
if (self) {
// Custom initialization
}
return self;
}
字面量
每當創(chuàng)建
NSString
,NSDictionary
尾膊,NSArray
媳危,和NSNumber
類的不可變實例時,都應該使用字面量冈敛。要注意nil
值不能傳給NSArray
和NSDictionary
字面量待笑,這樣做會導致崩潰。
推薦:
NSArray *names = @[@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul"];
NSNumber *shouldUseLiterals = @YES;
NSNumber *buildingZIPCode = @10018;
反對:
NSArray *names = [NSArray arrayWithObjects:@"Brian", @"Matt", @"Chris", @"Alex", @"Steve", @"Paul", nil];
NSNumber *shouldUseLiterals = [NSNumber numberWithBool:YES];
NSNumber *buildingZIPCode = [NSNumber numberWithInteger:10018];
CGRect 函數(shù)
當訪問一個
CGRect
的x抓谴, y滋觉, width签夭, height
時,應該使用CGGeometry
函數(shù)代替直接訪問結構體成員椎侠。蘋果的CGGeometry
參考中說到:
All functions described in this reference that take CGRect data structures as inputs implicitly standardize those rectangles before calculating their results. For this reason, your applications should avoid directly reading and writing the data stored in the CGRect data structure. Instead, use the functions described here to manipulate rectangles and to retrieve their characteristics.
所有功能描述在這個參考CGRect中隱式數(shù)據(jù)結構作為輸入規(guī)范那些矩形之前計算結果第租。由于這個原因,您的應用程序應該避免直接閱讀和寫作在CGRect中存儲的數(shù)據(jù)的數(shù)據(jù)結構。相反,使用這里描述的函數(shù)來操縱矩形和檢索他們的特征我纪。
推薦:
CGRect frame = self.view.frame;
CGFloat x = CGRectGetMinX(frame);
CGFloat y = CGRectGetMinY(frame);
CGFloat width = CGRectGetWidth(frame);
CGFloat height = CGRectGetHeight(frame);
反對:
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;
常量
常量首選內聯(lián)字符串字面量或數(shù)字慎宾,因為常量可以輕易重用并且可以快速改變而不需要查找和替換。常量應該聲明為
static
常量而不是#define
浅悉,除非非常明確地要當做宏來使用趟据。
推薦:
static NSString * const NYTAboutViewControllerCompanyName = @"The New York Times Company";
static const CGFloat NYTImageThumbnailHeight = 50.0;
反對:
#define CompanyName @"The New York Times Company"
#define thumbnailHeight 2
布爾
因為
nil
解析為NO
,所以沒有必要在條件中與它進行比較术健。永遠不要直接和YES
進行比較汹碱,因為YES
被定義為1
,而BOOL
可以多達8
位荞估。
這使得整個文件有更多的一致性和更大的視覺清晰度咳促。
推薦:
if (!someObject) {
}
反對:
if (someObject == nil) {
}
對于 BOOL
來說, 這有兩種用法:
if (isAwesome)
if (![someObject boolValue])
反對:
if ([someObject boolValue] == NO)
if (isAwesome == YES) // 永遠別這么做
如果一個 BOOL
屬性名稱是一個形容詞,屬性可以省略 is
前綴勘伺,但為 get
訪問器指定一個慣用的名字跪腹,例如:
@property (assign, getter=isEditable) BOOL editable;
內容和例子來自 Cocoa 命名指南
單例
單例對象應該使用線程安全的模式創(chuàng)建共享的實例。
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
這將會預防有時可能產生的許多崩潰飞醉。
類構造方法
當類構造方法被使用時冲茸,它應該返回類型是
instancetype
而不是id
。這樣確保編譯器正確地推斷結果類型缅帘。
例子:
@interface Airplane
+ (instancetype)airplaneWithType:(RWTAirplaneType)type;
@end
三轴术、注釋規(guī)范
最好的代碼是不需要注釋的,盡量通過合理的命名钦无、良好的代碼把含義表達清楚膳音,在必要的地方添加注釋,注釋需要與代碼同步更新铃诬,如果做不到命名盡量的見名知意的話祭陷,就可以適當?shù)奶砑右恍┳⑨尰蛘適ark
屬性注釋
例子:
/**學生*/
@property (nonatomic, strong) Student *student;
方法聲明注釋:
/**
訂單列表頁接口
@param psize [可選]: 每頁條數(shù)
@param page [可選]: 頁數(shù)
@param control 當前類
@param success 成功回調
@param failure 失敗回調
*/
+ (void)getOrderListDataWithPsize:(NSInteger)psize
page:(NSInteger)page
control:(NSObject *)control
success:(void (^)(NSArray *dataArray))success
failure:(void (^)(NSError *error))failure;
導入
如果有一個以上的
import
語句,就對這些語句進行分組趣席。每個分組的注釋是可選的兵志。
注:對于模塊使用
@import
語法。
// Frameworks
@import QuartzCore;
// Models
#import "NYTUser.h"
// Views
#import "NYTButton.h"
#import "NYTUserView.h"
四宣肚、代碼格式化
把代碼風格統(tǒng)一化想罕,可以讓代碼更加易讀,降低后續(xù)維護成本。
指針 * 位置
- 定義一個對象時按价,指針 "*" 靠近變量
例子: NSString *userName;
方法的聲明和定義
- 在 - 惭适、+ 和 返回值 之間留一個空格,方法名和第一個參數(shù)之間不留空格
例子:
- (id)initWithNibName:(NSString *)nibNameOrNilbundle:(NSBundle *)nibBundleOrNil
{
// some code
}
代碼縮進
- 使用 xcode 默認縮進楼镐,即 tab = 4空格
- 使用 xcode 中 re-indent 功能定期對代碼格式進行整理
- 相同類型變量聲明需要獨行聲明
例子:
CGFloatoringX = frame.origin.x;
CGFloatoringY = frame.origin.y;
CGFloatlineWidth = frame.size.width;
- Method與Method之間空一行
例子:
#pragma mark - private methods
- (void)samplePrivateMethod
{...}
- (void)sampleForIf
{...}
對method進行分組
- 使用 #pragma mark - 方式對類的方法進行分組
例子:
#import "SomeModel.h"
#import "SomeView.h"
#import "SomeController.h"
#import "SomeStore.h"
#import "SomeHelper.h"
#import <SomeExternalLibrary/SomeExternalLibraryHeader.h>
#pragma mark - 靜態(tài)成員的定義
static NSString * const XYZFooStringConstant = @"FoobarConstant";
static CGFloat const XYZFooFloatConstant = 1234.5;
@interface XYZFooViewController () <XYZBarDelegate>
#pragma mark - 私有成員的定義
@property (nonatomic, copy, readonly) Foo *foo;
@end
@implementation XYZFooViewController
#pragma mark - Lifecycle ViewController生命周期
- (instancetype)initWithFoo:(Foo *)foo;
- (void)dealloc;
#pragma mark - View Lifecycle view 頁面 生命周期
- (void)viewDidLoad;
- (void)viewWillAppear:(BOOL)animated;
#pragma mark - prepareData 準備數(shù)據(jù)
- (void)prepareData;
#pragma mark - Layout UI準備和布局相關
- (void)prepareUI;
- (void)makeViewConstraints;
#pragma mark - Public Interface 公共接口
- (void)startFooing;
- (void)stopFooing;
#pragma mark - User Interaction 用戶交互 按鈕事件相關
- (void)foobarButtonTapped;
#pragma mark - XYZFoobarDelegate Delegate代理
- (void)foobar:(Foobar *)foobar didSomethingWithFoo:(Foo *)foo;
#pragma mark - Internal Helpers 內部公用方法
- (NSString *)displayNameForFoo:(Foo *)foo;
@end
大括號寫法
- 對于類的method: 左括號另起一行寫(遵循蘋果官方文檔)
例子:
- (id)initWithNibName:(NSString *)nibNameOrNilbundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil
bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- 對于其他使用場景: 左括號跟在第一行后邊
例子:
- (void)sampleForIf
{
BOOL someCondition = YES;
if(someCondition) {
// do something here
}
}
- (void)sampleForWhile
{
int i = 0;
while (i < 10) {
// do something here
i = i + 1;
}
}
- (void)sampleForSwitch
{
SampleEnum testEnum = SampleEnumTwo;
switch(testEnum) {
caseSampleEnumUndefined:{
// do something
break;
}
caseSampleEnumOne:{
// do something
break;
}
caseSampleEnumTwo:{
// do something
break;
}
default:{
NSLog(@"WARNING: there is an enum type not handled properly!");
break;
}
}
- 任何需要寫大括號的部分癞志,不得省略
錯誤示例:
- (void)wrongExamples
{
BOOLsomeCondition = YES;
if (someCondition)
NSLog(@"this is wrong!!!");
while(someCondition)
NSLog(@"this is wrong!!!");
}
Block寫法
根據(jù)
block
的長度,有不同的書寫規(guī)則:
- 較短的
block
可以寫在一行內框产。 - 如果分行顯示的話凄杯,
block
的右括號}
應該和調用block
那行代碼的第一個非空字符對齊。 -
block
內的代碼采用4個空格的縮進秉宿。 - 如果
block
過于龐大戒突,應該單獨聲明成一個變量來使用。
^
和(
之間描睦,^
和{
之間都沒有空格膊存,參數(shù)列表的右括號)
和{
之間有一個空格。
//較短的block寫在一行內
[operation setCompletionBlock:^{ [self onOperationDone]; }];
//分行書寫的block忱叭,內部使用4空格縮進
[operation setCompletionBlock:^{
[self.delegate newDataAvailable];
}];
//使用C語言API調用的block遵循同樣的書寫規(guī)則
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參數(shù)列表同樣可以縮進后在新行書寫
[[SessionService sharedService]
loadWindowWithCompletionBlock:
^(SessionWindow *window) {
if (window) {
[self windowDidLoad:window];
} else {
[self errorLoadingWindow];
}
}];
//龐大的block應該單獨定義成變量使用
void (^largeBlock)(void) = ^{
// ...
};
[_operationQueue addOperationWithBlock:largeBlock];
//在一個調用中使用多個block,注意到他們不是像函數(shù)那樣通過對齊的窑多,而是同時進行了4個空格的縮進
[myObject doSomethingWith:arg1
firstBlock:^(Foo *a) {
// ...
}
secondBlock:^(Bar *b) {
// ...
}];
工程規(guī)范
一、Xcode工程規(guī)范
目錄結構參考
- 為了避免文件雜亂洼滚,物理文件應該保持和 Xcode 項目文件同步埂息。
- Xcode 創(chuàng)建的任何組(group)都必須在文件系統(tǒng)有相應的映射。
- 為了更清晰遥巴,代碼不僅應該按照類型進行分組千康,也可以根據(jù)功能進行分組。
Class/
├─ Main
├─ Category 分類
├─ Controller 根控制器铲掐,
├─ Lib 第三方庫
├─ Other 配置文件和APPdelegate
├─ Tool 工具類
├─ Model 公共模型
├─ View 公共視圖
├─ module1 功能模塊1
├─ model 模型
├─ Controllers 控制器
├─ Views 視圖
├─ Tool 工具類
├─ module2 功能模塊2
├─ model 模型
├─ Controllers 控制器
├─ Views 視圖
├─ Tool 工具類
編譯警告
- 如果可以的話拾弃,盡可能一直打開 target Build Settings 中 "Treat Warnings as Errors" 以及一些[額外的警告][Xcode-project_1]。
- 如果你需要忽略指定的警告,使用 [Clang 的編譯特性][Xcode-project_2] 摆霉。
[Xcode-project_1]:http://boredzo.org/blog/archives/2009-11-07/warnings
[Xcode-project_2]:http://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas
簡單的來說豪椿,至少需要在 _“Other Warning Flags” 編譯設置里面定義下面的值:
-Wall _(增加很多的警告)_
-Wextra _(增加更多的警告)_
同時打開 “Treat warnings as errors”
Assets資源
Asset catalogs
是管理你所有項目可視化資源的最好方式,它們可以同事管理通用的以及設備相關的iPhone 4-inch
,iPhone Retina
,iPad
等資源携栋,并且會自動通過它們的名字分組搭盾。告訴你的設計師如何添加它們(
Xcode
有內置的Git
客戶端)可以節(jié)省很多時間,否則你會話很多時間來在從郵件或者其他渠道復制到代碼庫里面婉支。它可以讓設計師馬上嘗試資源改變的樣子鸯隅,并且反復實驗。
Using Bitmap Images使用位圖
-
Asset catalogs
僅僅暴露了圖片的名稱向挖,圖片集里面的抽象的名字蝌以。這可以避免資源名字的沖突炕舵,就像button_large@2x.png
的文件的命名空間在它的圖片集里面。遵守一些命名規(guī)則可以讓生活更美好:
IconCheckmarkHighlighted.png // Universal, non-Retina
IconCheckmarkHighlighted@2x.png // Universal, Retina
IconCheckmarkHighlighted~iphone.png // iPhone, non-Retina
IconCheckmarkHighlighted@2x~iphone.png // iPhone, Retina
IconCheckmarkHighlighted-568h@2x~iphone.png // iPhone, Retina, 4-inch
IconCheckmarkHighlighted~ipad.png // iPad, non-Retina
IconCheckmarkHighlighted@2x~ipad.png // iPad, Retina
修飾后綴 -568h, @2x, ~iphone and ~ipad
是不必要的跟畅,但是有他們在文件里面咽筋,當把文件拖進去的時候,Xcode
會正確地處置它們碍彭。這避免賦值錯誤晤硕。
使用向量圖
- 你可以用設計師原始的
vector graphics (PDFs)
加入到asset catalogs
,Xcode
可以自動地根據(jù)它們生成位圖庇忌。這減少了你的工程的復雜性(管理更少的文件)舞箍。
調試
當你的
App
崩潰的時候,Xcode
不會默認進入到調試器里面皆疹。為了調試疏橄,你需要增加一個異常斷點(在
Xcode
的Debug
導航中點+
),來在異常發(fā)生的時候退出執(zhí)行略就。在很多情況下捎迫,你需要看看觸發(fā)這些異常的代碼。它會捕捉任何異常表牢,即使是已經處理的窄绒。如果
Xcode
在 一個第三方庫里面中斷執(zhí)行,比如崔兴,你可能需要通過選擇Edit Breakpoint
并且設置Exception
為Objective-C
彰导。對于視圖
debug
,Reveal
和Spark Inspector
這兩個強有力的可視化檢查工具可以幫你省下很多時間敲茄,特別是在你使用Auto Layout
并且希望定位出問題或者溢出屏幕的視圖的時候位谋。Xcode
提供了免費的類似功能 ,但是只能適用于iOS 8+
并且不那么好用堰燎。
二掏父、性能分析
Instruments分析
Xcode
有一個叫Instruments
的分析工具,它包括了許多分析內存秆剪,CPU
赊淑,網(wǎng)絡通訊,圖形以及更多的工具仅讽,它有點復雜的趟章,但是它的追蹤內存泄漏的時候還是蠻直觀的摹察。只需要在
Xcode
中 選擇Product > Profile
酸纲,選擇Allocations
咖楣, 點擊Record
按鈕并且用一些有用的字符串過濾申請空間的信息,比如你自己的app
的類名。它會在固定的列中統(tǒng)計伶贰,并且告訴你每個對象有多少實例蛛砰。到底是什么類一直增加實例導致內存泄漏。
Instruments
也有自動化的工具來進行錄制并且運行UI交互以及JavaScript
文件黍衙。UI Auto Monkey
是一個自動化隨機點擊泥畅、滑動以及旋轉你的app
的腳本,他在壓力琅翻、滲透測試中很有用位仁。
Clang靜態(tài)分析
-
Clang
編譯器(Xcode
使用的)有一個 靜態(tài)分析器 來進行你的代碼控制和數(shù)據(jù)流的分析,來檢測編譯器不能檢測的許多錯誤方椎。 - 你可以通過在
Xcode
里面手動運行Product → Analyze
菜單項來手動執(zhí)行代碼分析 - 分析器可以用淺或者深的模式允許聂抢,后者更加慢,但是可以從跨函數(shù)的控制流和數(shù)據(jù)流上分析更多問題
推薦
- 打開 所有 分析器檢查 (通過在
building setting
中打開所有Static Analyzer
選項) - 在
release
的編譯設置里面打開Analyze during 'Build'
來讓分析器自動在發(fā)布的版本構建的時候允許棠众。(這樣你就不需要記住要手動運行了) - 把
Mode of Analysis for ‘Analyze’
設置為Shallow (faster)
- 把
Mode of Analysis for ‘Build’
設置為to Deep
Faux Pas
- 我們自己的
Ali Rantakari
創(chuàng)建的琳疏,Faux Pas
是一個極佳的靜態(tài)錯誤檢測工具,它分析你的代碼并且找出那些你自己甚至都沒發(fā)現(xiàn)的問題闸拿。在提交你的App
到應用商店前用它吧空盼!
三、日志處理
Crash 崩潰查看
參考 http://www.reibang.com/p/e428501ff278
總結作者 https://github.com/ZHThinker
- 我們每次打包產品交付給測試部門時新荤,通常會運行archive編譯輸出揽趾,輸出后會產生.app 和 .dSYM文件,我們會將.app交付給測試部門苛骨。
- 測試部門在測試時遇到崩潰篱瞎,通常會給我們IPS為擴展名的崩潰日志文件,我們應該怎樣查看這個文件呢智袭?
第一步
- 準備一個 symbolicatecrash 文件
- symbolicatecrash文件地址命令:
find /Applications/Xcode.app -name symbolicatecrash -type f
運行后輸出的是symbolicatecrash文件的地址奔缠,復制 .symbolicatecrash 文件出來到桌面crash文件夾內,地址是: /Users/zhang/Desktop/crash/
第二步
- 將.app和.dSYM以及.symbolicatecrash全部都放到一個文件夾 /Users/zhang/Desktop/crash/ 將IPS文件更該擴展名為.crash也存放在一起
- 如果以下4個文件都準備好了之后
.app掠抬、 .crash吼野、 .dSYM、 .symbolicatecrash
第三步
- 執(zhí)行(注意路徑要根據(jù)自己mac 的情況進行修改两波,文件名字也要修改)
./symbolicatecrash /Users/xxx/Desktop/crash/IXQ-2017-01-05-170207.crash /Users/xxx/Desktop/crash/IXQ.app.dSYM > Control_symbol.crash
- 如果命令執(zhí)行后報錯
Error: "DEVELOPER_DIR" is not defined at /usr/local/bin/symbolicatecrash line 53
- 執(zhí)行以下命令:
export DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer"
第四步
- 再次執(zhí)行第三步瞳步,會得到一個Control_symbol.crash 文件,此文件為crash 日志文件腰奋,可查看詳細的崩潰信息
Crash Logs崩潰日志
應該讓你的 app 向一個服務發(fā)送崩潰日志单起。你可以手動實現(xiàn),通過 PLCrashReporter 以及你自己的后端劣坊。但是強烈推薦你使用現(xiàn)有的服務嘀倒,比如下面的
當你配置好后,確保你 保存了 the Xcode archive (.xcarchive)
對于每一個 app
放出的版本。
這個 歸檔中包含了構建的app
的二進制以及調試符號dSYM
测蘑,你需要用每個版本特定的app
把你的 Crash
報告符號化灌危。
Crash log的獲取
當你的app
在手機上crash
的時候,會在手機上自動生成一個崩潰日志碳胳,也就是我們說的Crash Log
勇蝙。
CrashLog
的位置位于:
iPhone
設備的var/mobile/Library/Logs/CrashReporter
我們要獲取的就是設備中的這個CrashLog
。
獲取用戶的Crash log
注意挨约。這里的用戶指的是你的app已經上架到AppStore上后的用戶味混。
作為開發(fā)者,你想要獲取到你的用戶的崩潰日志的話就得通過 iTunes Connect
了诫惭。在 iTunes Connect
上的 Manage Your Applications -> View Details -> Crash Reports
這種方式有個前提翁锡,就是用戶設備同意上傳相關信息,打開了診斷與用量這個選項設置->隱私->診斷與用量
獲取測試機的Crash log
很多測試人員在測試途中贝攒,或者開發(fā)者在自測的途中盗誊,會遇到APP crash
的情況。
一般的bug
隘弊,一個合格的測試可以給出明確的重現(xiàn)步驟讓開發(fā)者清晰地知道bug
原因哈踱;
也有不少bug
,很多時候是偶現(xiàn)的梨熙,很可能無法再次重現(xiàn)出來开镣,無法重現(xiàn)出來的bug
是開發(fā)者頭疼的,測試一般會給出bug
的截圖和重現(xiàn)步驟咽扇;
而一般crash
是比較嚴重的問題了(所以千萬不能當什么都沒發(fā)生過邪财,不然會被打的233),這個時候崩潰日志就尤為重要了质欲,把崩潰日志send
給開發(fā)人員树埠,如此才能讓開發(fā)者快速定位到錯誤的原因和位置。
那么測試如何拿到crash
日志呢嘶伟?
方法一:連接電腦怎憋,通過iTools高級選項來獲取崩潰日志(Mac版的找不到高級選項T.T,望賜教補充)
方法二:連接電腦九昧,去本地目錄找
Mac :~/Library/Logs/CrashReporter/MobileDevice/<DEVICE_NAME>
Windows : C://Users/<USERNAME>/AppDataRoamingApple/ComputerLogsCrashReporterMobileDevice/<DEVICE_NAME>/
這個時候你會發(fā)現(xiàn)一大堆的.crash
文件和.ips
文件
方法三:通過Xcode獲取到崩潰日志绊袋,方法是
Xcode->Window->Devices
Crash Log的符號化
獲取到了.crash
或者.ips
文件的時候(別糾結這兩個文件有什么差,改下后綴名就ok)铸鹰,用文本編輯器打開文件是一堆十六進制的內存地址癌别,你會郁悶的發(fā)現(xiàn)壓根看不懂。
Q:十六進制內存地址可以改成看得懂的么蹋笼?
A:當然展姐,將這些十六進制地址轉化成方法名稱和行數(shù)的過程稱之為Symbolication(符號化)
躁垛。符號化很簡單,只要你把你的.crash
文件拉到上面提到過的Xcode
的device log
里面圾笨,然后幾秒鐘后就會符號化缤苫。但是這里有個前提,就是這個發(fā)生crash
的版本包必須是你自己的Xcode
里面Archive
出來的(這個是蘋果自帶的方法墅拭,會自動檢測是否含有匹配的.dSYM
文件和應用二進制文件)活玲。
Crash Log的分析
接下來就讓我們對已經符號化以后的crash
文件進行分析。
網(wǎng)上已有的分類比較多谍婉,我這里直接把我目前一般找crash
原因的模塊展示出來舒憾,其他的就留待各位自己去研究了,分別是設備和crash
信息穗熬、異常信息镀迂、線程信息
1、首先是設備和crash
信息
Incident Identifier: F3573A...E2F244A //crash的id
CrashReporter Key: cc2298...es77eeb //crash的設備id
Hardware Model: iPhone7,2 //手機型號
Process: [AppName] [1816] //APP的名字[進程的id]
Path: /private/.../Application... //APP的位置
Identifier: com.... //bundle ID
Version: 14 (2.3.5) //版本號
Code Type: ARM-64 (Native) //app的應用架構之類不大清楚唤蔗,^_^
Parent Process: launchd [1]
Date/Time: 2015-10-26 15:03:29.29 +0800 //crash發(fā)生時間
Launch Time: 2015-10-26 14:58:28.28 +0800 //進入應用時間
OS Version: iOS 9.1 (13B143) //iOS版本
Report Version: 105
當你有大量的crash
文件的時候探遵,你就可以對crash
文件里面的 Hardware Model
,Version
妓柜, OS Version
等進行分類箱季,就可以獲知到很多信息,比如說棍掐,你會知道crash
一般發(fā)生原因是因為手機型號藏雏,還是App
版本,或者還是手機版本的原因作煌。
2掘殴、其次是異常信息
Exception Type: EXC_BAD_ACCESS (SIGABRT) //異常的類型
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000118 //異常子類型
Triggered by Thread: 0 //異常發(fā)生的線程(0為主線程,其他為子線程)
3粟誓、線程信息
Last Exception Backtrace:
0 CoreFoundation 0x182780f48 __exceptionPreprocess + 124
1 libobjc.A.dylib 0x197333f80 objc_exception_throw + 56
2 CoreFoundation 0x182780e90 +[NSException raise:format:] + 120
3 [AppName] 0x100c42a40 UmengSignalHandler + 144
4 libsystem_platform.dylib 0x197d6193c _sigtramp + 52
5 [AppName] 0x1005d9f38 CScopePtr<IAVGAudioLogic>::operator IAVGAudioLogic*<IAVGAudioLogic>() (xprefc.h:165)
6 [AppName] 0x1005d3b8c tencent::av::AVRoomMultiImpl::GetAudioLogic() (av_room_multi_impl.h:119)
7 [AppName] 0x10057076c tencent::av::AVAudioCtrlImpl::SetAudioOutputMode(int) (av_audio_ctrl_impl.cpp:443)
8 [AppName] 0x10044dc3c -[AVBasicManager changeSpeakerMode:] (AVManager.mm:525)
9 [AppName] 0x100296e1c -[KTQAVRoom enableSpeakerMode:] (KTQAVRoom.m:345)
10 [AppName] 0x1002970d0 -[KTQAVRoom settingSpeaker:] (KTQAVRoom.m:362)
11 [AppName] 0x1003d5464 -[KTChatView onAudioNotificationReceived:] (KTChatView.m:685)
恩奏寨。。鹰服。這符號化以后應該可以看懂了吧病瞳,這個crash
的問題應該是騰訊第三方的一個沖突
一般來說,通過異常信息和線程信息就可以找到crash
的原因了获诈。
補充一些異常類型信息
這里參考了很多信息仍源,有很多的異常類型心褐,有些沒遇到過舔涎,這里就厚顏摘抄過來了(這里是原文地址:iOS Crash文件的解析,再次感謝大牛們的經驗)
1逗爹、Exception Type
1)EXC_BAD_ACCESS
此類型的Excpetion是我們最長碰到的Crash亡嫌,通常用于訪問了不改訪問的內存導致嚎于。一般EXC_BAD_ACCESS后面的"()"還會帶有補充信息。
- SIGSEGV: 通常由于重復釋放對象導致挟冠,這種類型在切換了
ARC
以后應該已經很少見到了于购。 - SIGABRT: 收到Abort信號退出,通常
Foundation
庫中的容器為了保護狀態(tài)正常會做一些檢測知染,例如插入nil
到數(shù)組中等會遇到此類錯誤肋僧。 - SEGV:(Segmentation Violation),代表無效內存地址控淡,比如空指針嫌吠,未初始化指針,棧溢出等掺炭;
- SIGBUS:總線錯誤辫诅,與 SIGSEGV 不同的是,SIGSEGV 訪問的是無效地址涧狮,而 SIGBUS 訪問的是有效地址炕矮,但總線訪問異常(如地址對齊問題)
- SIGILL:嘗試執(zhí)行非法的指令,可能不被識別或者沒有權限
2)EXC_BAD_INSTRUCTION
此類異常通常由于線程執(zhí)行非法指令導致
3)EXC_ARITHMETIC
除零錯誤會拋出此類異常
2者冤、Exception Code
0xbaaaaaad 此種類型的log意味著該Crash log并非一個真正的Crash肤视,它僅僅只是包含了整個系統(tǒng)某一時刻的運行狀態(tài)。通成娣悖可以通過同時按Home鍵和音量鍵钢颂,可能由于用戶不小心觸發(fā)
0xbad22222 當VOIP程序在后臺太過頻繁的激活時,系統(tǒng)可能會終止此類程序
0x8badf00d 程序啟動或者恢復時間過長被watch dog終止
0xc00010ff 程序執(zhí)行大量耗費CPU和GPU的運算拜银,導致設備過熱殊鞭,觸發(fā)系統(tǒng)過熱保護被系統(tǒng)終止
0xdead10cc 程序退到后臺時還占用系統(tǒng)資源,如通訊錄被系統(tǒng)終止
0xdeadfa11 前面也提到過尼桶,程序無響應用戶強制關閉操灿。
總結
最后總結一些可能會對各位有用的博文:
- iOS應用崩潰日志分析(這最后有一個栗子很有意思)
- 獲取 iOS crash log(分析得很詳細)
- WWDC視頻(2010年的WWDC視頻)
- 官網(wǎng)文檔——Analyzing iOS Application Crash Reports
四、安全規(guī)約
在開發(fā)應用的時候泵督,數(shù)據(jù)的安全性至關重要趾盐,而僅僅用POST請求提交用戶的隱私數(shù)據(jù),還是不能完全解決安全問題小腊。
因此:提交用戶的隱私數(shù)據(jù)時救鲤,一定不要明文提交,要加密處理后再提交
- 常見的加密算法
MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ RSA \ IDEA \ DSA \ AES
- 加密算法的選擇
一般公司都會有一套自己的加密方案秩冈,按照公司接口文檔的規(guī)定去加密就好
這里主要介紹下項目中常用的加密算法MD5
MD5
- 簡單說明
MD5:全稱是Message Digest Algorithm 5本缠,譯為“消息摘要算法第5版”
效果:對輸入信息生成唯一的128位散列值(32個字符)
- MD5的特點
1.輸入兩個不同的明文不會得到相同的輸出值
2.根據(jù)輸出值,不能得到原始的明文入问,即其過程不可逆
- MD5的應用
由于MD5加密算法具有較好的安全性丹锹,而且免費稀颁,因此該加密算法被廣泛使用
主要運用在數(shù)字簽名、文件完整性驗證以及口令加密等方面
- MD5破解
MD5解密網(wǎng)站:http://www.cmd5.com
- MD5改進
現(xiàn)在的MD5已不再是絕對安全楣黍,對此匾灶,可以對MD5稍作改進,以增加解密的難度
加鹽(Salt):在明文的固定位置插入隨機串租漂,然后再進行MD5
先加密阶女,后亂序:先對明文進行MD5,然后對加密得到的MD5串的字符進行亂序
總之宗旨就是:黑客就算攻破了數(shù)據(jù)庫哩治,也無法解密出正確
代碼示例:
#import "HMViewController.h"
#import "NSString+Hash.h"
#define Salt @"fsdhjkfhjksdhjkfjhkd546783765"
@interface HMViewController ()
@end
@implementation HMViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self digest:@"123"]; //
[self digest:@"abc"];
[self digest:@"456"];
}
/**
* 直接用MD5加密
*/
- (NSString *)digest:(NSString *)str
{
NSString *anwen = [str md5String];
NSLog(@"%@ - %@", str, anwen);
return anwen;
}
/**
* 加鹽
*/
- (NSString *)digest2:(NSString *)str
{
str = [str stringByAppendingString:Salt];
NSString *anwen = [str md5String];
NSLog(@"%@ - %@", str, anwen);
return anwen;
}
/**
* 多次MD5
*/
- (NSString *)digest3:(NSString *)str
{
NSString *anwen = [str md5String];
anwen = [anwen md5String];
NSLog(@"%@ - %@", str, anwen);
return anwen;
}
/**
* 先加密, 后亂序
*/
- (NSString *)digest4:(NSString *)str
{
NSString *anwen = [str md5String];
// 注冊: 123 ---- 2CB962AC59075B964B07152D234B7020
// 登錄: 123 --- 202CB962AC59075B964B07152D234B70
NSString *header = [anwen substringToIndex:2];
NSString *footer = [anwen substringFromIndex:2];
anwen = [footer stringByAppendingString:header];
NSLog(@"%@ - %@", str, anwen);
return anwen;
}
@end
1.直接使用MD5加密(去MD5解密網(wǎng)站即可破解)
2.使用加鹽(通過MD5解密之后张肾,很容易發(fā)現(xiàn)規(guī)律)
3.多次MD5加密(使用MD5解密之后,發(fā)現(xiàn)還是密文锚扎,那就接著MD5解密)
4.先加密吞瞪,后亂序(破解難度增加)
注冊和驗證的數(shù)據(jù)處理過程
1.提交隱私數(shù)據(jù)的安全過程 – 注冊
2.提交隱私數(shù)據(jù)的安全過程 – 登錄
五、公共 庫/類 規(guī)約
當程序書寫到一定量的時候驾孔,畢竟要進行封裝芍秆、重構,這樣做的好處:
1.代碼邏輯結構更加清晰翠勉。
2.冗余代碼量減少妖啥,更加清爽。
3.維護量也較低对碌,符合"對擴展開放荆虱,對修改關閉"的軟件架構思想等等。
可以看到通過封裝使一部分成員充當類與外部的接口朽们,而將其他的成員隱蔽起來怀读,這樣就達到了對成員訪問權限的合理控制,使不同類之間的相互影響減少到最低限度骑脱,進而增強數(shù)據(jù)的安全性和簡化程序的編寫工作菜枷。
開閉原則
開閉原則(OCP:Open-Closed Principle)
是指在進行面向對象設計(OOD:Object Oriented Design)中,
設計類或其他程序單位時叁丧,應該遵循以下設計原則:
1.對擴展開放(open)
2.對修改關閉(closed)
開閉原則是判斷面向對象設計是否正確的最基本的原理之一啤誊。
根據(jù)開閉原則,在設計一個軟件系統(tǒng)模塊(類拥娄,方法)的時候蚊锹,應該可以在不修改原有的模塊(修改關閉)的基礎上,能擴展其功能(擴展開放)稚瘾。
1.擴展開放:某模塊的功能是可擴展的牡昆,則該模塊是擴展開放的。軟件系統(tǒng)的功能上的可擴展性要求模塊是擴展開放的孟抗。
2.修改關閉:某模塊被其他模塊調用迁杨,如果該模塊的源代碼不允許修改,則該模塊修改關閉的凄硼。軟件系統(tǒng)的功能上的穩(wěn)定性铅协,持續(xù)性要求是修改關閉的。
這也是系統(tǒng)設計需要遵循開閉原則的原因:
1.穩(wěn)定性:開閉原則要求擴展功能不修改原來的代碼摊沉,這可以讓軟件系統(tǒng)在變化中保持穩(wěn)定狐史。
2.擴展性:開閉原則要求對擴展開放,通過擴展提供新的或改變原有的功能说墨,讓軟件系統(tǒng)具有靈活的可擴展性骏全。
六、三方庫規(guī)約
通過CocoaPods來統(tǒng)一管理第三方庫文件
CocoaPods 安裝
CocoaPods 安裝前準備
- 移除Ruby默認源
gem sources --remove https://rubygems.org/
- 使用新的源
gem sources -a https://ruby.taobao.org/
- 驗證新源是否替換成功
gem sources -l
- 替換成功后
*** CURRENT SOURCES * * *
https://ruby.taobao.org/
CocoaPods 安裝
sudo gem install cocoapods
注意:蘋果系統(tǒng)升級 OS X EL Capitan 后改為:
sudo gem install -n /usr/local/bin cocoapods (v1.0.0)
pod setup(//將 CocoaPods Specs repository復制到你電腦上~/.cocoapods目錄下)
sudo gem update --system
CocoaPods 的使用
- 如果你計劃增加外部依賴(比如尼斧,第三方庫)在你的項目中姜贡,CocoaPods 提供了一個快捷的途徑.
- 新建工程,并在終端中cd到工程文件夾內,在你的 iOS 項目目錄下運行:
pod init
- 它會創(chuàng)建一個 Podfile棺棵, 會管理你所有的依賴楼咳,在 Podfile 中加入你的依賴
- 編輯文件:platform:ios, '8.0'
pod 'AFNetworking', '~> 2.3.1' <-------第三方 - 執(zhí)行下面命令安裝
pod install
- 來安裝第三方庫并且將它們作為 workspace 的一部分,你的 workspace 也會包含你自己的項目烛恤。
- 一般推薦提交你自己的項目的依賴母怜,而不是每個開發(fā)者在一個 checkout之后運行 pod install 。
- 注意在之后缚柏,你需要打開 .xcworkspace 而不是 .xcproject苹熏,否則你的代碼就不能被編譯了,命令:
pod update
會升級所有的 pod 到最新版本币喧,你可以用大量 符號 來定義你期望的版本需求轨域。
關于 Podfile.lock
當你執(zhí)行pod install之后,除了 Podfile 外杀餐,CocoaPods 還會生成一個名為Podfile.lock的文件疙挺,Podfile.lock 應該加入到版本控制里面,不應該把這個文件加入到.gitignore中怜浅。因為Podfile.lock會鎖定當前各依賴庫的版本铐然,之后如果多次執(zhí)行pod install 不會更改版本,要pod update才會改Podfile.lock了恶座。這樣多人協(xié)作的時候搀暑,可以防止第三方庫升級時造成大家各自的第三方庫版本不一致。
將代碼提交到CocoaPods
- 如果你在github共享了一段代碼跨琳,你想把代碼提交到CocoaPods自点,希望其他用戶search 你的項目的名稱就可以找到你,并且 pod install 集成你的代碼到項目內脉让,你就需要學會怎樣將自己的代碼先提交給 CocoaPods servers.
http://www.cnblogs.com/wengzilin/p/4742530.html
七桂敛、開發(fā)流程
初始化 創(chuàng)建master分支
cd ~/workspace/NewProject
git init
touch README.md
git commit -m 'add README.md'
git remote add origin git@10.0.1.254:group/newproject.git git push -u origin master
以上命令完成以下操作:
- 創(chuàng)建了本地git版本庫功炮,
- 創(chuàng)建并提交了README.md文件,
- 連接了git@10.0.1.254:group/newproject.git遠程Git版本庫origin
- 推送當前分支到遠程的 master
創(chuàng)建 develop 分支
初始化 GitFlow
GitFlow 一般使用默認參數(shù)配置即可术唬,在此規(guī)定如下:
- Production Branch 產品主分支:master
- Development Branch 開發(fā)分支:develop
- Feature Branch Prefix 功能分支前綴:feature/
- Hotfix Branch Prefix 熱修復分支前綴:hotfix/
- Release Branch Prefix 發(fā)布分支前綴:release/
- Version Tag Prefix 版本標簽前綴:tag/
設置中薪伏,以/
結尾的是分支前綴,在某些工具中會以文件夾的形式分組顯示粗仓。
命令行:
git flow init [-d]
帶有 -d
參數(shù)時爆安,init
命令將全部使用默認配置;否則宛篇,會提示輸入各分支名稱。
開始開發(fā)
開發(fā)在 feature
的子分支進行。
1呜笑、Start Feature
在一個版本開發(fā)的開始階段袜腥,創(chuàng)建新的Feature分支漆腌。 使用命令:
# 創(chuàng)建 Feature 分支
git flow feature start <name> [<base>]
# 推送 Feature 到遠程庫
git flow feature publish <name>
# 拉取遠程庫的 Feature 分支
git flow feature pull <remote> <name>
開始一個Feature
分支畔派,其中<name>
參數(shù)是 feature
分支的名稱,最終創(chuàng)建的分 支名稱為feature/<name>
;<base>
可選參數(shù)是 develop
分支中的一個Revision
;<remote>
是遠程庫的地址曙蒸,例如
git@10.0.1.254:group/newproject.git
Feature 分支命名規(guī)范:
- 由小寫英文字母召噩、數(shù)字、下劃線構成逸爵。
- 分支名稱應表明當前版本主要功能具滴。
- 例如:
feature/http_refactor
2、Finish Feature
在當前版本的全部需求和功能開發(fā)完成之后师倔,關閉Feature分支构韵。 使用命令:
git flow feature finish <name>
git push
此操作將本地Feature
分支合并到develop
分支并刪除;然后推送本地的develop
分支到遠程的develop
分支。
Feature 分支在關閉之后趋艘,遠程庫的對應分支需要保留疲恢,以備不時之需。
開始測試
提測后的修改在release
的子分支進行瓷胧。
Start Release
Feature
開發(fā)完成后显拳,需要創(chuàng)建一個Release
分支修改Bug
。 使用命令:
git flow release start <name> [<base>]
此操作將創(chuàng)建分支 release/<name>
Release 命名規(guī)范:
- 以發(fā)布版本號命名搓萧,例如:
release/1.1
杂数、release/2.0
Finish Release
在Release
分支完成修改Bug
,達到本次版本發(fā)布要求之后瘸洛,執(zhí)行此操作揍移。使用命令:
git flow release finish <name>
此操作會將此Release
分支合并到master
,然后把master
代碼合并到develop
反肋。本地的Release
分支自動刪除那伐。
鑒于 Finish Release 之后,仍然存在發(fā)版失敗的可能性,所以此時不創(chuàng)建 Tag罕邀。
在本地 Release 分支刪除之后畅形,仍然保留遠程 Release 分支,以備不時之需诉探。
上線之后
熱修復在 hotfix 的子分支進行日熬。
Start Hotfix
上線之后,仍然可能發(fā)現(xiàn)新的Bug
阵具,此時不能中斷新版本的開發(fā)碍遍,要在線上版本的基礎上修改Bug
定铜,也就是“熱修復”阳液。 使用命令:
git flow hotfix start <name> [<base>]
此操作將創(chuàng)建分支 hotfix/<name>
Hotfix 分支命名規(guī)范:
- 前綴:固定為
hotfix/
- 線上版本號:此熱修復的線上版本號,例如
2.0/
- 日期:開始熱修復的日期揣炕,例如
20170305
完整的分支名由以上三部分構成帘皿,例如 hotfix/2.0/20170305
。此方式可以將同一版本的多次 Hotfix
分組畸陡。
Finish Hotfix
解決完線上Bug鹰溜,首先要在當前Hotfix分支測試驗證。驗證成功后丁恭,即可結束此次 熱修復曹动。 使用命令:
git flow hotfix finish <name>
此操作將名為 hotfix/<name>
的hotfix
分支合并到 master
,然后再將 master
分 支合并到 develop
牲览,然后刪除了當前Hotfix
分支墓陈。
鑒于Hotfix
完成之后,仍然可能再次開啟并繼續(xù)修復第献,所以此時不創(chuàng)建Tag
贡必。
正式發(fā)布版本
所謂的正式發(fā)布版本,是指產品正式更新到線上庸毫,線上用戶可以下載或打開新版本的產品使用仔拟。在正式發(fā)布版本之后,需要在 master
分支的對應 Revision
處創(chuàng)建 Tag
飒赃。
可以使用命令 git tag
創(chuàng)建分支并 git push origin –tags
利花,也可以在GitLab
網(wǎng)站完成。
Tag 命名規(guī)范:
- 使用產品的正式版本的真實版本號载佳,作為
Tag
的名稱 - 所有的正式版本必須創(chuàng)建
Tag
- 完整
Tag
以tag/
為前綴晋被,完整Tag名為tag/<name>
產品的正式版本號由產品和測試確定,格式可能不盡相同刚盈。
例如:掃碼槍版本號為 JLB5.0.0
羡洛,Android
某App
的版本號為 1.5.0
,某Web
產品的版本號為 V1.0.3
。
創(chuàng)建 Tag
的時候欲侮,命名與版本發(fā)布的真實版本號相同即可崭闲,并不強制所有項目使用一致的格式。
八威蕉、部署與發(fā)布
上線流程大致分為三部分:
1.證書刁俭,APPID和描述文件的配置
2.Xcode設置
3.iTunes填寫APP信息
1.證書,APPID和描述文件的配置
首先我們要登陸蘋果開發(fā)者中心
登陸開發(fā)者賬號
進入證書韧涨、APPID和描述文件的創(chuàng)建頁面
創(chuàng)建證書
點擊小“+”號創(chuàng)建發(fā)布證書
點擊頁面最下面的Continue按鈕
繼續(xù)點擊最下面的Continue按鈕
CSR文件我們要從鑰匙串里面生成牍戚,點開鑰匙串
讓鑰匙串作為第一響應者,點擊左上角的鑰匙串訪問虑粥,如圖所示:
點擊后填寫CSR文件信息
點擊繼續(xù)以后如孝,然后點擊存儲就OK
然后回到我們證書創(chuàng)建頁面,選取CSR文件娩贷,然后點擊繼續(xù)
這時候我們的發(fā)布證書就創(chuàng)建好了第晰,下載下來后雙擊裝到鑰匙串里面即可
創(chuàng)建APP ID
如果你已經創(chuàng)建了APP ID就不用再次創(chuàng)建,如果沒有彬祖,就跟著一步步來吧
點擊最下面的Continue茁瘦,進入頁面以后點擊Register即可
創(chuàng)建描述文件
接下來創(chuàng)建描述文件(注:創(chuàng)建描述文件是所選擇的發(fā)布證書、APP ID一定要和鑰匙串里的證書储笑、工程里的Bundle Identifier保持一致)
因為我們是發(fā)布到AppStore甜熔,這里我們選擇發(fā)布的描述文件
然后給描述文件起個名字
下載后雙擊裝到Xcode里即可
2.Xcode設置
發(fā)布要改成release模式
添加Bundle display name字段,填寫應用名稱
溫馨提示:寫到這里突倍,工程配置基本完成腔稀,只剩下打包了,后面再介紹打包赘方。
3.iTunes填寫APP信息
首先進入iTunes
填完信息后記得保存
Xcode打包有兩種方法
方法1
把下面文件放到一個比較容易找到的地方
打開iTunes烧颖,找到“應用”
把剛才的文件放到“應用”里
右鍵show in finder ,把生成的ipa包放到桌面上
點開Xcode窄陡,讓Xcode作為第一響應者炕淮,點擊右上角Xcode -> Open Developer Tool -> Application Loader
點擊頁面右下角的選取,把剛生成的ipa包放入即可
方法2
方法二比較簡單
上傳完成以后跳夭,回到我們的itunes
選中要上傳的構建版本后涂圆,點擊完成
保存后,點擊右上角的提交以供審核
點擊提交币叹,OVER润歉!
其他
一、關于Crash
審核的時候一旦出現(xiàn)閃退情況颈抚,那肯定會被拒踩衩,所以程序應盡量做到沒有Crash。
Observer的移除
現(xiàn)在的代碼里面很多需要用到Observer
, 根據(jù)被觀察對象的狀態(tài)來相應的更新UI或者執(zhí)行某個操作. 注冊Observer
很簡單, 但是移除的時候就出問題了, 要么是忘記移除Observer
了, 要么是移除的時機不對. 如果某個被觀察對象已經被釋放了, Observer
還在, 那結果只能是Crash了, 所以切記至少在dealloc
里面移除一下Observer
NSArray,NSDictionary成員的判空保護
在addObject
或insertObject
到NSArray
或者NSDictionary
時最好加一下判空保護, 尤其是網(wǎng)絡相關的邏輯, 如果網(wǎng)絡返回為空(jason
解析出來為空), 但你還是毅然決然的add
到array
里面, 那么就會出現(xiàn)Crash
二、Xcode快捷鍵
圖標
圖標 | 鍵盤 |
---|---|
? | Command |
? | Control |
? | Option |
? | Shift |
文件快捷鍵
快捷鍵 | 描述 |
---|---|
?N | 新文件 |
??N | 新項目 |
?O | 打開 |
?S | 保存 |
??S | 另存為 |
?W | 關閉窗口 |
導航快捷鍵
快捷鍵 | 描述 |
---|---|
?1-8 | 打開 Project/Symbol/Find/Issue/Test/Debug/Breakpoint/Log 導航欄 |
?0 | 顯示/隱藏 左側 tool panel |
??Y | 顯示/隱藏 控制臺 |
??0 | 顯示/隱藏 右側 tool panel |
??1-6 | 打開右側導航欄 |
??J | 在項目導航中定位當前文件(Reveal in Project Navigator) |
?J | 焦點切換(Move Focus)驱富,可快速定位到編輯界面 |
搜索快捷鍵
快捷鍵 | 描述 |
---|---|
??F | 使用項目搜索可以找到某個變量或方法名的被提到的次數(shù)锚赤。可以依據(jù)實例來匹配褐鸥,并可忽略大小寫字母线脚。另外還可以對查找的變量名進行替換。 |
??Up/Down | .h 和 .m文件間的快速切換 |
??O | 可以直接跳轉到指定的代碼文件叫榕。 |
?6 | (鍵入方法/變量名+Enter跳轉)跳轉至當前代碼文件中的代碼行浑侥。如果文件中有上千行代碼,你可以通過該快捷操作來縮小查找范圍晰绎,從而在需要的地方插入代碼以添加新的功能寓落。 |
?1 | 該快捷鍵可打開’Show Related Items‘彈出菜單’。倘若你已經將光標放在了任何方法中寒匙,并點擊‘?1 ’就可以很方便地通過彈出的視圖訪問該方法的所有調用者和被調用者零如。 |
運行調試快捷鍵
快捷鍵 | 描述 |
---|---|
??K | 清除工程(clean) |
?B | 構建應用程序 |
?R | 運行應用程序 |
?. | 停止運行(Stop) |
?\ | 設置/取消斷點躏将;通過鼠標點擊藍色斷點來啟用/禁用當前行斷點锄弱。 |
?Y | 全局激活或禁用所有的斷點,激活進入調試模式(此時斷點藍色可見)祸憋。 |
編輯快捷鍵
快捷鍵 | 描述 |
---|---|
?[/] | 向前/向后縮進 |
?/ | 注釋選中的代碼 |
??←/→ | 折疊當前代碼塊 |
???←/→ | 折疊該文件內所有代碼塊(方法/函數(shù)) |
??[/] | 當前行上移/下移 |
?B | 前移光標 |
?F | 后移光標 |
?P | 移動光標到上一行 |
?N | 移動光標到下一行 |
?A | 移動光標到本行行首 |
?E | 移動光標到本行行尾 |
?K | 刪除本行 |
?D | 刪除光標右邊的字符(一個字符) |
?L | 將插入點置于窗口正中 |