iOS技術(shù)小Tips

1.UITableView算高度

UITableView算高度最好不要用以下2行代碼自動(dòng)撐高度, iOS9.0上reloadData后,tableview會(huì)滾到頂部

rowHeight = UITableViewAutomaticDimension;
estimatedRowHeight = xxx

2.UIKeyboardWillShowNotification 通知獲取鍵盤(pán)高度

    CGRect keyboardEndFrame = [noti.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

系統(tǒng)自帶鍵盤(pán)回調(diào)一次
搜狗鍵盤(pán)回調(diào)3次 鍵盤(pán)高度分別是 0 , 226, 292,如果進(jìn)行動(dòng)畫(huà)可能發(fā)生跳動(dòng)

2.FLEXBOX布局

屬性定義了子視圖的主軸方向 column:是上下   row:左右
flexDirection: column, row, column-reverse, row-reverse

屬性定義了子視圖在主軸上的對(duì)齊方式
justifyContent: flex-start | flex-end | center | space-between | space-around | space-evenly

屬性定義項(xiàng)目在交叉軸上的對(duì)齊方式
alignItems: flex-start | flex-end | center | baseline | stretch

3.真機(jī)調(diào)試包地址

https://github.com/iGhibli/iOS-DeviceSupport/tree/master/DeviceSupport

4 TextView 相關(guān)

去除 textView 左右邊距:

self.textView.textContainer.lineFragmentPadding = 0;

去除 textView 上下邊距:

self.textView.textContainerInset = UIEdgeInsetsZero;

判斷輸入是否有高亮部分

  UITextRange *selectedRange = [textView markedTextRange];
    //獲取高亮部分
    UITextPosition *position = [textView   positionFromPosition:selectedRange.start offset:0];
    // 如果在變化中是高亮部分在變,就不要計(jì)算字符了
    if (!(selectedRange && position)) {
             // 輸入完成
    }

5 TextFiled 相關(guān)

自定義占位符顏色

- (void)drawPlaceholderInRect:(CGRect)rect {
    // 先計(jì)算size
    CGSize size = [self.placeholder sizeWithAttributes:@{NSFontAttributeName : self.font}];
    [self.placeholder drawInRect:CGRectMake(0, (rect.size.height - size.height) / 2.0, rect.size.width, rect.size.height)
                  withAttributes:@{NSForegroundColorAttributeName : self.placeholderColor, NSFontAttributeName : self.font}];
}

6、 Delegate和Notification有什么區(qū)別

說(shuō)一對(duì)一和一對(duì)多的區(qū)別就很low了
Delegate模式也是能夠?qū)崿F(xiàn)出一對(duì)多的功能的(例如XMPP的Multi Delegate)。

他們之間的本質(zhì)區(qū)別就在于命令式和響應(yīng)式。

假設(shè)你現(xiàn)在是主人,你肚子餓了。你需要讓你的仆人們給你做飯,端過(guò)來(lái)給你吃。

  • 命令式
1. 對(duì)仆人中負(fù)責(zé)買(mǎi)菜的人吩咐你去買(mǎi)菜帶給你
2. 你拿著仆人買(mǎi)來(lái)的菜,給到負(fù)責(zé)做菜的仆人,吩咐他去做菜
3. 廚師做好菜端給你,你就可以吃了
  • 響應(yīng)式
你喊一聲:我肚子餓了!

1. 負(fù)責(zé)買(mǎi)菜的仆人聽(tīng)到你喊的這一聲,就去買(mǎi)菜了,買(mǎi)好菜就放到倉(cāng)庫(kù)里,然后喊一聲:"我買(mǎi)好菜了!"
2. 負(fù)責(zé)做菜的仆人聽(tīng)到買(mǎi)菜的仆人喊的這一聲,就去倉(cāng)庫(kù)里拿東西做菜,做好了端給你。

7、 NSMutableParagraphStyle

  • 系統(tǒng)會(huì)復(fù)用這個(gè)對(duì)象, 2個(gè)段富文本都new了NSMutableParagraphStyle,但是打印出來(lái)的 地址是一個(gè), 這時(shí)候 如果我們改變這個(gè)對(duì)象的一些屬性, 2段文本會(huì)同時(shí)改變, 這是 系統(tǒng)的一個(gè)優(yōu)化需要注意
- (void)paragraphStyle {
    NSMutableParagraphStyle *style1 = [[NSMutableParagraphStyle alloc]init];
    style1.tailIndent = 10;
    NSMutableAttributedString *atrr1 = [[NSMutableAttributedString alloc]initWithString:@"此外,新增動(dòng)態(tài)計(jì)算功能,輕松支持同比、環(huán)比及加減乘除等運(yùn)算需求!" attributes:@{NSParagraphStyleAttributeName: style1}];
    
 
    NSMutableParagraphStyle *style2 = [[NSMutableParagraphStyle alloc]init];
    style2.tailIndent = 10;
    NSMutableAttributedString *atrr2 = [[NSMutableAttributedString alloc]initWithString:@"曼城意外折戟,熱刺強(qiáng)勢(shì)晉級(jí)!北京時(shí)間10月31日凌晨,英格蘭聯(lián)賽杯第4輪的較量上演了一場(chǎng)引人矚目的對(duì)決。" attributes:@{NSParagraphStyleAttributeName: style2}];
            
    [self check_paragraphStyle:atrr1];
    [self check_paragraphStyle:atrr2];
}

