IOS安裝CocoaPods詳情過程https://www.tuicool.com/articles/3yAJR3i
iOS Git的使用: http://www.itdecent.cn/p/1134abfb40c1
pod 'JXCategoryView'
iOS開發(fā)iOS14適配https://www.tuicool.com/articles/BRJBvuR
如何申請(qǐng)接入微信APP支付:http://www.itdecent.cn/p/20d33602877c
iOS接入微信支付:http://www.itdecent.cn/p/49c7515e96e4
myGitHub:2016llf
Aspect Ratio
Aspect Ratio:設(shè)置視圖的寬高比
視圖寬度隨著屏幕寬度變化拉伸時(shí),讓其高度自動(dòng)進(jìn)行等比例拉伸.保持該視圖寬高比不變.
一般先確定寬度(6的尺寸),再設(shè)置寬高比利,
Device RGB
iOS色彩空間——xib和代碼設(shè)置顏色的偏差問題在使用可視化編程時(shí),
在XIB或SB中直接設(shè)置顏色,選擇RGB Slider設(shè)置顏色時(shí),Xcode 中默認(rèn)勾選的是Generic RGB。
解決方式:選擇Device RGB,
//強(qiáng)與弱
__weak typeof(self) weakSelf = self;
[self doSomeBlockJob:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
if (strongSelf) {
...
}
}];
按鈕細(xì)節(jié)問題
[_cancelBtn setTitleColor:UIColorHex(00ACEB) forState:(UIControlStateNormal)];
[_cancelBtn setTitleColor:UIColorHexAndAlpha(00ACEB, 0.5) forState:(UIControlStateHighlighted)];
[_cancelBtn setBackgroundImage:[BYDImageManager imageWithColor:kColorHighlight] forState:UIControlStateHighlighted];
UIViewController
//UIViewController細(xì)節(jié):
self.navigationItem.title = @"XXXX"
等比例縮放圖片
//img:為傳入的圖片; size:為放置圖片區(qū)域的大小; scaledImage:為返回壓縮后的圖片
+ (UIImage *)scaleToSize:(UIImage *)img size:(CGSize)size{
// 創(chuàng)建一個(gè)bitmap的context
// 并把它設(shè)置成為當(dāng)前正在使用的context
UIGraphicsBeginImageContext(size);
// 繪制改變大小的圖片
[img drawInRect:CGRectMake(0,0, size.width, size.height)];
// 從當(dāng)前context中創(chuàng)建一個(gè)改變大小后的圖片
UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();
// 使當(dāng)前的context出堆棧
UIGraphicsEndImageContext();
//返回新的改變大小后的圖片
return scaledImage;
}
內(nèi)存優(yōu)化
1,圖片的讀取采用正確的方式
imageNamed: 會(huì)緩存圖片,用它讀取頻繁用到的小圖片,最惡心的是不知道它到底什么時(shí)候釋放。
imageWithContentsOfFile: 不緩存圖片,適合一次性讀取的大圖片。
NSString *path = [[NSBuddle mainBuddle] pathForResource:@"resourceName" oftype@"resourceType"];
UIImage *image = [[UIImage imageWithContentsOfFile:path];
2,imageWithContentsOfFile 、 Assets.xcassets
對(duì)于大的圖片且偶爾需要顯示的應(yīng)放到工程目錄下,不要放到 Assets.xcassets 中;
并使用 imageWithContentsOfFile 加載不讓系統(tǒng)緩存
對(duì)于經(jīng)常需要展示的小圖片放到 Assets.xcassets 中讓系統(tǒng)緩存,使用 imageNamed 加載
一張圖片 7kb,在5個(gè)地方會(huì)用到;resource會(huì)占用35kb內(nèi)存,imageAssets占用7kb
一張圖片300kb,在一個(gè)地方會(huì)用到;resource會(huì)在使用后會(huì)清除300kb內(nèi)存,imageAssets會(huì)一直占用300kb內(nèi)存
///
這里順便提一下 imageNamed: 和 imageWithContentsOfFile: 的區(qū)別,這兩個(gè) API 都需要解碼,并且工作流程都是一致的。
不過imageNamed:會(huì)做緩存處理,在下一次用到相同的資源時(shí),就會(huì)從緩存里面讀取。而 imageWithContentsOfFile: 則不會(huì)。
其實(shí),大多數(shù)情況下,都是直接使用[UIImage imageNamed:]這種加載本地圖片,既然是使用這種方法,
那么圖片放在Images.xcassets里面和放在單獨(dú)文件夾里面區(qū)別不是很大,
最大的區(qū)別就是Images.xcassets在打包的時(shí)候會(huì)減小包的體積。
數(shù)據(jù)庫(kù)問題
1 數(shù)據(jù)庫(kù)頻繁操作打開關(guān)閉,手動(dòng)打開關(guān)閉鎖, 使用一個(gè)單例類操作數(shù)據(jù)庫(kù)
2 避免同時(shí)操作一個(gè)資源使用隊(duì)列串行方式
Appearance方法
我們通過UIAppearance設(shè)置一些UI的全局效果,這樣就可以很方便的實(shí)現(xiàn)UI的自定義效果
又能最簡(jiǎn)單的實(shí)現(xiàn)統(tǒng)一界面風(fēng)格,但是需要注意使用細(xì)則:
**
1、控件遵守了UIAppearance協(xié)議,才能對(duì)控件進(jìn)行appearance設(shè)置
2、只有被UI_APPEARANCE_SELECTOR這個(gè)宏修飾的屬性才能使用appearance進(jìn)行設(shè)置,其他屬性則不具備該功能
3、appearance設(shè)置需要在該控制顯示之前設(shè)置完成,否則可能無效
**
if (@available(iOS 11.0, *)){
[[UIScrollView appearance] setContentInsetAdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever];
}
if (@available(iOS 15.0, *)) {
[UITableView appearance].sectionHeaderTopPadding = 0;
}
// [[UITableView appearance] setEstimatedRowHeight:0];
[[UITableView appearance] setEstimatedSectionFooterHeight:0];
[[UITableView appearance] setEstimatedSectionHeaderHeight:0];
NSUserDefaults standardUserDefaults中在最后使用synchronize的作用
系統(tǒng)會(huì)保存到該應(yīng)用下的/Library/Preferences/gongcheng.plist文件中。需要注意的是如果程序意外退出,
NSUserDefaultsstandardUserDefaults數(shù)據(jù)不會(huì)被系統(tǒng)寫入到該文件,所以,
要使用[[NSUserDefaultsstandardUserDefaults] synchronize]命令直接同步到文件里,來避免數(shù)據(jù)的丟失。
///小插曲
- (void)test {
NSDictionary *dict = @{@1: @"甲",
@2: @"乙",
@3: @"丙",
@4: @"丁"};
[[NSUserDefaults standardUserDefaults] setObject:dict forKey:@"testKey"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
///報(bào)錯(cuò)
2018-04-16 10:55:04.573393+0800 text[1344:58370] [User Defaults] Attempt to set a non-property-list object {
3 = "\U4e19";
2 = "\U4e59";
1 = "\U7532";
4 = "\U4e01";
} as an NSUserDefaults/CFPreferences value for key testKey
///why
And although NSDictionary and CFDictionary objects allow their keys to be objects of any type,
if the keys are not string objects, the collections are not property-list objects.
雖然 NSDictionary 和 CFDictionary 對(duì)象的 Key 可以為任何類型(只要遵循 NSCopying 協(xié)議即可),
但是如果當(dāng) Key 不為字符串 string 對(duì)象時(shí),此時(shí)這個(gè)字典對(duì)象就不能算是 property list objects 了,
捕捉異常
@try
{
///關(guān)鍵代碼
NSString *str = @"abc";
[str substringFromIndex:111]; // 程序到這里會(huì)崩
}
@catch (NSException *exception)
{
///捕捉異常(彈框提示報(bào)錯(cuò)了)
NSLog(@"%s\n%@", __FUNCTION__, exception);
NSLog(@"%@", exception.name);
NSLog(@"%@", exception.reason);
}
@finally
{
///資源回收完畢!
NSLog(@"我一定會(huì)執(zhí)行");
}
多用字面量語(yǔ)法,少用等價(jià)方法
// 字面量字符串
NSString *str = @"QiShare";
// 字面量數(shù)值
NSNumber *num = @(1);
NSNumber *floatNum = @(1.0);
int x = 5;
float y = 3.14;
NSNumber *num = @(x * y);
// 字面量數(shù)組
NSArray *animals = @[@"cat", @"dog", @"tiger", @"monkey"];
NSString *cat = animals[0];
// 字面量字典
NSDictionary *qiShareDic = @{@"englishName": @"QiShare",
@"chineseName": @"奇分享"}];
NSString *englishName = qiShareDic[@"englishName"];
NSString *chineseName = qiShareDic[@"chineseName"];
//@property()定義一個(gè)成員變量時(shí):1:生成一個(gè)帶有下滑線的成員變量,2:生成成員變量的set和get方法
trong常使用在可變類型:NSMutableArray、NSMutableDictionary、NSMutableString
copy常使用在不可以變類型:NSArray、NSDictionary、NSString
assign常使用在基本類型:NSInteger、NSUInteger,CGFloat,NSTimeInterval
weak常使用在delegate等防止循環(huán)引用的場(chǎng)景
NSString應(yīng)該使用copy與strong關(guān)鍵字
NSMutableString 不要用 copy http://www.itdecent.cn/p/5d138efee024
這里當(dāng)我們用copy修飾可變類型(NSMutableString、NSMutableArray、NSMutableSet)時(shí),竟然崩潰了。因?yàn)楫?dāng)用copy修飾后,NSMutaleArray由可變類型變成了不可變類型,而NSArray并沒有增、刪元素的方法,所以崩潰。因此,可變類型(NSMutableString、NSMutableArray、NSMutableSet),要用strong修飾。
@property (nonatomic, strong) NSString *str1;
@property (nonatomic, copy) NSString *str2;
NSMutableString *mtStr = [NSMutableString stringWithFormat:@"hello"];
self.str1 = mtStr;
self.str2 = mtStr;
[mtStr appendString:@"world"];
NSLog(@"mtStr:%p,, str1:%p,, str2:%p",mtStr, self.str1, self.str2);
// mtStr:0x281641710,, str1:0x281641710,, str2:0xb5284f85e15a82cb
// mtStr,str1指向同一個(gè)對(duì)象
// 而mtStr,str2對(duì)象地址不同,是兩個(gè)不同的對(duì)象,所以copy是深復(fù)制,創(chuàng)建了一個(gè)新的對(duì)象。
NSLog(@"str1-------%@",self.str1);
// str1-------helloworld
// 經(jīng)過strong修飾過的str1卻隨mtStr的改變而改變。
NSLog(@"str2-------%@",self.str2);
// str2-------hello
// 經(jīng)過copy關(guān)鍵字修飾過的str2并沒有因?yàn)閙tStr的變化而變化,
// 如果不希望字串的值跟著賦值的字串的值變化,所以我們一般用copy.
// 如果希望字串的值跟著賦值的字串的值變化,可以使用strong。
//上面的情況是針對(duì)于當(dāng)把NSMutableString賦值給NSString的時(shí)候,才會(huì)有不同,如果是賦值是NSString對(duì)象,那么使用copy還是strong,結(jié)果都是一樣的,因?yàn)镹SString對(duì)象根本就不能改變自身的值,他是不可變的。
//把一個(gè)對(duì)象賦值給一個(gè)屬性變量,當(dāng)這個(gè)對(duì)象變化了,如果希望屬性變量變化就使用strong屬性,如果希望屬性變量不跟著變化,就是用copy屬性。
static:聲明局部變量時(shí),則改變變量的存儲(chǔ)方式(生命期),使變量成為靜態(tài)的局部變量,即編譯時(shí)就為變量分配內(nèi)存,直到程序退出才釋放存儲(chǔ)單元。
//兩個(gè)概念:生命周期、作用域
//static修飾全局變量,擁有局部變量修飾時(shí)候的屬性,不同的是該變量只能被本文件訪問使用。
static int age = 20;
//
- (void)staticTest{
// static修飾局部變量,它的生命周期、作用域都是在這個(gè)代碼塊內(nèi)。
//1,使得局部變量只初始化一次
//2,局部變量在程序中只有一份內(nèi)存,使這個(gè)變量擁有記憶功能(可以被賦值).
//3,局部變量的作用域不變,但是生命周期變了(直到程序結(jié)束才銷毀)
static int age = 0;
age++;
//所以此處輸入的是局部變量的值,在其他部分調(diào)用全局age還是20。
NSLog(@"局部變量的age:%d",age);
}
const:修飾變量,const修飾的變量值是不可變的,(主要強(qiáng)調(diào)變量是不可修改的)
const修飾的是其右邊的值,也就是const右邊的這個(gè)整體的值不能改變。
//staic和const常用使用場(chǎng)景,是用來代替宏,把一個(gè)經(jīng)常使用的字符串常量,定義成靜態(tài)全局只讀變量。
static NSString * const key = @"name";
iOS - Xcode Slicing圖片拉伸的圖文詳解
這里主要講下Slicing里三條線條的意義和作用

