1.單個控制器監(jiān)聽進(jìn)入后臺
在該控制器的-viewDidLoad方法中典奉,添加代碼監(jiān)聽notification最爬,也可以使用監(jiān)聽APP返回方法
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(someMethod:)
name:UIApplicationDidBecomeActiveNotification object:nil];
監(jiān)聽方法的具體實(shí)現(xiàn)
-(void)someMethod:(NSNotification *)noti
{
? ? ? ? //從該控制器進(jìn)入后臺時需要執(zhí)行的代碼
}
恢復(fù)到前臺
- (void)applicationDidBecomeActive:(UIApplication *)application{
????NSLog(@"---applicationDidBecomeActive----");
}
2.十六進(jìn)制字符串轉(zhuǎn)換成字節(jié)數(shù)組.
目標(biāo)字符串 NSString *str = @"0200107580FD7590FD750FD7590FD75A0FD";
調(diào)用方法:NSData *temp = [string hexToBytes]; ?轉(zhuǎn)換后
?byte數(shù)組?Byte byteArr[] = { 0x02, 0x00, 0x10, ... , ?0xFD };
3肚医、對于項目中的第三庫一定要進(jìn)行再次封裝匙奴,包括網(wǎng)絡(luò)叙赚、刷新怨咪、提示乏矾、模型轉(zhuǎn)換等所有能封裝的部分孟抗,一直用MJExtension來做字典轉(zhuǎn)模型,突然想用YYModel了钻心,項目中替換很麻煩凄硼,刷新也一樣,一直用第三方框架捷沸,突然想自己寫摊沉,改起來麻煩的不要不要的;
4、熟悉一下測試的幾種方案痒给,例如交叉測試(一個功能正在運(yùn)行说墨,另一個功能運(yùn)行對它的影響,例如 掃碼時打開燈光苍柏,突然退到后臺尼斧,再回來查看,可能燈光已經(jīng)熄滅试吁,按鈕還沒改變狀態(tài))等棺棵,這樣寫程序時才知道往哪些方面考慮
5、多寫點(diǎn)代碼塊,寫起代碼來會很快烛恤,我把自定義Cell都封裝了代碼塊母怜,用xib布局cell就沒有純手寫這么快了,改起來還麻煩,這就是代碼塊的好處棒动;
6糙申、主控制器因?yàn)榇a比較多,結(jié)構(gòu)一定要清晰船惨,才方便尋找柜裸,插入的類按 服務(wù)工具類+MVC 劃分,屬性按修飾符劃分粱锐,下面代碼按功能劃分疙挺,如下
#import "ViewController.h"
// 工具和服務(wù)類
#import "Header.h"
#import "Tool1.h"
#import "Tool2.h"
// Model
#import "Model1.h"
#import "Model2.h"
#import "Model3.h"
// View
#import "View1.h"
#import "View2.h"
#import "View3.h"
// Controller
#import "ViewController1.h"
#import "ViewController2.h"
#import "ViewController3.h"
@interface ViewController ()
// 按修飾符劃分
@property (nonatomic, assign) NSInteger num1;
@property (nonatomic, assign) NSInteger num2;
@property (nonatomic, strong, nonnull) NSMutableArray<NSString *> *object3;@property (nonatomic, strong, nonnull) NSMutableArray<NSNumber *> *object4;
@property (nonatomic, copy, nullable) NSString *object5;
@property (nonatomic, copy, nullable) NSString *object6;
@property (nonatomic, weak) UILabel *object1;
@property (nonatomic, weak) UILabel *object2;
@end
@implementation ViewController
- (void)viewDidLoad {? ?
????[super viewDidLoad]; ? ?
}
#pragma mark - 初始化View
- (void)initView{
?}
#pragma mark - 系統(tǒng)方法,界面顯示到銷毀
#pragma mark - 代理
#pragma mark - 按鈕點(diǎn)擊怜浅,通知铐然,定時器
#pragma mark - 輔助方法#pragma mark - 懶加載
@end
7、定時器不是馬上開始的恶座,多久觸發(fā)一次事件搀暑,多久才開始,記得在退出頁面的時候釋放定時器,否則控制器不會釋放跨琳;
8自点、如果錯誤提示中出現(xiàn)了duplicate這樣的字眼,很可能就是引入了.m文件
9脉让、UIView的tag不能為0桂敛;
10、字典轉(zhuǎn)JSON字符串溅潜;
NSData *data = [NSJSONSerialization dataWithJSONObject:params options:NSJSONWritingPrettyPrinted error:nil];
NSString *paramStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
11术唬、有時在動畫過程中,需要避免用戶重復(fù)操作滚澜,否則很容易崩潰粗仓。
建議動畫過程中設(shè)置[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
允許用戶操作[[UIApplication sharedApplication] endIgnoringInteractionEvents];
12博秫、如果延時執(zhí)行事件會被多次觸發(fā)潦牛,那是一件很危險的事情,需要取消前面的延時執(zhí)行事件
[selfperformSelector:<#(nonnull SEL)#>
withObject:<#(nullable id)#>afterDelay:<#(NSTimeInterval)#>];// 延時執(zhí)行
[NSObject cancelPreviousPerformRequestsWithTarget:<#(nonnull id)#>
selector:<#(nonnull SEL)#>object:<#(nullable id)#>]// 取消延時執(zhí)行
13挡育、測試某部分代碼的運(yùn)行時間
NSTimeInterval beginTime = CFAbsoluteTimeGetCurrent();
......// 執(zhí)行代碼
NSTimeInterval endTime = CFAbsoluteTimeGetCurrent();
time = endTime-beginTime;// 運(yùn)行時間
14、對某個控件截圖
UIGraphicsBeginImageContextWithOptions(view.bounds.size,NO,0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
15朴爬、添加毛玻璃效果
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:effect];
effectView.contentView = 控件;
16即寒、添加長按手勢,在手勢開始時才執(zhí)行方法,避免方法被調(diào)用兩次
- (void)longPress:(UILongPressGestureRecognizer *)longPressGesture{
????if (UIGestureRecognizerStateBegan != longPressGesture.state) {
????????return;
????}
????... // 執(zhí)行方法
}
17母赵、輸入框有值時才能點(diǎn)擊return key
textField.enablesReturnKeyAutomatically = YES;
18逸爵、isKindOfClass判斷對象是否是一個類的成員,或者是派生自該類的成員isMemberOfClass確定對象是否是當(dāng)前類的成員;
19凹嘲、tableView設(shè)置cell的分割線從屏幕左側(cè)邊緣開始
?cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0);
20师倔、tableView當(dāng)內(nèi)容不夠時,去掉底部的分割線
self.tableView.tableFooterView = [[UIView alloc]init];
21周蹭、UITableView設(shè)置為Plain的樣式時趋艘,你又有多組時,組頭就會默認(rèn)有懸浮效果凶朗,停留在上邊瓷胧,如果不想組頭懸浮在上邊,可以將樣式設(shè)為Grouped,把足部設(shè)置很小棚愤,解決這問題搓萧;
UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(x,y,w,h) style:UITableViewStyleGrouped];
tableView.sectionFooterHeight = 0.0001;
22、設(shè)置UITableViewCell之間的間距,在自定義cell中重寫setFrame方法
-(void)setFrame:(CGRect)frame{
????frame.origin.y += 5;
????frame.size.height -= 5;
????[super setFrame:frame];
}
23宛畦、修改UISearchController上searchBar的風(fēng)格瘸洛,遍歷子控件(很有用),找到合適的, 設(shè)置想要的子控件的顏色和分格次和;
UIImageView *barImageView = self.searchController.searchBar.subviews[0].subviews[0];
barImageView.layer.borderColor = [UIColor lightGrayColor];
barImageView.layer.borderWidth = 1;
UIView *textView = self.searchController.searchBar.subviews[0].subviews[1];
textView.backgroundColor = [UIColor whiteColor];
24反肋、監(jiān)測WKWebView的加載進(jìn)度
[wkWebView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
25、一個控件獲取在某個控件上的坐標(biāo)點(diǎn)的四種方式
// 獲取View在window上的坐標(biāo)點(diǎn)的四種寫法
// 使用 convertRect:toRect 方法
CGRect rect = [view convertRect:view.bounds toRect:window];
CGRect rect = [view.superView convertRect:view.frame toRect:window];
// 使用 convertRect:from 方法
CGRect rect = [window convertRect:view.boundsfrom:view];
CGRect rect = [window convertRect:view.framefrom:view.superView];
26斯够、iOS11獲取最上面的window
// iOS 11 以前
UIView *windowView = [[UIApplication sharedApplication].windows lastObject];
// iOS 11 以后
UIView *windowView = [[UIApplication sharedApplication].windows firstObject];
27囚玫、某個控件有雙擊和單擊時,設(shè)置雙擊失敗時读规,才觸發(fā)單擊
[oneTap requireGestureRecognizerToFail:doubleTap];
28抓督、設(shè)置圖片捏合縮放,雙擊放大
// 首先把imageView添加到scrollview中
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
????return self.imageView;
????// 在代理返回當(dāng)前imageView現(xiàn)
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView{
????// 保證繞著中心點(diǎn)縮放
????????CGSize boundsSize = self.scrollView.bounds.size;
????????CGRect frameToCenter = self.imageView.frame;
????????if (frameToCenter.size.width < boundsSize.width) {
????????????frameToCenter.origin.x = floorf((boundsSize.width - frameToCenter.size.width) * 0.5f);
????????} else {
????????????frameToCenter.origin.x = 0;
????????}
????????if (frameToCenter.size.height < boundsSize.height) {
????????????????frameToCenter.origin.y = floorf((boundsSize.height - frameToCenter.size.height) * 0.5f);
????????}else {
????????????????frameToCenter.origin.y = 0;
????????}
????????if (!CGRectEqualToRect(self.imageView.frame, frameToCenter)) {
????????????????self.imageView.frame = frameToCenter;
????????}
}
-(void)doubleTap:(UITapGestureRecognizer *)tapBgRecognizer{
????CGFloat scale = 4; // 最大縮放比例
????if (self.self.imageView.frame.frame.size.width < kScreenWidth * scale) {
????????CGPoint point = [tapBgRecognizer locationInView:self.imageView.frame];
????????CGFloat xSize = kScreenWidth / scale;
????????CGFloat ySize = kScreenHeight / scale;
????????CGRect zoomRect = CGRectMake(point.x - xSize * 0.5f, point.y - ySize * 0.5f, xSize, ySize);
????????self.scrollView.maximumZoomScale = scale;
????????// 以點(diǎn)擊點(diǎn)為中心縮放到最大
????????[self.scrollView zoomToRect:zoomRect animated:YES];
????} else {
????????[UIView animateWithDuration:0.25 animations:^{
????????self.scrollView.zoomScale = 1.0;
????????self.scrollView.contentSize = self.scrollView.bounds.size;
? ? ????self.self.imageView.frame.frame = self.originFrame; }];
????}
}
29束亏、尋找當(dāng)前控件的控制器
-(UIViewController*)ht_viewController{
????for(UIView *next = self; next; ?next = next.superview){
????????UIResponder *nextResponder = [next nextResponder];
????????if([nextResponder isKindOfClass:[UIViewController class]]{
????????????return (UIViewController *)nextResponder;
????????}
????}
????return nil;
}
30铃在、UITextField的inputView屬性是指第一響應(yīng)的不是鍵盤,而是賦值給inputView的那個view碍遍, inputAccessoryView 是指往鍵盤上添加另一個view;
31定铜、設(shè)置鍵盤在UIScrollView拖動動時消失
scrollview.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag
32、設(shè)置UITableViewCell之間的分割線顏色怕敬;
self.tableView.separatorColor = [UIColor redColor];
33揣炕、iOS9以后點(diǎn)擊狀態(tài)欄,UIScrollView可返回頂部;
34东跪、顯示狀態(tài)欄的網(wǎng)絡(luò)請求菊花畸陡;
// 顯示菊花-----NO為關(guān)閉菊花
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
35鹰溜、讓UILabel的字體適應(yīng)指定的寬度,當(dāng)寬度大時丁恭,字體不變曹动, 寬度小時, 字體變小適應(yīng)寬度
label.adjustsFontSizeToFitWidth = YES;
36牲览、監(jiān)聽拖動進(jìn)度條時的狀態(tài)
監(jiān)聽拖動進(jìn)度條時的狀態(tài)
[slider addTarget:self action:@selector(sliderChange:event:) forControlEvents:UIControlEventValueChanged];
- (void)sliderChange:(UISlider *)slider event:(UIEvent *)event{
????UITouch *touch = [[event allTouches] anyObject];
????// 根據(jù)狀態(tài)來做相應(yīng)的事情墓陈,避免拖動時一直調(diào)用某些事件
????switch (touch.phase) {
????????case UITouchPhaseBegan: // 開始
????????case UITouchPhaseMoved: // 拖動
????????case UITouchPhaseEnded: // 結(jié)束
????????default:
????????????break;
????????}
}
37、讓UITableView的某一行滾到底部第献;
[self.tableView scrollToRowAtIndexPath:indexPath? ? atScrollPosition:UITableViewScrollPositionBottom animated:YES];
38贡必、以Modal的形式push出一個界面;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.75];
[self.navigationController pushViewController:vc animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
[UIView commitAnimations];
39痊硕、阻止設(shè)備自動鎖屏[UIApplication sharedApplication].idleTimerDisabled = YES;在后臺不管用赊级,退出當(dāng)前頁面時,記得設(shè)為NO
40岔绸、為了避免循環(huán)引用理逊,在block中我們一般都用弱引用,但是block中的弱引用對象可能會提前釋放盒揉,造成崩潰晋被,我們需要在block中強(qiáng)引用一下這個弱對象;
__weak __typeof(self)weakSelf = self;
view.callback = ^(ViewStatus status) {
????// 強(qiáng)引用這個對象刚盈,避免執(zhí)行到一半 self釋放羡洛,造成崩潰;
????__strong __typeof(weakSelf)strongSelf = weakSelf;
????[strongSelf doSomething];
}
41藕漱、如果一個參數(shù)中需要包含多個枚舉值欲侮,用NS_OPTIONS,不要用NS_ENUM
// 位運(yùn)算保證任意組合的枚舉值進(jìn)行或運(yùn)算能得到唯一的值
typedefNS_OPTIONS(NSUInteger,TestName){
????????TestNameXiaoHua=1<<0,// 小花
????????TestNameXiaoBai=1<<1,// 小白
????????TestNameXiaoHei=1<<2// 小黑
};
[self eat:TestNameXiaoHua | TestNameXiaoBai];// 讓小花和小白有飯吃肋联;
-(void)eat:(TestName)name{
????if( (name & TestNameXiaoHua) || (name & TestNameXiaoBai) ){
????????NSLog(@"有飯吃");
????}
}
42威蕉、快速生成一個帶值的可變字典
NSMutableDictionary *mutDic = @{@"key":@"value"}.mutableCopy;
43、忽略編譯器警告
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"????// 設(shè)置要忽略的類型 這里是GNU警告
// 代碼
#pragma clang diagnostic pop
44橄仍、為了避免多線程訪問數(shù)據(jù)庫韧涨,造成數(shù)據(jù)混亂,讓讀寫方法都在同一個隊列中進(jìn)行侮繁;
static const void * const IOKey = &IOKey;
// 開辟一個單例隊列
dispatch_queue_t NTESDispatchIOQueue(){
????static dispatch_queue_t queue;
????static dispatch_once_t onceToken;
????dispatch_once(&onceToken, ^{
????// dispatch_queue_create("", DISPATCH_QUEUE_SERIAL) queue = dispatch_queue_create("io.queue", 0);
????dispatch_queue_set_specific(queue, IOKey, (void *)IOKey, NULL); // 設(shè)置隊列的的標(biāo)記 });
????return queue;
}
typedef void(^dispatch_block)(void);
void io_sync_safe(dispatch_block block){
????// 如果是自己設(shè)置的隊列虑粥,執(zhí)行block
????if (dispatch_get_specific(IOKey)) {
????????block();
????} else// 如果不是自己設(shè)置的隊列,先創(chuàng)建隊列宪哩,再執(zhí)行block {
????????dispatch_sync(NTESDispatchIOQueue(), ^() {
????????block();
????});
}
45娩贷、監(jiān)聽UITextField值的改變,可以使用這個方法
[_textViewaddTarget:self.action:@selector(textFieldDidChangeValue:)forControlEvents:UIControlEventEditingChanged]
而不要使用這個代理锁孟,因?yàn)榭赡鼙O(jiān)聽不到
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { }育勺,
46但荤、把C++算法庫封裝在OC文件里形成靜態(tài)庫時罗岖,記得把OC的.m文件改成.mm文件
47涧至、如果視圖里面存在唯一一個UIScrollView或其子類View時,會主動設(shè)置相應(yīng)的內(nèi)邊距桑包,避免被導(dǎo)航欄遮住南蓬,如果我們的導(dǎo)航欄不透明,原點(diǎn)會從我們的導(dǎo)航欄下方算起哑了,導(dǎo)致上方留白赘方,解決這問題:
if (@available(iOS 11.0, *)) {
????????self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;????????//UIScrollView也適用
}else {
????????self.automaticallyAdjustsScrollViewInsets = NO;
?}
48、如果數(shù)組中的元素是唯一的弱左,或者要查詢某個數(shù)據(jù)是否在該數(shù)組中窄陡,不要使用NSArray, 而是使用集合NSSet,集合采用的是哈希表,查詢速度更快拆火;
49跳夭、動畫里的萬能神器CAShapeLayer,性能特別好,能實(shí)現(xiàn)很多神奇的效果们镜,做什么動畫前優(yōu)先考慮它币叹,尤其做股票財經(jīng)、健康A(chǔ)PP類的模狭,經(jīng)常需要畫圖颈抚,如果遇到性能問題,試試它嚼鹉;
50贩汉、swift中為了避免循環(huán)引用,我們使用weak或者unowned來解決锚赤,但它們是有區(qū)別的匹舞; unowned更像OC里的unsafe_unretained,當(dāng)引用對象釋放了以后宴树,它仍然會保持對引用對象的一個無效引用策菜,如果嘗試調(diào)用方法和成員屬性的話,程序就會崩潰酒贬;? weak則會在引用的內(nèi)容被釋放后又憨,它會自動地變成 nil;? 因此我們在使用它時锭吨,如果你引用對象不會釋放蠢莺, 使用unowned,寫起來方便點(diǎn)零如;? 如果你引用對象會被釋放躏将,請使用weak,例如網(wǎng)絡(luò)請求锄弱;
51、在swift中用強(qiáng)制解包!一定要非常小心祸憋,盡量少用会宪,一不小心程序就崩潰了;
52蚯窥、在swift中數(shù)組和字典都屬于值類型瓤鼻,相當(dāng)于int類型淋硝,跟oc不一樣墨林,當(dāng)你把數(shù)組賦值給另一個數(shù)組饥伊,修改數(shù)組的值不會影響另一個數(shù)組;
53荷鼠、__bridge 用于OC指針與c語言中的 void *互相轉(zhuǎn)換句携,雖然?id 和void *能夠相互轉(zhuǎn)換。但轉(zhuǎn)換為void *允乐,其安全性與賦值給__unsafe_unretained修飾符相近矮嫉,甚至?xí)汀H绻芾頃r不注意賦值對象的所有者喳篇,就會因懸垂指針而導(dǎo)致程序崩潰敞临。具體細(xì)節(jié),參考?__bridge 的那些事兒
54麸澜、void* 類型指針:通用變體類型指針挺尿;可以不經(jīng)轉(zhuǎn)換,賦給其他指針炊邦,函數(shù)指針除外编矾;malloc返回的就是void*類型。
NULL指針:是一個標(biāo)準(zhǔn)規(guī)定的宏定義馁害;#define NULL ((void *) 0) ? ? ?用來表示空指針常量窄俏;
零指針:指針值為0,零值指針碘菜,沒有存儲任何內(nèi)存地址的指針凹蜈;可以使任意一種指針類型,eg:void * 忍啸;int * 仰坦;double *;
空指針:指針賦值為0计雌;0*7悄晃;3-3等之后,指針即變成空指針凿滤;即:空指針不指向任何實(shí)際的對象或者函數(shù)妈橄;NULL指針和零指針都是空指針庶近。
野指針:指向垃圾內(nèi)存的指針;(1)指針變量沒有初始化(2)指針被delete或者free之后沒有置為空(3)指針操作超越了變量的范圍
懸垂指針:指向曾經(jīng)存放對象的內(nèi)存眷蚓,但是該對象已經(jīng)不存在了鼻种;delete操作完成后的指針就是懸垂指針,此時需要將指針置為0變?yōu)榱阒抵羔槪?/p>
55溪椎、WKWebView 與 JS 交互普舆,需要添加?[userController addScriptMessageHandler:self name:@"callFunction"]; ?callFunction 可自定義,與 JS 保持一致校读,才可交互。
于控制器中添加 evaluateJavaScript:方法
56.關(guān)于 -> 語法 與 .語法
self -> _topview 這個是把 self 當(dāng)成了個結(jié)構(gòu)體指針祖能;
self.topview 是把self 當(dāng)成了一個對象歉秫,或者說是結(jié)構(gòu)體變量;
另外养铸,self-> 不會觸發(fā) set方法雁芙,self. 會觸發(fā)。
. 左側(cè)可以是結(jié)構(gòu)體變量钞螟,也可以是對象兔甘;->?左側(cè)肯定是當(dāng)成 結(jié)構(gòu)體指針。
像這種用法鳞滨, k 就是個結(jié)構(gòu)體變量洞焙,p 是取了k 的地址,所以p 是個 astrct 類型指針拯啦,他就可以用->
成員變量 + 讀寫方法 = 類屬性
簡單直接的理解方式:.語法是去訪問類屬性澡匪,->是訪問成員變量。?. 語法用于尋址褒链,在c 語言中唁情,左側(cè)必須是個類型變量。而 - > 用于間接尋址甫匹。比如下圖
驗(yàn)證上面所說
第一行 &k 和 &(k.a)的地址完全一樣甸鸟,是因?yàn)樵谶@個結(jié)構(gòu)體中,于內(nèi)存存儲的時候兵迅,最開始的部分存放的就是a抢韭,然后緊接著就是b,當(dāng)拿到這個結(jié)構(gòu)題類型的變量K, 實(shí)際上就是拿到存儲的首地址喷兼。
而第二行的 p 篮绰,其實(shí)是 指針p 自身的地址,而指針指向的是 k季惯。
57.Implicit declaration of function XXX is invalid in C99
? ? ** 和CNCopySupportedInterfaces CNCopyCurrentNetworkInfo 等相關(guān)的錯?需要?#import <SystemConfiguration/CaptiveNetwork.h>
58.關(guān)于?armv7吠各、armv7s臀突、arm64、i386贾漏、x86_64 的區(qū)別
arm64:iPhone6s | iphone6s plus|iPhone6| iPhone6 plus|iPhone5S | iPad Air| iPad mini2(iPad mini with Retina Display)
armv7s:iPhone5|iPhone5C|iPad4(iPad with Retina Display)
armv7:iPhone4|iPhone4S|iPad|iPad2|iPad3(The New iPad)|iPad mini|iPod Touch 3G|iPod Touch4
i386 是針對intel通用微處理器32位處理器
x86_64是針對x86架構(gòu)的64位處理器
模擬器32位處理器測試需要i386架構(gòu)候学;
模擬器64位處理器測試需要x86_64架構(gòu);
真機(jī)32位處理器需要armv7,或者armv7s架構(gòu)纵散;
真機(jī)64位處理器需要arm64架構(gòu)梳码;
58.界面出來之前 xib 中的 frame 都不要去使用∥橄疲可以在viewDidAppear 方法里設(shè)置??♂?
59.使用CocoaPods創(chuàng)建自己的私有庫掰茶,首次使用?pod lib lint 可能遇到的問題
這個問題是pod依賴的組件fourflusher與xcode版本不匹配造成的,可以使用如下命令:
1.sudo gem uninstall fourflusher?
2.sudo gem install fourflusher
必要情況下還需要更新pod
sudo gem update cocoapods
[!] TestLib did not pass validation, due to 3 warnings (but you can use `--allow-warnings` to ignore them).?
pod驗(yàn)證發(fā)現(xiàn)3個及以上的warning就會報這個錯蜜笤,如果只是驗(yàn)證一下工程濒蒋,能確保對外發(fā)布之前能修復(fù),可以使用 --allow-warnings
pod lib lint --allow-warnings
如果驗(yàn)證通過把兔,會看到 TestLib passed validation 沪伙,到這一步既完成驗(yàn)證。
60.WKWebView 背景透明
[self.webView setOpaque:NO];
[self.webView setBackgroundColor:[UIColor clearColor]];
[self.webView.scrollView setBackgroundColor:[UIColor clearColor]];
61.ARC 情況下堆县好、棧注意點(diǎn)
如圖第二個Block處不使用Copy發(fā)生崩潰,通過打印可以發(fā)現(xiàn)2個Block所處區(qū)域不同缕贡,前者?blk0 在堆區(qū)翁授,而后面的blk1在棧,容易被系統(tǒng)回收善绎,在ARC 的情況下一般就直接拷貝到堆上去黔漂。
62.App 或 Mac 程序內(nèi)使用WebView播放網(wǎng)絡(luò)視頻,禁止自動全屏:
? ? 目前在做一個Mac程序的監(jiān)控設(shè)備播放禀酱,由JavaScript控制播放炬守,發(fā)現(xiàn)程序在加載頁面后會自動彈出播放器并進(jìn)行全屏播放,碰巧視頻是采用如?.m3u8 格式剂跟,結(jié)果在退出全屏后减途,除非重新加載頁面,否則視頻無法播放曹洽;
WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];? ?
configuration.allowsInlineMediaPlayback = true;? ?
self.webView =[[WKWebView alloc] initWithFrame:CGRectMake(0,20,W,H-20)configuration: configuration];
如果使用的是UIWebView:
self.webView.allowsInlineMediaPlayback = YES;
如果是在Xib中創(chuàng)建鳍置,需要勾選Inline Playback選項:
63.手機(jī)連接打印機(jī)
let printVC = UIPrintInteractionController.init()? ? ? ?
let printInfo = UIPrintInfo.printInfo()? ? ? ?
printInfo.outputType = .general? ? ? ?
printInfo.duplex = .longEdge? ? ? ?
printVC.showsPaperSelectionForLoadedPapers = true? ? ? ?
printVC.printInfo = printInfo? ? ? ?
printVC.printFormatter = webView.viewPrintFormatter()? ? ? ?
printVC.present(animated: true, completionHandler: nil)
64.關(guān)于可變數(shù)組添加對象
? ? 假設(shè)有臨時變量可變數(shù)組A,可變數(shù)組B送淆,可變數(shù)組B中有若干元素税产,當(dāng)可變數(shù)組A執(zhí)行 AddObject 添加數(shù)組B后,僅是添加可變數(shù)組B的指針,即數(shù)組B的首地址辟拷,當(dāng)操作數(shù)組B后撞羽,如移除數(shù)組元素,數(shù)組A中的數(shù)據(jù)也會隨之改變衫冻。
? ? 同理诀紊。數(shù)組A在添加字符串C后,改變字符串C的值隅俘,數(shù)組A中的元素也會改變邻奠。
65.dealloc 方法被調(diào)用后,不代表對象的內(nèi)存立刻被回收为居。詳情可以了解一下runloop內(nèi)部autoRelase的釋放機(jī)制.
66.ARC情況下碌宴,關(guān)于控制器dealloc未執(zhí)行,導(dǎo)致沒有移除通知的預(yù)防措施
????假設(shè) A颜骤、B唧喉、C三個類,都繼承自 D 類忍抽,即D類為基類,層級關(guān)系為A push B董朝,B push C鸠项,由此可以知道,程序會當(dāng)C出棧時子姜,會執(zhí)行dealloc方法祟绊,然后D類執(zhí)行dealloc,接著B執(zhí)行dealloc哥捕,D又執(zhí)行dealloc牧抽,最后是A執(zhí)行dealloc,D再執(zhí)行dealloc遥赚。故而我們可以根據(jù)這一特性來設(shè)計扬舒。
? ? 首先定義一個全局的NSCache 來存儲 某個類class,其內(nèi)部監(jiān)聽所有KVO的Key凫佛,即?class 作為NSCache 的key, 所監(jiān)聽 key的數(shù)組作為Value讲坎,也就是一個類有多個通知的情況,然后在基類的delloc中愧薛,檢查是否存在這樣的key-value晨炕,如存在,for循環(huán)Remove毫炉。
? ? 解釋:假設(shè)因?yàn)镃類中的block強(qiáng)弱引用問題瓮栗,或NSTime未釋放等原因?qū)е耫eallo未執(zhí)行,通知未移除。而當(dāng)B類出棧時若正常執(zhí)行dealloc费奸,程序會自動調(diào)用基類的dealloc弥激,其方法內(nèi)檢查到NSCache中有通知未移除,就移除通知货邓。以達(dá)到防止內(nèi)存泄漏的目的秆撮。
67. arrarWithArray 等效于 alloc init 的方式創(chuàng)建數(shù)組
68. 關(guān)于copy與mutableCopy
69. 不可變字符串相當(dāng)于常量,初始化后换况,只有當(dāng)程序結(jié)束運(yùn)行才會被釋放职辨,并不會因?yàn)槌隽撕瘮?shù)作用域或者控制器被銷毀而釋放
驗(yàn)證:開始執(zhí)行for循環(huán),循環(huán)創(chuàng)建1億個String對象戈二,CPU與內(nèi)存開始上漲
循環(huán)結(jié)束舒裤,CPU使用率下降,內(nèi)存占有率不變
70.?WWDC 2020 觉吭,蘋果宣布當(dāng)用戶退款成功時腾供,無論哪種內(nèi)購類型,開發(fā)者都能收到退款通知!
當(dāng)Apple受理了用戶(玩家)的退款申請后鲜滩,即允許退款后伴鳖,蘋果服務(wù)器會發(fā)送通知,(商家)通過處理退款信息以響應(yīng)退款通知徙硅,達(dá)到因用戶(退款)而采取的相應(yīng)行動榜聂,如扣除相關(guān)訂閱服務(wù)或游戲道具等。
詳細(xì)說明:https://developer.apple.com/documentation/storekit/in-app_purchase/handling_refund_notifications
在蘋果后臺可以配置一個退款通知的回調(diào)地址(一個App配置一條鏈接):
配置的回調(diào)鏈接必須滿足條件:
滿足應(yīng)用傳輸安全要求(使用https)
URL 最長 255 字符
注意:這里的?https?是指蘋果的 App Transport Security (ATS)嗓蘑,其中有協(xié)議的要求须肆,比如使用 Transport Layer Security (TLS) protocol 1.2 版本,具體見蘋果文檔:Preventing Insecure Network Connections | Apple Developer Documentation桩皿。
蘋果把回調(diào)的通知分為2種類型:
退款通知類型
取消通知類型
其中新增加的退款通知類型是針對:
消耗型
非消耗型
非續(xù)期訂閱
取消通知類型是針對:
自動續(xù)期訂閱
退款通知流程
退款通知的內(nèi)容:
蘋果返回的通知內(nèi)容為 JSON 對象數(shù)據(jù)豌汇,所有的退款訂單的通知是在?unified_receipt?里的?latest_receipt_info?數(shù)組中:
在?unified_receipt?里的?latest_receipt_info?是一個數(shù)組,其中包含的最近的100次應(yīng)用內(nèi)購買交易:
數(shù)據(jù)中每個退款訂單的主要字段:
詳細(xì)的返回字段見官方文檔:
responseBody | Apple Developer Documentation
unified_receipt | Apple Developer Documentation
responseBody.Latest_receipt_info | Apple Developer Documentation
退款通知的響應(yīng)
您的服務(wù)器應(yīng)發(fā)送HTTP狀態(tài)代碼泄隔,以指示服務(wù)器到服務(wù)器的通知接收是否成功:
如果回調(diào)接收成功拒贱,則發(fā)送 HTTP?200。您的服務(wù)器不需要返回數(shù)據(jù)梅尤。
如果回調(diào)接收不成功柜思,請發(fā)送 HTTP?50x?或?40x?讓 App Store 重試該通知。App Store在一段時間內(nèi)嘗試重試該通知巷燥,但在連續(xù)失敗嘗試后最終停止(3次)赡盘。
注意事項:
當(dāng)您使用包含退款交易的收據(jù)?transaction_data?向蘋果服務(wù)器校驗(yàn)?verifyReceipt?時,JSON響應(yīng)中不存在退款交易缰揪,自動續(xù)訂訂閱除外陨享。
收到?REFUND?通知時葱淳,您有責(zé)任為每筆退款交易存儲,監(jiān)控并采取適當(dāng)?shù)拇胧┡坠谩#ㄒ驗(yàn)樘O果只通知一次赞厕,暫時無法在蘋果后臺查詢退款的訂單。也不能由開發(fā)者主動去蘋果服務(wù)器查詢定硝。)
自動續(xù)訂訂閱通知
這個取消通知之前就一直有皿桑,所以這里不重復(fù)了,需要的自行搜索蔬啡。
自動續(xù)訂訂閱的相關(guān)文檔:
Handling Subscriptions Billing | Apple Developer Documentation
In-App Purchases and Using Server-to-Server Notifications - WWDC 2019 - Videos - Apple Developer
Subscription Offers Best Practices - WWDC 2019 - Videos - Apple Developer
最后有2點(diǎn)诲侮,1.退款通知目前并不能在沙盒中測試;2.蘋果后臺也無法看到退款的訂單詳情箱蟆;
71.?命令行修改App版本號
? ? cd 進(jìn)入工程所在目錄后
修改 Version 版本號 - 如改成?3.0.0
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString 3.0.0" Info.plist
修改 Build 版本號 - 如改成?3.0.202103051700
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion 3.0.202103051700" Info.plist
72. 真機(jī)調(diào)試下查看沙盒文件
連接真機(jī)設(shè)備沟绪,打開Xcode ,選擇Window -->Device and Simulator?,快捷鍵 Command + Shift + 2;
找到對應(yīng)的APP空猜,選擇設(shè)置圖標(biāo)绽慈,點(diǎn)擊Download?Container 下載到桌面
完成后就會在桌面上看見如下文件,右擊 ——> 選擇“顯示包內(nèi)容”
如果要想替換真機(jī)中的沙盒文件也是如上操作辈毯,在已下載好的文件中修改完成后坝疼。打開Xcode,Command + Shift + 2谆沃。選擇Replace Container裙士,選擇修改后的沙盒文件,點(diǎn)擊Open管毙。
73. 獲取不到內(nèi)購套餐產(chǎn)品信息的情況
1.檢查App的Bundle ID是否與蘋果商店中配置的信息統(tǒng)一;
2.檢查產(chǎn)品ID是否填寫錯誤桌硫;
3.檢查是否同意App付費(fèi)協(xié)議夭咬,及填寫銀行卡等稅務(wù)信息;
????????當(dāng)在蘋果商店配置好內(nèi)購套餐后铆隘,即便不提交審核(二進(jìn)制文件缺失)卓舵,或者審核失敗,App在沙盒環(huán)境下膀钠,仍然能獲取掏湾、購買App內(nèi)購套餐;
74. 簡單的線程死鎖
75.并行與串行的區(qū)別
在子線程中啟動定時器肿嘲,需要使用Runloop
76.OC的動態(tài)消息機(jī)制
調(diào)用某個對象的私有方法
77.字符轉(zhuǎn)換
將普通話轉(zhuǎn)換為拉丁符號融击,且?guī)б魳?biāo),包括希伯來語雳窟、阿拉伯語尊浪、泰語等多種語言。對處理除英語以外的語言和非拉丁文字時非常有用
78.將時間戳轉(zhuǎn)換為NSDate 或 NSString (如今日0點(diǎn)時間戳1639929600 -> 2021-12-20 00:00:00)
79.在字典A中SetValue一個從字典B轉(zhuǎn)換成的字符串B‘,然后將字典A轉(zhuǎn)成字符串A’導(dǎo)致Web端解析失敗的問題
? ? 因?yàn)橥值渲蠸et 字符串pkgStr拇涤,會自動為Value添加引號捣作,導(dǎo)致最后將字典infoData轉(zhuǎn)成字符串時,會出現(xiàn) "webInfo":"{xxxx 的情況鹅士,導(dǎo)致Web解析失敗券躁。
? ? 解決方法,直接在 infoData 中Set另一個字典 pkgInfo掉盅,不需要轉(zhuǎn)成字符串后再寫入
這樣就不會出現(xiàn) Web 解析失敗的問題也拜;
80.關(guān)于App后臺推送標(biāo)題、副標(biāo)題怔接、正文及圖片音頻視頻等內(nèi)容正常應(yīng)由服務(wù)器確定搪泳,但App配置文件與代碼優(yōu)先級更高。優(yōu)先級為:App配置文件(TARGETS——NotificationService——Build Settings——Info.plist Value內(nèi)修改Display Name)扼脐、NotificationService.m內(nèi)UNMutableNotificationContent對象的title屬性岸军、服務(wù)器推送內(nèi)容中的title字段,以上內(nèi)容都為空時瓦侮,系統(tǒng)默認(rèn)以App名作為推送標(biāo)題艰赞。