- (void)check_paragraphStyle:(NSAttributedString *)attributedText {
    NSLog(@"");
    [attributedText enumerateAttribute:NSParagraphStyleAttributeName inRange:NSMakeRange(0, attributedText.length) options:0 usingBlock:^(NSParagraphStyle *value, NSRange range, BOOL * _Nonnull stop) {
        NSLog(@"%@", value);
    }];
}
  • 修復(fù)
[attributedText enumerateAttribute:NSParagraphStyleAttributeName inRange:NSMakeRange(0, attributedText.length) options:0 usingBlock:^(NSParagraphStyle *value, NSRange range, BOOL * _Nonnull stop) {
        這里修改 value 時(shí)必須調(diào)用 value.mutableCopy
        yytext 里面的宏定義有點(diǎn)問(wèn)題
    }];

#define ParagraphStyleSet(_attr_) \
[self enumerateAttribute:NSParagraphStyleAttributeName \
                 inRange:range \
                 options:kNilOptions \
              usingBlock: ^(NSParagraphStyle *value, NSRange subRange, BOOL *stop) { \
                  NSMutableParagraphStyle *style = nil; \
                  if (value) { \
                      if (CFGetTypeID((__bridge CFTypeRef)(value)) == CTParagraphStyleGetTypeID()) { \
                          value = [NSParagraphStyle yy_styleWithCTStyle:(__bridge CTParagraphStyleRef)(value)]; \
                      } \
                      if (value. _attr_ == _attr_) return; \
                      if ([value isKindOfClass:[NSMutableParagraphStyle class]]) { \
                          style = (id)value; \
                      } else { \
                          style = value.mutableCopy; \
                      } \
                  } else { \
                      if ([NSParagraphStyle defaultParagraphStyle]. _attr_ == _attr_) return; \
                      style = [NSParagraphStyle defaultParagraphStyle].mutableCopy; \
                  } \
                  style. _attr_ = _attr_; \
                  [self yy_setParagraphStyle:style range:subRange]; \
              }];

8、有用的文章

緩存 https://zhuanlan.zhihu.com/p/591436083
網(wǎng)絡(luò) https://zhuanlan.zhihu.com/p/405387352
虛擬定位 https://zhuanlan.zhihu.com/p/451765172
防定位黑產(chǎn) http://www.itdecent.cn/p/84830b9ebde0
SwiftHook(libffi庫(kù)) https://blog.csdn.net/gitblog_00080/article/details/139516503
內(nèi)存 https://wetest.qq.com/labs/367

9、RunLoop 和 GCD

 NSLog(@"開(kāi)始")
 dispatch_async(dispatch_get_main_queue(), ^{
      NSLog(@"執(zhí)行")
 });
 NSLog(@"結(jié)束")

打印順序: 開(kāi)始 -> 結(jié)束 -> 執(zhí)行
  • 上面代碼gcd的block會(huì)在新的一輪runloop中執(zhí)行, 他的執(zhí)行時(shí)機(jī)是什么呢?
GCD 在調(diào)用dispatch_async之后不會(huì)立刻執(zhí)行block而是把block存起來(lái),  猜測(cè)其內(nèi)部監(jiān)聽(tīng)了 runloop的kCFRunLoopBeforeWaiting狀態(tài)
這時(shí)候通過(guò)Dispatch port 注冊(cè)的Source1喚醒runloop

執(zhí)行這個(gè)方法            
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);

這個(gè)方法內(nèi)部是和GCD進(jìn)行通信, 去執(zhí)行存在主隊(duì)列里面的block

10、dispatch_after

使用dispatch_after還有一個(gè)問(wèn)題就是取消問(wèn)題,當(dāng)然通常遇到了這種問(wèn)題大部分答案就是使用下面的方式:

[self performSelector:@selector(myDelayedMethod) withObject: self afterDelay: desiredDelay];

[NSObject cancelPreviousPerformRequestsWithTarget: self selector:@selector(myDelayedMethod) object: self];

不過(guò)如果你使用的是iOS 8及其以上的版本,那么其實(shí)是可以取消的(如下),當(dāng)然如果你還在支持iOS 8以下的版本不妨試試這個(gè)自定義的dispatch_cancelable_block_t類(lèi):

dispatch_block_t block = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
    NSLog(@"dispatch_after...");
    
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
    
// 取消
dispatch_block_cancel(block);

GCD源碼解讀
RunLoop

11. UICollectionView

  • minimumInteritemSpacing 和 minimumInteritemSpacing 設(shè)置為同一個(gè)值時(shí)
  • 并且 UICollectionView是由多組構(gòu)成
    UICollectionView 在滑動(dòng)中 一些item會(huì)隱藏不見(jiàn)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容