也就是當(dāng)圖片拉伸時(shí),用區(qū)域A的圖片元素去不斷復(fù)制填充區(qū)域B的空間,區(qū)域B是被白遮罩層蓋的,這區(qū)域的圖片部分是不可見的,是用于區(qū)域A填充的空間。
線1和線2的區(qū)間為區(qū)域A
線2和線3之間的白遮罩區(qū)間為區(qū)域B




1,先設(shè)置 slicing 圖片拉伸
2,設(shè)置UIImageView的contentMode屬性為Redraw或者scale To Fill
字符串問題
//減少硬編碼
static NSString * const newPushGotoMessageTips = @"前往消息中心";
#define heightItem kAutoSize(64)
//字符串轉(zhuǎn)數(shù)組
NSString *str1 = @"張三, 李四, 王五, 祥子";
NSArray *array1 = [str1 componentsSeparatedByString:@","];
NSLog(@"%@", array1);
(張三, 李四, 王五,祥子,)
//數(shù)組轉(zhuǎn)字符串
NSArray *array2= @[@"哈哈", @"呵呵", @"你好", @"簡(jiǎn)書"];
NSString *str2 = [array2 componentsJoinedByString:@","];
NSLog(@"%@", str2);
哈哈,呵呵,你好,簡(jiǎn)書
//檢查字符串是否為空 或 NSNumber 并替換
+ (NSString *)checkEmpty:(id)value defaultString:(NSString *)defaultString {
if ([value isKindOfClass:[NSString class]] && ((NSString *)value).length) {
return value;
}
if ([value isKindOfClass:[NSNumber class]]) {
return [value stringValue];
}
if ([defaultString isKindOfClass:[NSString class]]) {
return defaultString;
}
return @"";
}
//檢查字符串是否為空
+ (BOOL)checkEmptyString:(NSString *)string {
if ([string isKindOfClass:[NSString class]] && string.length) {
return NO;
}
return YES;
}
//檢查數(shù)組是否為空
+ (BOOL)checkEmptyArray:(NSArray *)array {
if ([array isKindOfClass:[NSArray class]] && array.count) {
return NO;
}
return YES;
}
//檢查字典是否為空
+ (BOOL)checkEmptyDic:(NSDictionary *)dic {
if ([dic isKindOfClass:[NSDictionary class]] && dic.allValues.count) {
return NO;
}
return YES;
}
字符串根據(jù) , 轉(zhuǎn)數(shù)組
if ([model.attr_name length] > 2) {
NSArray *arrayStr = [model.attr_name componentsSeparatedByString:@","];
NSMutableString *attriStr = [NSMutableString string];
for (NSString * str in arrayStr) {
[attriStr appendString:NSStringFromFormat(@"%@\n", str)];
}
[attriStr deleteCharactersInRange:NSMakeRange([attriStr length] - 1, 1)];
self.subTitleLabel.text = attriStr;
}
UITextField
//限制長(zhǎng)度
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textfieldEditChange) name:UITextFieldTextDidChangeNotification object:nil];
- (void)textfieldEditChange{
if (self.phoneTextFiled.text.length > 11) {
self.phoneTextFiled.text = [self.phoneTextFiled.text substringToIndex:11];
}
}
///去掉前后空格
NSString *searchText = textField.text;
searchText = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
UIKeyboard
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
#pragma mark - keyboardWillShow
- (void)keyboardWillShow:(NSNotification *)notification {
CGFloat kbHeight = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
CGFloat offset = kbHeight;
double duration = [[notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
//將視圖上移計(jì)算好的偏移
if(offset > 0) {
[UIView animateWithDuration:duration animations:^{
_contenView.top = kScreenHeight - kAutoSize(323) - offset/2;
}];
}
}
#pragma mark - keyboardWillHide
- (void)keyboardWillHide:(NSNotification *)notify {
double duration = [[notify.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:duration animations:^{
_contenView.top = kScreenHeight - kAutoSize(323);
}];
}
Masonry
//優(yōu)先級(jí)約束
[self.numberLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[self.priceLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
//大于等于10
make.bottom.lessThanOrEqualTo(self).mas_offset(@-10);
//寬高比利1:1
make.width.mas_equalTo(self.leftImageView.mas_height).multipliedBy(1);
//底部安全距離
if (@available(ios 11.0,*)) {
make.bottom.equalTo(self.view.mas_safeAreaLayoutGuideBottom);
}else{
make.bottom.equalTo(@0);
}
///
mas_makeConstraints:
一個(gè)視圖,剛創(chuàng)建出來,沒有任何約束。后期也不會(huì)重置相關(guān)的約束用這個(gè)方法。
已有的約束,再添加約束,不修改原有約束
添加新的約束, 則視圖會(huì)添加這個(gè)約束
不會(huì)刪除已有約束
mas_updateConstraints:
一個(gè)視圖,剛創(chuàng)建出來,沒有任何約束或者已經(jīng)有約束需要去更新相關(guān)約束或者加入約束,但后面不回去重制約束
已有的約束,再添加約束,則更新原有約束
添加新的約束, 則視圖會(huì)添加這個(gè)約束
不會(huì)刪除已有約束
mas_remakeConstraints
一個(gè)視圖雖然已經(jīng)有了約束,但是之前的約束都不要了,需要重新去更新約束。
已有的約束,再添加約束,則更新原有約束
添加新的約束, 則視圖會(huì)添加這個(gè)約束
會(huì)刪除已有的所有約束
Block
- (void)pushViewControllerSuccess:(UIViewController *)viewController
animated:(BOOL)animated
successHandle:(void (^)(void))success
faliedHandle:(void (^)(void))falied;
數(shù)組
//項(xiàng)目開發(fā)過程中可能會(huì)有這種需求,某個(gè)可變數(shù)組不斷地增加元素,同時(shí)
//我們需要判斷新的元素是否已經(jīng)在數(shù)組里,如果不在才添加該元素,否則丟棄
//containsObject:是在比較內(nèi)存地址,即使兩個(gè)對(duì)象內(nèi)容完全一樣,地址不同,那也是不同的。
//我個(gè)人認(rèn)為這個(gè)方法應(yīng)該叫是否存在同一個(gè)對(duì)象
NSMutableArray *defaultArray = [NSMutableArray array];
if (![defaultArray containsObject:searchText]) {
[defaultArray insertObject:searchText atIndex:0];
}
//取前面10個(gè)
if (defaultArray.count > 10) {
[defaultArray subarrayWithRange:NSMakeRange(0, 10)]
}
網(wǎng)絡(luò)數(shù)據(jù)處理
//pageSize == 10
if (isFirst) {
//show轉(zhuǎn)圈圈
}
//成功
if (listArray.count < pageSize) {
dispatch_async(dispatch_get_main_queue(), ^(){
[weakSelf.collectionView.mj_footer endRefreshingWithNoMoreData];
});
}
if (weakSelf.dataPage == 1)
{
[weakSelf.qualityGoodsModeArray removeAllObjects];
(listArray.count == 0) ? (notDataView.hidden = NO) : (notDataView.hidden = YES);
}
else if (weakSelf.dataPage > 1 && listArray.count == 0)
{
weakSelf.dataPage--;
}
[weakSelf.dataArray addObjectsFromArray:listArray];
[weakSelf.collectionView.mj_footer endRefreshing];
weakSelf.collectionView.mj_footer.hidden = NO;
[weakSelf.collectionView reloadData];
//失敗
weakSelf.dataPage--;
[weakSelf.collectionView.mj_footer endRefreshing];
if (weakSelf.dataArray.count > 0) {
weakSelf.collectionView.mj_footer.hidden = NO;
//show吐司(提示無網(wǎng)絡(luò),報(bào)錯(cuò))
return;
}else{
weakSelf.collectionView.mj_footer.hidden = YES;
}
if (isFirst) {
if (error.isNetwork) {
[weakSelf.collectionView statusViewLoadFailed:^{
[weakSelf requestDatafirst:YES];
}];
} else {
[weakSelf.collectionView statusViewLoadError:^{
[weakSelf requestDatafirst:YES];
}];
}
}
多個(gè)請(qǐng)求網(wǎng)絡(luò)無序
dispatch_group_enter :通知 group,下個(gè)任務(wù)要放入 group 中執(zhí)行了
dispatch_group_leave: 通知 group,任務(wù)成功完成,要移除,與 enter成對(duì)出現(xiàn)
dispatch_group_wait: 在任務(wù)組完成時(shí)調(diào)用,或者任務(wù)組超時(shí)是調(diào)用
dispatch_group_notify: 只要任務(wù)全部完成了,就會(huì)在最后調(diào)用
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
//成功
dispatch_group_leave(group);
//失敗
dispatch_group_leave(group);
});
//
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
//成功
dispatch_group_leave(group);
//失敗
dispatch_group_leave(group);
});
//
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
//成功
dispatch_group_leave(group);
//失敗
dispatch_group_leave(group);
});
//
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//TODO:
});
多個(gè)網(wǎng)絡(luò)請(qǐng)求有序
用信號(hào)量機(jī)制使異步線程完成同步操作
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_group_async(group, queue, ^{
//1
//成功1(發(fā)送一個(gè)信號(hào))
dispatch_semaphore_signal(semaphore);
//失敗1(發(fā)送一個(gè)信號(hào))
dispatch_semaphore_signal(semaphore);
//等待信號(hào)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
dispatch_group_async(group, queue, ^{
//2
//成功2(發(fā)送一個(gè)信號(hào))
dispatch_semaphore_signal(semaphore);
//失敗2(發(fā)送一個(gè)信號(hào))
dispatch_semaphore_signal(semaphore);
//等待信號(hào)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
dispatch_group_async(group, queue, ^{
//3
//成功3(發(fā)送一個(gè)信號(hào))
dispatch_semaphore_signal(semaphore);
//失敗3(發(fā)送一個(gè)信號(hào))
dispatch_semaphore_signal(semaphore);
//等待信號(hào)
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
});
//
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//TODO:
});
VC返回指定的VC
for (UIViewController *subVC in self.navigationController.viewControllers) {
if ([subVC isKindOfClass:[BYDAfterSalesGoodsVC class]]) {
[self.navigationController popToViewController:subVC animated:YES];
break;
}
}
URL跳支付寶支付
///白名單
<key>LSApplicationQueriesSchemes</key>
<array>
<string>alipay</string>
<string>alipayshare</string>
</array>
<key>LSApplicationQueriesSchemes</key>
///
BOOL isSucc = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:resultModel.payinfo]];
if (!isSucc) {
[UIFactory showToast:@"用戶未安裝支付寶客戶端"];
}else{
[weakSelf paySuccessEvent];
}
WKWebView加載html字符串
WKWebView * webView = [[WKWebView alloc]init];
webView.navigationDelegate = self;
webView.frame = self.view.bounds;
[webView loadHTMLString:self.htmlStr baseURL:nil];
[self.view addSubview:webView];
- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
NSLog(@"網(wǎng)頁(yè)導(dǎo)航加載完畢");
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
//修改字體大?。ǚ椒ㄒ唬? NSString *fontSize = [NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%f%%'",kAutoSize(250)];
[webView evaluateJavaScript:fontSize completionHandler:nil];
}
導(dǎo)航欄按鈕問題:大小24*24,距離20
//
UIButton * searchBtn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, kAutoSize(24), kAutoSize(24))];
[searchBtn setImage:UIImageWithName(@"Top_search_icon") forState:(UIControlStateNormal)];
[searchBtn addTarget:self action:@selector(touchSearchClick) forControlEvents:(UIControlEventTouchUpInside)];
UIBarButtonItem * searchBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:searchBtn];
//
UIBarButtonItem *fixedSpaceBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
fixedSpaceBarButtonItem.width = kAutoSize(20);
//
UIButton * scanBarBtn = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, kAutoSize(24), kAutoSize(24))];
[scanBarBtn setImage:UIImageWithName(@"shop_scan_icon") forState:(UIControlStateNormal)];
[scanBarBtn addTarget:self action:@selector(touchScanVinClick) forControlEvents:(UIControlEventTouchUpInside)];
UIBarButtonItem * scanBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:scanBarBtn];
//
self.navigationItem.rightBarButtonItems = @[scanBarButtonItem,fixedSpaceBarButtonItem,searchBarButtonItem];
getset
@property (nonatomic,strong) BYDSentryVideoInfo *model;
-(void)setModel:(BYDSentryVideoInfo *)model
{
_model = model;
}
進(jìn)入后臺(tái)做耗時(shí)操作
- (void)applicationDidEnterBackground:(UIApplication *)application
{
//阻塞主線程
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for(int i=0;i<10000;i++)
{
NSLog(@"i->> %d",i);
}
//在這里你處理一些事情
});
}
不允許在 dealloc 的時(shí)候取 weak self.
- (void)dealloc
{
[_segmentView removeFromSuperview];
}
項(xiàng)目規(guī)范問題:
1,屏幕適配:kAutoSize()
2,字體適配:UIFontSize()
3,按鈕高亮狀態(tài)
[secondBtn setBackgroundImage:[ImageManager imageWithColor:kColorHighlight] forState:UIControlStateHighlighted];
4,tableview:先隱藏tableView,拿到數(shù)據(jù),再顯示tableView
5,多個(gè)網(wǎng)絡(luò)請(qǐng)求:順序執(zhí)行有依賴關(guān)系(用信號(hào)量一個(gè)一個(gè)執(zhí)行有序),并發(fā)執(zhí)行( 加到group里執(zhí)行玩再處理)
6,無網(wǎng)絡(luò)狀態(tài),加載失敗狀態(tài),無數(shù)據(jù)狀態(tài)。(占位圖+文字+按鈕)(正在加載...)(加載失敗)(上傳中...)(網(wǎng)絡(luò)異常,請(qǐng)檢查網(wǎng)絡(luò)設(shè)置)
7,吐司規(guī)范:宏定義
8,接口返回錯(cuò)誤碼規(guī)范
9,訂單列表:列表沒數(shù)據(jù)轉(zhuǎn)圈圈,有數(shù)據(jù)不轉(zhuǎn)圈圈,上拉下拉也不轉(zhuǎn)圈圈,
底部(endRefreshingWithNoMoreData)
10,判斷是否越獄手機(jī),越獄手機(jī)直接提示不支持使用,點(diǎn)擊確定退出應(yīng)用。
11,數(shù)據(jù)模式跟UI分開,模型里面不能寫UI。
12,Model的網(wǎng)絡(luò)請(qǐng)求用減方法(實(shí)例方法,必須通過實(shí)例化的對(duì)象調(diào)用)。
13,第三方的方法不能直接調(diào)用,都要二次封裝使用。
項(xiàng)目風(fēng)險(xiǎn)安全問題:
1,梆梆安全
2,微信支付
3,支付寶支付
4,上架審核
5,軟件著作權(quán)
6,埋點(diǎn)
第三方
SwipeTableView 一款好用的,既能上下滾動(dòng)又能左右滑動(dòng)的控件SwipeTableView。
keyChain是ios中唯一可以存儲(chǔ)安全可靠敏感數(shù)據(jù)的地方。而且應(yīng)用被卸載,數(shù)據(jù)也不會(huì)被刪除,所以非??煽?。蘋果官方的操作keychain,比較繁瑣和隱晦,這里使用開源的第三方庫(kù)SAMKeychain。
Bugly
優(yōu)化
1,圖片壓縮:刪除腫的元數(shù)據(jù)。通過壓縮圖像節(jié)省磁盤空間和帶寬,而不會(huì)降低質(zhì)量:https://imageoptim.com/mac
2,后臺(tái)給業(yè)務(wù)部門?個(gè)圖?上傳的標(biāo)準(zhǔn),業(yè)務(wù)部門上傳的圖?處理成標(biāo)準(zhǔn)范圍內(nèi)再上傳(20-100kb)
3,列表頁(yè)顯示縮略圖,詳情頁(yè)使用原始圖
4,項(xiàng)目管理從svn(管理方便,適合開發(fā)人數(shù)不多的項(xiàng)目開發(fā);但服務(wù)器壓力太大,數(shù)據(jù)庫(kù)容量暴增。 如果不能連接到服務(wù)器上,基本上不可以工作。)轉(zhuǎn)成git(適合分布式開發(fā),強(qiáng)調(diào)個(gè)體)
5,iOS路由(MGJRouter) 跳轉(zhuǎn)
CMMI認(rèn)證
CMMI全稱是Capability Maturity Model Integration, 即軟件能力成熟度模型集成,是由美國(guó)國(guó)防部與卡內(nèi)基-梅隆大學(xué)和美國(guó)國(guó)防工業(yè)協(xié)會(huì)共同開發(fā)和研制的,其目的是幫助軟件企業(yè)對(duì)軟件工程過程進(jìn)行管理和改進(jìn),增強(qiáng)開發(fā)與改進(jìn)能力,從而能按時(shí)地、不超預(yù)算地開發(fā)出高質(zhì)量的軟件。其所依據(jù)的想法是:只要集中精力持續(xù)努力去建立有效的軟件工程過程的基礎(chǔ)結(jié)構(gòu),不斷進(jìn)行管理的實(shí)踐和過程的改進(jìn),就可以克服軟件開發(fā)中的困難。CMMI為改進(jìn)一個(gè)組織的各種過程提供了一個(gè)單一的集成化框架,新的集成模型框架消除了各個(gè)模型的不一致性,減少了模型間的重復(fù),增加透明度和理解,建立了一個(gè)自動(dòng)的、可擴(kuò)展的框架。因而能夠從總體上改進(jìn)組織的質(zhì)量和效率。CMMI主要關(guān)注點(diǎn)就是成本效益、明確重點(diǎn)、過程集中和靈活性四個(gè)方面。
自測(cè)的問題
1,iOS,Android的實(shí)現(xiàn),兩端同事多溝通,保證邏輯,交互,界面統(tǒng)一。
2,中文文字帶上中文的標(biāo)點(diǎn)符號(hào)。
3,每周二代碼評(píng)審
4,手機(jī)號(hào)判斷:只彈出數(shù)字鍵盤,判斷(長(zhǎng)度11位)&&(首位是1)
5,下單按鈕防重點(diǎn)
6,手機(jī)app性能指標(biāo)記錄
7,收集手機(jī)app有關(guān)隱私權(quán)限,以及提示語(yǔ)
項(xiàng)目中遇到的崩潰
//奔潰提示:
**[__NSArrayM info]: unrecognized selector sent to instance 0x280e2bb10**
//原因:解析后臺(tái)返回的數(shù)組,數(shù)組里面包含有兩個(gè)模型。第一個(gè)為空,調(diào)用第一個(gè)模型發(fā)生崩潰
XXXModel *model = listArray[0];
model.info
//解決:判斷對(duì)象是否是某個(gè)類型或某個(gè)類型子類的對(duì)象
XXXModel *model = listArray[0];
if ([XXXModel isKindOfClass:[XXXModel class]]) {
model.info
}
//總結(jié):造成unrecognized selector sent to instance XXX,
//大部分情況下是因?yàn)閷?duì)象被提前release了,在你心里不希望他release的情況下,指針還在,對(duì)象已經(jīng)不在了。
后期項(xiàng)目管理
1,每次發(fā)版本前都會(huì)走查bugly,解決崩潰問題。
2,每次新功能開發(fā)完都會(huì)代碼走查。
3,每次發(fā)版本前都會(huì)進(jìn)行發(fā)布評(píng)審:
- bug修復(fù)與驗(yàn)證
- 強(qiáng)關(guān)功能
- SDK更新
- 機(jī)型適配
- 注意事項(xiàng),加固,代碼混淆,關(guān)閉Log日志,關(guān)閉新特性,版本備份,項(xiàng)目配置