百思奇解項目筆記

從iOS9開始的常見報錯

Application windows are expected to have a root view controller at the end of application launch
  • 從iOS9開始, 在程序啟動完畢那一刻顯示出來的窗口必須要設(shè)置根控制器

有些圖片顯示出來會自動渲染成藍(lán)色

比如

  • 設(shè)置tabBarItem的選中圖片
vc.tabBarItem.selectedImage = image;
  • 設(shè)置UIButtonTypeSystem樣式按鈕的image時
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
[btn setImage:image forState:UIControlStateNormal];

解決方案

  • 再次產(chǎn)生一張不會進(jìn)行渲染的圖片
// 加載圖片
UIImage *tempImage = [UIImage imageNamed:@"tabBar_essence_click_icon"];
// 產(chǎn)生一張不會進(jìn)行自動渲染的圖片
UIImage *selectedImage = [tempImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
vc.tabBarItem.selectedImage = selectedImage;
  • 直接在xcassets文件中配置


    Snip20151105_1.png

設(shè)置TabBarItem的文字屬性

  • 直接設(shè)置每一個tabBarItem對象
// 普通狀態(tài)下的文字屬性
NSMutableDictionary *normalAttrs = [NSMutableDictionary dictionary];
normalAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:14];
normalAttrs[NSForegroundColorAttributeName] = [UIColor grayColor];
[vc.tabBarItem setTitleTextAttributes:normalAttrs forState:UIControlStateNormal];

// 選中狀態(tài)下的文字屬性
NSMutableDictionary *selectedAttrs = [NSMutableDictionary dictionary];
selectedAttrs[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
[vc.tabBarItem setTitleTextAttributes:selectedAttrs forState:UIControlStateSelected];


// 字典中用到的key
1.iOS7之前(在UIStringDrawing.h中可以找到)
- 比如UITextAttributeFont\UITextAttributeTextColor
- 規(guī)律:UITextAttributeXXX

2.iOS7開始(在NSAttributedString.h中可以找到)
- 比如NSFontAttributeName\NSForegroundColorAttributeName
- 規(guī)律:NSXXXAttributeName
  • 通過UITabBarItem的appearance對象統(tǒng)一設(shè)置
/**** 設(shè)置所有UITabBarItem的文字屬性 ****/
UITabBarItem *item = [UITabBarItem appearance];
// 普通狀態(tài)下的文字屬性
NSMutableDictionary *normalAttrs = [NSMutableDictionary dictionary];
normalAttrs[NSFontAttributeName] = [UIFont systemFontOfSize:14];
normalAttrs[NSForegroundColorAttributeName] = [UIColor grayColor];
[item setTitleTextAttributes:normalAttrs forState:UIControlStateNormal];
// 選中狀態(tài)下的文字屬性
NSMutableDictionary *selectedAttrs = [NSMutableDictionary dictionary];
selectedAttrs[NSForegroundColorAttributeName] = [UIColor darkGrayColor];
[item setTitleTextAttributes:normalAttrs forState:UIControlStateSelected];

Appearance的使用場合

  • 只要后面帶有UI_APPEARANCE_SELECTOR的方法或者屬性,都可以通過appearance對象統(tǒng)一設(shè)置
  • 比如
@interface UISwitch : UIControl <NSCoding>

@property(nullable, nonatomic, strong) UIColor *onTintColor NS_AVAILABLE_IOS(5_0) UI_APPEARANCE_SELECTOR;

@end

UISwitch *s = [UISwitch appearance];
s.onTintColor = [UIColor redColor];

項目的圖片資源

顏色相關(guān)的一些知識

  • 顏色的基本組成
    • 一種顏色由N個顏色通道組成
  • 顏色通道
    • 1個顏色通道占據(jù)8bit
    • 1個顏色通道的取值范圍
      • 10進(jìn)制 : [0, 255]
      • 16進(jìn)制 : [00, ff];
    • 常見的顏色通道
      • 紅色 red R
      • 綠色 green G
      • 藍(lán)色 blue B
      • 透明度 alpha A
    • R\G\B一樣的是灰色
  • 顏色的種類
    • 24bit顏色
      • 由R\G\B組成的顏色
      • 常見的表示形式
        • 10進(jìn)制(僅僅是用在CSS)
          • 紅色 : rgb(255,0,0)
          • 綠色 : rgb(0,255,0)
          • 藍(lán)色 : rgb(0,0,255)
          • 黃色 : rgb(255,255,0)
          • 黑色 : rgb(0,0,0)
          • 白色 : rgb(255,255,255)
          • 灰色 : rgb(80,80,80)
        • 16進(jìn)制(可以用在CSS\android)
          • 紅色 : #ff0000 #f00
          • 綠色 : #00ff00 #0f0
          • 藍(lán)色 : #0000ff #00f
          • 黃色 : #ffff00 #ff0
          • 黑色 : #000000 #000
          • 白色 : #ffffff #fff
          • 灰色 : #979797
    • 32bit顏色
      • 由R\G\B\A組成的顏色
      • 常見的表示形式
        • 10進(jìn)制(僅僅是用在CSS)
          • 紅色 : rgba(255,0,0,255)
          • 綠色 : rgba(0,255,0,255)
          • 藍(lán)色 : rgba(0,0,255,255)
          • 黃色 : rgba(255,255,0,255)
          • 黑色 : rgba(0,0,0,255)
          • 白色 : rgba(255,255,255,255)
        • 16進(jìn)制(#AARRGGBB, 僅僅是用在android)
          • 紅色 : #ffff0000
          • 綠色 : #ff00ff00
          • 藍(lán)色 : #ff0000ff
          • 黃色 : #ffffff00
          • 黑色 : #ff000000
          • 白色 : #ffffffff

PCH文件可能引發(fā)的錯誤

Snip20151105_8.png
  • 解決方案
#ifndef PrefixHeader_pch
#define PrefixHeader_pch

/*** 如果希望某些內(nèi)容能拷貝到任何源代碼文件(OC\C\C++等), 那么就不要寫在#ifdef __OBJC__和#endif之間 ***/


/***** 在#ifdef __OBJC__和#endif之間的內(nèi)容, 只會拷貝到OC源代碼文件中, 不會拷貝到其他語言的源代碼文件中 *****/
#ifdef __OBJC__


#endif
/***** 在#ifdef __OBJC__和#endif之間的內(nèi)容, 只會拷貝到OC源代碼文件中, 不會拷貝到其他語言的源代碼文件中 *****/


#endif

在Build Setting中配置宏

  • 如果項目中有些宏找不到, 可能是配置在Build Setting中
Snip20161116_4.png
  • 注意點:宏的名字不能全部是小寫字母

  • 如果宏的名字全部是小寫, 會出現(xiàn)以下錯誤


    Snip20161116_1.png

控制臺可能會輸出以下警告信息

  • 警告的原因: [UIImage imageNamed:nil]
CUICatalog: Invalid asset name supplied: (null)
CUICatalog: Invalid asset name supplied: (null)
  • 警告的原因: [UIImage imageNamed:@""]
CUICatalog: Invalid asset name supplied:
CUICatalog: Invalid asset name supplied:

準(zhǔn)確判斷一個字符串是否有內(nèi)容

if (string.length) {

}

/*
錯誤寫法:
if (string) {

}
*/

替換UITabBarController內(nèi)部的tabBar

// 這里的self是UITabBarController
[self setValue:[[LYWTabBar alloc] init] forKeyPath:@"tabBar"];

center和size的設(shè)置順序

  • 建議的設(shè)置順序
    • 先設(shè)置size
    • 再設(shè)置center

給系統(tǒng)自帶的類增加分類

  • 建議增加的分類屬性名\方法名前面加上前綴, 比如
@interface UIView (LYWExtension)

@property (nonatomic,assign) CGFloat LYW_X;
@property (nonatomic,assign) CGFloat LYW_Y;
@property (nonatomic,assign) CGFloat LYW_W;
@property (nonatomic,assign) CGFloat LYW_H;
@property (nonatomic,assign) CGSize  LYW_size;
@property (nonatomic,assign) CGPoint LYW_point;
@property (assign, nonatomic) CGFloat LYW_centerX;
@property (assign, nonatomic) CGFloat LYW_centerY;
@property (nonatomic,assign) CGFloat LYW_right;
@property (nonatomic,assign) CGFloat LYW_bottom;

+(instancetype)LYWviewFromXib;

@end

按鈕常見的訪問方法

[button imageForState:UIControlStateNormal].size;
button.currentImage.size;

[button backgroundImageForState:UIControlStateNormal];
button.currentBackgroundImage;

[button titleForState:UIControlStateNormal];
button.currentTitle;

[button titleColorForState:UIControlStateNormal];
button.currentTitleColor;

設(shè)置按鈕的內(nèi)邊距

@property(nonatomic) UIEdgeInsets contentEdgeInsets UI_APPEARANCE_SELECTOR;
@property(nonatomic) UIEdgeInsets titleEdgeInsets;
@property(nonatomic) UIEdgeInsets imageEdgeInsets;

解決導(dǎo)航控制器pop手勢失效

self.interactivePopGestureRecognizer.delegate = self;

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    // 手勢何時有效 : 當(dāng)導(dǎo)航控制器的子控制器個數(shù) > 1就有效
    return self.childViewControllers.count > 1;
}

frame和bounds的重新認(rèn)識

  • frame
    • 父控件 內(nèi)容的左上角為坐標(biāo)原點, 計算出的控件自己 矩形框的位置和尺寸
  • bounds
    • 控件自己 內(nèi)容的左上角為坐標(biāo)原點, 計算出的控件自己 矩形框的位置和尺寸
  • 概括
    • frame.size == bounds.size
    • scrollView.bounds.origin == scrollView.contentOffset

bounds和frame的區(qū)別

bounds和frame的區(qū)別.png

矩形框和內(nèi)容的理解

  • 矩形框
    • 控件自己的顯示位置和尺寸
  • 內(nèi)容
    • 控件內(nèi)部的東西,比如它的子控件

在使用UITableViewController過程中,可能會出現(xiàn)的錯誤

@interface TestTableViewController : UITableViewController

@end

'-[UITableViewController loadView] instantiated view controller with identifier "UIViewController-BYZ-38-t0r" from storyboard "Main", but didn't get a UITableView.'
  • 造成這個錯誤的原因
    • 錯誤地將一個UIViewController當(dāng)做UITableViewController來用
  • 錯誤做法


    Snip20151108_134.png
  • 正確做法
Snip20151108_135.png
Snip20151108_137.png

contentInset的調(diào)整

  • 默認(rèn)情況下, 如果一個控制器A處在導(dǎo)航控制器管理中, 并且控制器A的第一個子控件是UIScrollView, 那么就會自動調(diào)整這個UIScrollView的contentInset
    • UIEdgeInsetsMake(64, 0, 0, 0) // 有導(dǎo)航欄
    • UIEdgeInsetsMake(20, 0, 0, 0) // 沒有導(dǎo)航欄
  • 默認(rèn)情況下, 如果一個控制器A處在導(dǎo)航控制器管理中, 并且導(dǎo)航控制器又處在UITabBarController管理中, 并且控制器A的第一個子控件是UIScrollView, 那么就會自動調(diào)整這個UIScrollView的contentInset
    • UIEdgeInsetsMake(64, 0, 49, 0)
  • 如何禁止上述的默認(rèn)問題?
控制器A.automaticallyAdjustsScrollViewInsets = NO;

文字內(nèi)容換行

  • 如何讓storyboard\xib中的文字內(nèi)容換行
    • 快捷鍵: option + 回車鍵
    • 在storyboard\xib輸入\n是無法實現(xiàn)換行的
  • 在代碼中輸入\n是可以實現(xiàn)換行的
self.label.text = @"534534534\n5345345\n5345";

修改狀態(tài)欄樣式

  • 使用UIApplication來管理


    Snip20151108_152.png
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

在Info.plist中做了圖中的配置,可能會出現(xiàn)以下警告信息

  • 使用UIViewController來管理
@implementation LYWLoginRegisterViewController
- (UIStatusBarStyle)preferredStatusBarStyle
{
    return UIStatusBarStyleLightContent;
}
@end

在xib\storyboard中使用KVC

Snip20151108_177.png

修改UITextField的光標(biāo)顏色

textField.tintColor = [UIColor whiteColor];

UITextField占位文字相關(guān)的設(shè)置

// 設(shè)置占位文字內(nèi)容
@property(nullable, nonatomic,copy)   NSString               *placeholder;
// 設(shè)置帶有屬性的占位文字, 優(yōu)先級 > placeholder
@property(nullable, nonatomic,copy)   NSAttributedString     *attributedPlaceholder;

NSAttributedString

  • 帶有屬性的字符串, 富文本
  • 由2部分組成
    • 文字內(nèi)容 : NSString *
    • 文字屬性 : NSDictionary *
      • 文字顏色 - NSForegroundColorAttributeName
      • 字體大小 - NSFontAttributeName
      • 下劃線 - NSUnderlineStyleAttributeName
      • 背景色 - NSBackgroundColorAttributeName
  • 初始化
NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
attributes[NSForegroundColorAttributeName] = [UIColor yellowColor];
attributes[NSBackgroundColorAttributeName] = [UIColor redColor];
attributes[NSUnderlineStyleAttributeName] = @YES;
NSAttributedString *string = [[NSAttributedString alloc] initWithString:@"123" attributes:attributes];
  • 使用場合
    • UILabel - attributedText
    • UITextField - attributedPlaceholder

NSMutableAttributedString

  • 繼承自NSAttributedString
  • 常見方法
// 設(shè)置range范圍的屬性, 重復(fù)設(shè)置同一個范圍的屬性, 最后一次設(shè)置才是有效的(之前的設(shè)置會被覆蓋掉)
- (void)setAttributes:(nullable NSDictionary<NSString *, id> *)attrs range:(NSRange)range;
// 添加range范圍的屬性, 同一個范圍, 可以不斷累加屬性
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
- (void)addAttributes:(NSDictionary<NSString *, id> *)attrs range:(NSRange)range;
  • 圖文混排
UILabel *label = [[UILabel alloc] init];
label.frame = CGRectMake(100, 100, 200, 25);
label.backgroundColor = [UIColor redColor];
label.font = [UIFont systemFontOfSize:14];
[self.view addSubview:label];

// 圖文混排
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] init];
// 1 - 你好
NSAttributedString *first = [[NSAttributedString alloc] initWithString:@"你好"];
[attributedText appendAttributedString:first];

// 2 - 圖片
// 帶有圖片的附件對象
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = [UIImage imageNamed:@"header_cry_icon"];
CGFloat lineH = label.font.lineHeight;
attachment.bounds = CGRectMake(0, - ((label.lyw_height - lineH) * 0.5 - 1), lineH, lineH);
// 將附件對象包裝成一個屬性文字
NSAttributedString *second = [NSAttributedString attributedStringWithAttachment:attachment];
[attributedText appendAttributedString:second];

// 3 - 哈哈哈
NSAttributedString *third = [[NSAttributedString alloc] initWithString:@"哈哈哈"];
[attributedText appendAttributedString:third];

label.attributedText = attributedText;
  • 一個Label顯示多行不同字體的文字
UILabel *label = [[UILabel alloc] init];
// 設(shè)置屬性文字
NSString *text = @"你好\n哈哈哈";
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:text];
[attributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:10] range:NSMakeRange(0, text.length)];
[attributedText addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:13] range:NSMakeRange(3, 3)];
label.attributedText = attributedText;
// 其他設(shè)置
label.numberOfLines = 0;
label.textAlignment = NSTextAlignmentCenter;
label.frame = CGRectMake(0, 0, 100, 40);
[self.view addSubview:label];
self.navigationItem.titleView = label;

在storyboard\xib中給UIScrollView子控件添加約束

  • 給添加一個UIView類型的子控件A(這將是UIScrollView唯一的一個子控件)
  • 設(shè)置A距離UIScrollView上下左右間距都為0
  • 往A中再添加其他子控件


    Snip20151109_228.png
  • 上下滾動(垂直滾動)
    • 設(shè)置A的高度(這個高度就是UIScrollView的內(nèi)容高度: contentSize.height)


      Snip20151109_202.png
    • 設(shè)置A在UIScrollView中左右居中(水平居中)


      Snip20151109_203.png
  • 左右滾動(水平滾動)
    • 設(shè)置A的寬度(這個寬度就是UIScrollView的內(nèi)容寬度: contentSize.width)
Snip20151109_231.png

- 設(shè)置A在UIScrollView中上下居中(垂直居中)


Snip20151109_230.png
  • 上下左右滾動(水平垂直滾動)
    • 設(shè)置A的寬度(這個寬度就是UIScrollView的內(nèi)容寬度: contentSize.width)
    • 設(shè)置A的高度(這個高度就是UIScrollView的內(nèi)容高度: contentSize.height)
Snip20151109_232.png
Snip20151109_229.png

修改UITextField占位文字的顏色

  • 使用attributedPlaceholder
@property(nullable, nonatomic,copy)   NSAttributedString     *attributedPlaceholder;
  • 重寫- (void)drawPlaceholderInRect:(CGRect)rect;
- (void)drawPlaceholderInRect:(CGRect)rect;
  • 修改內(nèi)部占位文字Label的文字顏色
[textField setValue:[UIColor grayColor] forKeyPath:@"placeholderLabel.textColor"];

如何監(jiān)聽一個控件內(nèi)部的事件

  • 如果繼承自UIControl
- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;
  • 代理

  • 通知

  • 利用內(nèi)部的某些機制

    • 比如重寫UITextField的becomeFirstResponderresignFirstResponder來監(jiān)聽UITextField的獲得焦點和失去焦點事件

assign和weak的區(qū)別

  • 本質(zhì)區(qū)別
    • 速度比較: __unsafe_unretained > __weak
@property (nonatomic, assign) MyDog *dog;  // MyDog *__unsafe_unretained _dog;

__unsafe_unretained的特點:
1.不是強引用, 不能保住OC對象的命
2.如果引用的OC對象銷毀了, 指針并不會被自動清空, 依然指向銷毀的對象(很容易產(chǎn)生野指針錯誤: EXC_BAD_ACCESS)

@property (nonatomic, weak) MyDog *dog;  // MyDog * _Nullable __weak _dog;

__weak的特點:
1.不是強引用, 不能保住OC對象的命
2.如果引用的OC對象銷毀了, 指針會被自動清空(變?yōu)閚il), 不再指向銷毀的對象(永遠(yuǎn)不會產(chǎn)生野指針錯誤)
  • 用途
    • assign一般用在基本數(shù)據(jù)類型上面, 比如int\double等
    • weak一般用在代理對象上面, 或者用來解決循環(huán)強引用的問題

監(jiān)聽UITextField的獲得焦點和失去焦點事件

  • addTarget
[textField addTarget:target action:@selector(editingDidBegin) forControlEvents:UIControlEventEditingDidBegin];
[textField addTarget:target action:@selector(editingDidEnd) forControlEvents:UIControlEventEditingDidEnd];

UIControlEventEditingDidBegin
1.開始編輯
2.獲得焦點
3.彈出鍵盤

UIControlEventEditingDidEnd
1.結(jié)束編輯
2.失去焦點
3.退下鍵盤
  • delegate
textField.delegate = self;

#pragma mark - <UITextFieldDelegate>
- (void)textFieldDidBeginEditing:(UITextField *)textField
{

}

- (void)textFieldDidEndEditing:(UITextField *)textField
{

}
  • 通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginEditing) name:UITextFieldTextDidBeginEditingNotification object:textField];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endEditing) name:UITextFieldTextDidEndEditingNotification object:textField];

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)beginEditing
{

}

- (void)endEditing
{

}
  • 重寫UITextField的becomeFirstResponderresignFirstResponder方法
/**
 *  調(diào)用時刻 : 成為第一響應(yīng)者(開始編輯\彈出鍵盤\獲得焦點)
 */
- (BOOL)becomeFirstResponder
{

    return [super becomeFirstResponder];
}

/**
 *  調(diào)用時刻 : 不做第一響應(yīng)者(結(jié)束編輯\退出鍵盤\失去焦點)
 */
- (BOOL)resignFirstResponder
{

    return [super resignFirstResponder];
}

枚舉值的某個規(guī)律

  • 凡是使用了1 << n格式的枚舉值, 都可以使用|進(jìn)行組合使用
UIControlEventEditingDidBegin                                   = 1 << 16,
UIControlEventEditingChanged                                    = 1 << 17,
UIControlEventEditingDidEnd                                     = 1 << 18,
UIControlEventEditingDidEndOnExit                               = 1 << 19,

[textField addTarget:self action:@selector(test) forControlEvents:UIControlEventEditingDidBegin | UIControlEventEditingChanged];

通知相關(guān)的補充

使用block監(jiān)聽通知

// object對象發(fā)出了名字為name的通知, 就在queue隊列中執(zhí)行block
self.observer = [[NSNotificationCenter defaultCenter] addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[[NSOperationQueue alloc] init] usingBlock:^(NSNotification * _Nonnull note) {
    // 一旦監(jiān)聽到通知, 就會執(zhí)行這個block中的代碼
}];

// 最后需要移除監(jiān)聽
[[NSNotificationCenter defaultCenter] removeObserver:self.observer];

一次性通知(監(jiān)聽1次后就不再監(jiān)聽)

id observer = [[NSNotificationCenter defaultCenter] addObserverForName:UITextFieldTextDidBeginEditingNotification object:self queue:[[NSOperationQueue alloc] init] usingBlock:^(NSNotification * _Nonnull note) {


    // 移除通知
    [[NSNotificationCenter defaultCenter] removeObserver:observer];
}];

其他

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    // 因為是在子線程注冊了通知監(jiān)聽器, 所以beginEditing和endEditing會在子線程中執(zhí)行
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(beginEditing) name:UITextFieldTextDidBeginEditingNotification object:self];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(endEditing) name:UITextFieldTextDidEndEditingNotification object:self];
});

CocoaPods

  • Podfile.lock文件
    • 最后一次更新Pods時, 所有第三方框架的版本號
  • 常用指令的區(qū)別
    • pod install
      • 會根據(jù)Podfile.lock文件中列舉的版本號來安裝第三方框架
      • 如果一開始Podfile.lock文件不存在, 就會按照Podfile文件列舉的版本號來安裝第三方框架
      • 安裝框架之前, 默認(rèn)會執(zhí)行pod repo update指令
    • pod update
      • 將所有第三方框架更新到最新版本, 并且創(chuàng)建一個新的Podfile.lock文件
      • 安裝框架之前, 默認(rèn)會執(zhí)行pod repo update指令
    • pod install --no-repo-update
    • pod update --no-repo-update
      • 安裝框架之前, 不會執(zhí)行pod repo update指令

利用SDWebImage設(shè)置UIButton的圖片

  • 正確用法
[button sd_setImageWithURL:[NSURL URLWithString:url] forState:UIControlStateNormal placeholderImage:image];

解決tableView設(shè)置tableFooterView時contentSize不正確的問題

tableView.tableFooterView = footerView;
// 重新刷新數(shù)據(jù)(會重新計算contentSize)
[tableView reloadData];

查找字符串的常見方法

// 如果range.location == 0, 說明是以searchString開頭
// 如果range.location == NSNotFound或者range.length == 0, 說明沒找到對應(yīng)的字符串
- (NSRange)rangeOfString:(NSString *)searchString;
// 是否以str開頭
- (BOOL)hasPrefix:(NSString *)str;
// 是否以str結(jié)尾
- (BOOL)hasSuffix:(NSString *)str;
// 是否包含了str(不管頭部\中間\尾部)
- (BOOL)containsString:(NSString *)str;

計算某個文件\文件夾的大小

@implementation NSString (LYWExtension)
//- (unsigned long long)fileSize
//{
//    // 總大小
//    unsigned long long size = 0;
//
//    // 文件管理者
//    NSFileManager *mgr = [NSFileManager defaultManager];
//
//    // 文件屬性
//    NSDictionary *attrs = [mgr attributesOfItemAtPath:self error:nil];
//
//    if ([attrs.fileType isEqualToString:NSFileTypeDirectory]) { // 文件夾
//        // 獲得文件夾的大小  == 獲得文件夾中所有文件的總大小
//        NSDirectoryEnumerator *enumerator = [mgr enumeratorAtPath:self];
//        for (NSString *subpath in enumerator) {
//            // 全路徑
//            NSString *fullSubpath = [self stringByAppendingPathComponent:subpath];
//            // 累加文件大小
//            size += [mgr attributesOfItemAtPath:fullSubpath error:nil].fileSize;
//        }
//    } else { // 文件
//        size = attrs.fileSize;
//    }
//
//    return size;
//}

- (unsigned long long)fileSize
{
    // 總大小
    unsigned long long size = 0;

    // 文件管理者
    NSFileManager *mgr = [NSFileManager defaultManager];

    // 是否為文件夾
    BOOL isDirectory = NO;

    // 路徑是否存在
    BOOL exists = [mgr fileExistsAtPath:self isDirectory:&isDirectory];
    if (!exists) return size;

    if (isDirectory) { // 文件夾
        // 獲得文件夾的大小  == 獲得文件夾中所有文件的總大小
        NSDirectoryEnumerator *enumerator = [mgr enumeratorAtPath:self];
        for (NSString *subpath in enumerator) {
            // 全路徑
            NSString *fullSubpath = [self stringByAppendingPathComponent:subpath];
            // 累加文件大小
            size += [mgr attributesOfItemAtPath:fullSubpath error:nil].fileSize;
        }
    } else { // 文件
        size = [mgr attributesOfItemAtPath:self error:nil].fileSize;
    }

    return size;
}
@end

LYWLog(@"%zd", @"/Users/lyw/Desktop".fileSize);

計算文字的寬度

CGFloat titleW = [字符串 sizeWithFont:字體大小].width;
CGFloat titleW = [字符串 sizeWithAttributes:@{NSFontAttributeName : 字體大小}].width;

有透明度的顏色

[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.2];
[UIColor colorWithWhite:1.0 alpha:0.2];
[[UIColor whiteColor] colorWithAlphaComponent:0.2];

viewWithTag:內(nèi)部的大致實現(xiàn)思路

@implementation UIView
- (UIView *)viewWithTag:(NSInteger)tag
{
    if (self.tag == tag) return self;

    for (UIView *subview in self.subviews) {
        return [subview viewWithTag:tag];
    }
}
@end

addObject:和addObjectsFromArray:的區(qū)別

self.topics = @[20, 19, 18]
moreTopics = @[17, 16, 15]

self.topics = @[20, 19, 18, @[17, 16, 15]]
[self.topics addObject:moreTopics];

self.topics = @[20, 19, 18, 17, 16, 15]
[self.topics addObjectsFromArray:moreTopics];

服務(wù)器分頁的做法

服務(wù)器數(shù)據(jù)庫的數(shù)據(jù) = @[23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10]


第1頁數(shù)據(jù) == @[20, 19, 18, 17, 16]

做法1:
發(fā)送page參數(shù) : page=2
第2頁數(shù)據(jù) == @[18, 17, 16, 15, 14]

做法2:
發(fā)送maxid參數(shù) : maxid=16
第2頁數(shù)據(jù) == @[15, 14, 13, 12, 11]

集成MJRefresh

self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewTopics)];
[self.tableView.mj_header beginRefreshing];

self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreTopics)];

利用AFN取消請求

// 取消所有請求
for (NSURLSessionTask *task in self.manager.tasks) {
    [task cancel];
}

// 取消所有請求
[self.manager.tasks makeObjectsPerformSelector:@selector(cancel)];

// 關(guān)閉NSURLSession + 取消所有請求
// NSURLSession一旦被關(guān)閉了, 就不能再發(fā)請求
[self.manager invalidateSessionCancelingTasks:YES];

// 注意: 一個請求任務(wù)被取消了(cancel), 會自動調(diào)用AFN請求的failure這個block, block中傳入error參數(shù)的code是NSURLErrorCancelled

NSDateFormatter的作用

  • NSString * -> NSDate *
- (nullable NSDate *)dateFromString:(NSString *)string;
  • NSDate * -> NSString *
- (NSString *)stringFromDate:(NSDate *)date;

常見的日期格式

NSString * -> NSDate *

  • 2015-11-20 09:10:05
// 時間字符串
NSString *string = @"2015-11-20 09:10:05";

// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 設(shè)置日期格式(為了轉(zhuǎn)換成功)
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";

// NSString * -> NSDate *
NSDate *date = [fmt dateFromString:string];

NSLog(@"%@", date);
  • 11月-20號/2015年 09-10:05秒
// 時間字符串
NSString *string = @"11月-20號/2015年 09-10:05秒";

// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"MM月-dd號/yyyy年 HH-mm:ss秒";

NSLog(@"%@", [fmt dateFromString:string]);
  • Tue May 31 17:46:55 +0800 2011
// 時間字符串
NSString *string = @"Tue May 31 17:46:55 +0800 2011";

// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"EEE MMM dd HH:mm:ss Z yyyy";
// fmt.dateFormat = @"EEE MMM dd HH:mm:ss ZZZZ yyyy";
// 設(shè)置語言區(qū)域(因為這種時間是歐美常用時間)
fmt.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];

NSLog(@"%@", [fmt dateFromString:string]);
  • 1745645645645
// 時間戳 : 從1970年1月1號 00:00:00開始走過的毫秒數(shù)

// 時間字符串 - 時間戳
NSString *string = @"1745645645645";
NSTimeInterval second = string.longLongValue / 1000.0;

// 時間戳 -> NSDate *
NSDate *date = [NSDate dateWithTimeIntervalSince1970:second];
NSLog(@"%@", date);

NSCalendar的注意點

#define iOS(version) ([UIDevice currentDevice].systemVersion.doubleValue >= (version))

NSCalendar *calendar = nil;
if ([UIDevice currentDevice].systemVersion.doubleValue >= 8.0) {
    calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
} else {
    calendar = [NSCalendar currentCalendar];
}

NSCalendar *calendar = nil;
if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
    calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
} else {
    calendar = [NSCalendar currentCalendar];
}

NSDate * -> NSString *

NSDate *date = [NSDate date];

NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy年MM月dd號 HH:mm:ss";

NSString *string = [fmt stringFromDate:date];

獲得日期元素

NSString *string = @"2015-11-20 09:10:05";

NSString *month = [string substringWithRange:NSMakeRange(5, 2)];

NSLog(@"%@", month);
// 時間字符串
NSString *string = @"2015-11-20 09:10:05";

// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 設(shè)置日期格式(為了轉(zhuǎn)換成功)
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";

// NSString * -> NSDate *
NSDate *date = [fmt dateFromString:string];

// 利用NSCalendar處理日期
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:date];
NSInteger hour = [calendar component:NSCalendarUnitHour fromDate:date];
NSInteger minute = [calendar component:NSCalendarUnitMinute fromDate:date];

NSLog(@"%zd %zd %zd", month, hour, minute);
// 時間字符串
NSString *string = @"2015-11-20 09:10:05";

// 日期格式化類
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
// 設(shè)置日期格式(為了轉(zhuǎn)換成功)
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";

// NSString * -> NSDate *
NSDate *date = [fmt dateFromString:string];

// 利用NSCalendar處理日期
NSCalendar *calendar = [NSCalendar currentCalendar];

NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
NSDateComponents *cmps = [calendar components:unit  fromDate:date];

//    NSLog(@"%zd %zd %zd", cmps.year, cmps.month, cmps.day);
NSLog(@"%@", cmps);

日期比較

// 時間字符串
NSString *createdAtString = @"2015-11-20 11:10:05";
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSDate *createdAtDate = [fmt dateFromString:createdAtString];

// 手機當(dāng)前時間
NSDate *nowDate = [NSDate date];

/**
 NSComparisonResult的取值
 NSOrderedAscending = -1L, // 升序, 越往右邊越大
 NSOrderedSame,  // 相等
 NSOrderedDescending // 降序, 越往右邊越小
 */
// 獲得比較結(jié)果(誰大誰小)
NSComparisonResult result = [nowDate compare:createdAtDate];
if (result == NSOrderedAscending) { // 升序, 越往右邊越大
    NSLog(@"createdAtDate > nowDate");
} else if (result == NSOrderedDescending) { // 降序, 越往右邊越小
    NSLog(@"createdAtDate < nowDate");
} else {
    NSLog(@"createdAtDate == nowDate");
}
// 時間字符串
NSString *createdAtString = @"2015-11-20 09:10:05";
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
NSDate *createdAtDate = [fmt dateFromString:createdAtString];

// 手機當(dāng)前時間
//    NSDate *nowDate = [NSDate date];

// 獲得createdAtDate和nowDate的時間間隔(間隔多少秒)
//    NSTimeInterval interval = [nowDate timeIntervalSinceDate:createdAtDate];
NSTimeInterval interval = [createdAtDate timeIntervalSinceNow];
NSLog(@"%f", interval);
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
fmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";

// 時間字符串
NSString *createdAtString = @"2015-11-01 09:10:05";
NSDate *createdAtDate = [fmt dateFromString:createdAtString];

// 其他時間
NSString *otherString = @"2015-10-31 08:56:45";
NSDate *otherDate = [fmt dateFromString:otherString];

// 獲得NSCalendar
NSCalendar *calendar = nil;
if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
    calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
} else {
    calendar = [NSCalendar currentCalendar];
}

// 獲得日期之間的間隔
NSCalendarUnit unit = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
NSDateComponents *cmps = [calendar components:unit fromDate:createdAtDate toDate:otherDate options:0];

NSLog(@"%@", cmps);

條件判斷的一些注意點

1.判斷一個數(shù)組中是否有具體內(nèi)容
1> 正確
if (array.count) {

}

2> 錯誤
if (array) {

}

2.判斷一個字符串是否有具體內(nèi)容
1> 正確
if (string.length) {

}

2> 錯誤
if (string) {

}

自動拉伸問題

  • 從xib中加載進(jìn)來的控件的autoresizingMask屬性值默認(rèn)是
    • UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
  • 如果一個控件顯示出來的大小和當(dāng)初設(shè)置的frame大小不一致,有可能是因為autoresizingMask屬性值包含了UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight,解決方案
控件.autoresizingMask = UIViewAutoresizingNone;

獲得自定義的所有相簿

// 獲得所有的自定義相簿
PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
// 遍歷所有的自定義相簿
for (PHAssetCollection *assetCollection in assetCollections) {

}

獲得相機膠卷相簿

// 獲得相機膠卷
PHAssetCollection *cameraRoll = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeSmartAlbumUserLibrary options:nil].lastObject;

獲得某個相簿的縮略圖

PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
// 同步獲得圖片, 只會返回1張圖片
options.synchronous = YES;

// 獲得某個相簿中的所有PHAsset對象
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
for (PHAsset *asset in assets) {
    CGSize size = CGSizeZero;

    // 從asset中獲得圖片
    [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
        NSLog(@"%@", result);
    }];
}

獲得某個相簿的原圖

PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
// 同步獲得圖片, 只會返回1張圖片
options.synchronous = YES;

// 獲得某個相簿中的所有PHAsset對象
PHFetchResult<PHAsset *> *assets = [PHAsset fetchAssetsInAssetCollection:assetCollection options:nil];
for (PHAsset *asset in assets) {
    CGSize size = CGSizeMake(asset.pixelWidth, asset.pixelHeight);

    // 從asset中獲得圖片
    [[PHImageManager defaultManager] requestImageForAsset:asset targetSize:size contentMode:PHImageContentModeDefault options:options resultHandler:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
        NSLog(@"%@", result);
    }];
}

利用UIImagePickerController挑選圖片

// UIImagePickerController : 可以從系統(tǒng)自帶的App(照片\相機)中獲得圖片

// 判斷相冊是否可以打開
if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) return;

UIImagePickerController *ipc = [[UIImagePickerController alloc] init];
// 打開照片應(yīng)用(顯示所有相簿)
ipc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// 打開照片應(yīng)用(只顯示"時刻"這個相簿)
// ipc.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
// 照相機
// ipc.sourceType = UIImagePickerControllerSourceTypeCamera;
ipc.delegate = self;
[self presentViewController:ipc animated:YES completion:nil];

#pragma mark - <UIImagePickerControllerDelegate>
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
    // 銷毀控制器
    [picker dismissViewControllerAnimated:YES completion:nil];

    // 設(shè)置圖片
    self.imageView.image = info[UIImagePickerControllerOriginalImage];
}

NaN錯誤

  • 錯誤起因:0被當(dāng)做除數(shù), 比如 10 / 0

最簡單的方法保存圖片到相機膠卷

UIImageWriteToSavedPhotosAlbum(self.imageView.image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);

/**
 *  通過UIImageWriteToSavedPhotosAlbum函數(shù)寫入圖片完畢后就會調(diào)用這個方法
 *
 *  @param image       寫入的圖片
 *  @param error       錯誤信息
 *  @param contextInfo UIImageWriteToSavedPhotosAlbum函數(shù)的最后一個參數(shù)
 */
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
    if (error) {
        [SVProgressHUD showErrorWithStatus:@"圖片保存失敗!"];
    } else {
        [SVProgressHUD showSuccessWithStatus:@"圖片保存成功!"];
    }
}

保存圖片到自定義相冊

- (IBAction)save {
    /*
     PHAuthorizationStatusNotDetermined,     用戶還沒有做出選擇
     PHAuthorizationStatusDenied,            用戶拒絕當(dāng)前應(yīng)用訪問相冊(用戶當(dāng)初點擊了"不允許")
     PHAuthorizationStatusAuthorized         用戶允許當(dāng)前應(yīng)用訪問相冊(用戶當(dāng)初點擊了"好")
     PHAuthorizationStatusRestricted,        因為家長控制, 導(dǎo)致應(yīng)用無法方法相冊(跟用戶的選擇沒有關(guān)系)
     */

    // 判斷授權(quán)狀態(tài)
    PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
    if (status == PHAuthorizationStatusRestricted) { // 因為家長控制, 導(dǎo)致應(yīng)用無法方法相冊(跟用戶的選擇沒有關(guān)系)
        [SVProgressHUD showErrorWithStatus:@"因為系統(tǒng)原因, 無法訪問相冊"];
    } else if (status == PHAuthorizationStatusDenied) { // 用戶拒絕當(dāng)前應(yīng)用訪問相冊(用戶當(dāng)初點擊了"不允許")
        LYWLog(@"提醒用戶去[設(shè)置-隱私-照片-xxx]打開訪問開關(guān)");
    } else if (status == PHAuthorizationStatusAuthorized) { // 用戶允許當(dāng)前應(yīng)用訪問相冊(用戶當(dāng)初點擊了"好")
        [self saveImage];
    } else if (status == PHAuthorizationStatusNotDetermined) { // 用戶還沒有做出選擇
        // 彈框請求用戶授權(quán)
        [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
            if (status == PHAuthorizationStatusAuthorized) { // 用戶點擊了好
                [self saveImage];
            }
        }];
    }
}

- (void)saveImage
{
    // PHAsset : 一個資源, 比如一張圖片\一段視頻
    // PHAssetCollection : 一個相簿

    // PHAsset的標(biāo)識, 利用這個標(biāo)識可以找到對應(yīng)的PHAsset對象(圖片對象)
    __block NSString *assetLocalIdentifier = nil;

    // 如果想對"相冊"進(jìn)行修改(增刪改), 那么修改代碼必須放在[PHPhotoLibrary sharedPhotoLibrary]的performChanges方法的block中
    [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
        // 1.保存圖片A到"相機膠卷"中
        // 創(chuàng)建圖片的請求
        assetLocalIdentifier = [PHAssetCreationRequest creationRequestForAssetFromImage:self.imageView.image].placeholderForCreatedAsset.localIdentifier;
    } completionHandler:^(BOOL success, NSError * _Nullable error) {
        if (success == NO) {
            [self showError:@"保存圖片失敗!"];
            return;
        }

        // 2.獲得相簿
        PHAssetCollection *createdAssetCollection = [self createdAssetCollection];
        if (createdAssetCollection == nil) {
            [self showError:@"創(chuàng)建相簿失敗!"];
            return;
        }

        [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
            // 3.添加"相機膠卷"中的圖片A到"相簿"D中

            // 獲得圖片
            PHAsset *asset = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetLocalIdentifier] options:nil].lastObject;

            // 添加圖片到相簿中的請求
            PHAssetCollectionChangeRequest *request = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:createdAssetCollection];

            // 添加圖片到相簿
            [request addAssets:@[asset]];
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            if (success == NO) {
                [self showError:@"保存圖片失敗!"];;
            } else {
                [self showSuccess:@"保存圖片成功!"];;
            }
        }];
    }];
}

/**
 *  獲得相簿
 */
- (PHAssetCollection *)createdAssetCollection
{
    // 從已存在相簿中查找這個應(yīng)用對應(yīng)的相簿
    PHFetchResult<PHAssetCollection *> *assetCollections = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    for (PHAssetCollection *assetCollection in assetCollections) {
        if ([assetCollection.localizedTitle isEqualToString:LYWAssetCollectionTitle]) {
            return assetCollection;
        }
    }

    // 沒有找到對應(yīng)的相簿, 得創(chuàng)建新的相簿

    // 錯誤信息
    NSError *error = nil;

    // PHAssetCollection的標(biāo)識, 利用這個標(biāo)識可以找到對應(yīng)的PHAssetCollection對象(相簿對象)
    __block NSString *assetCollectionLocalIdentifier = nil;
    [[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
        // 創(chuàng)建相簿的請求
        assetCollectionLocalIdentifier = [PHAssetCollectionChangeRequest creationRequestForAssetCollectionWithTitle:LYWAssetCollectionTitle].placeholderForCreatedAssetCollection.localIdentifier;
    } error:&error];

    // 如果有錯誤信息
    if (error) return nil;

    // 獲得剛才創(chuàng)建的相簿
    return [PHAssetCollection fetchAssetCollectionsWithLocalIdentifiers:@[assetCollectionLocalIdentifier] options:nil].lastObject;
}

- (void)showSuccess:(NSString *)text
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [SVProgressHUD showSuccessWithStatus:text];
    });
}

- (void)showError:(NSString *)text
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [SVProgressHUD showErrorWithStatus:text];
    });
}

Xcode插件的安裝路徑

/Users/用戶名/Library/Application Support/Developer/Shared/Xcode/Plug-ins

屬性名注意點

  • 對象屬性名不能以new開頭
@property (nonatomic, strong) NSMutableArray<LYWComment *> *newComments;

常見錯誤

-[__NSArray0 objectForKeyedSubscript:]: unrecognized selector sent to instance 0x7fb738c01870
// 錯誤地將NSArray當(dāng)做NSDictionary來使用了

block細(xì)節(jié)

  • 如果【block內(nèi)部】使用【外部聲明的強引用】訪問【對象A】, 那么【block內(nèi)部】會自動產(chǎn)生一個【強引用】指向【對象A】
  • 如果【block內(nèi)部】使用【外部聲明的弱引用】訪問【對象A】, 那么【block內(nèi)部】會自動產(chǎn)生一個【弱引用】指向【對象A】

矩形框比較的2個函數(shù)

  • bool CGRectContainsRect(CGRect rect1, CGRect rect2)
    • 判斷rect1是否包含了rect2
  • bool CGRectIntersectsRect(CGRect rect1, CGRect rect2)
    • 判斷rect1和rect2是否有重疊
    • 注意:rect1和rect2要在同一個坐標(biāo)系,比較結(jié)果才準(zhǔn)確

轉(zhuǎn)換坐標(biāo)系總結(jié)

view2坐標(biāo)系 : 以view2的左上角為坐標(biāo)原點
view1坐標(biāo)系 : 以view1的左上角為坐標(biāo)原點

CGRect newRect = [view1 convertRect:rect fromView:view2];
// 讓rect這個矩形框宦言, 從view2坐標(biāo)系轉(zhuǎn)換到view1坐標(biāo)系, 得出一個新的矩形框newRect
// rect和view2的含義 : 用來確定矩形框原來在哪

CGRect newRect = [view1 convertRect:rect toView:view2];
// 讓rect這個矩形框杨耙, 從view1坐標(biāo)系轉(zhuǎn)換到view2坐標(biāo)系, 得出一個新的矩形框newRect
// rect和view1的含義 :用來確定矩形框原來在哪

獲得一個控件在window中的位置和尺寸

  • 以獲得redView在window中的位置和尺寸為例
CGRect newRect = [[UIApplication sharedApplication].keyWindow convertRect:redView.bounds fromView:redView];
CGRect newRect = [[UIApplication sharedApplication].keyWindow convertRect:redView.frame fromView:redView.superview];
CGRect newRect = [redView convertRect:redView.bounds toView:[UIApplication sharedApplication].keyWindow];
CGRect newRect = [redView.superview convertRect:redView.frame toView:[UIApplication sharedApplication].keyWindow];
CGRect newRect = [redView convertRect:redView.bounds toView:nil];
CGRect newRect = [redView.superview convertRect:redView.frame toView:nil];

關(guān)于tableView的估算高度的那個屬性的深入研究
// 所有cell的高度 -> contentSize.height -> 滾動條長度
// 1000 * 20 -> contentSize.height -> 滾動條長度
// contentSize.height -> 200 * 20 -> 16800
/*
使用estimatedRowHeight的優(yōu)缺點
1.優(yōu)點
1> 可以降低tableView:heightForRowAtIndexPath:方法的調(diào)用頻率
2> 將【計算cell高度的操作】延遲執(zhí)行了(相當(dāng)于cell高度的計算是懶加載的)

2.缺點
1> 滾動條長度不準(zhǔn)確捧弃、不穩(wěn)定医咨,甚至有卡頓效果(如果不使用estimatedRowHeight,滾動條的長度就是準(zhǔn)確的)
*/

/**
這個方法的特點:
1.默認(rèn)情況下(沒有設(shè)置estimatedRowHeight的情況下)
1> 每次刷新表格時误续,有多少數(shù)據(jù)飘哨,這個方法就一次性調(diào)用多少次(比如有100條數(shù)據(jù),每次reloadData時尼啡,這個方法就會一次性調(diào)用100次)
2> 每當(dāng)有cell進(jìn)入屏幕范圍內(nèi)暂衡,就會調(diào)用一次這個方法

2.設(shè)置estimatedRowHeight的情況下
1> 用到了(顯示了)哪個cell,才會調(diào)用這個方法計算那個cell的高度(方法調(diào)用頻率降低了)
*/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末崖瞭,一起剝皮案震驚了整個濱河市狂巢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌书聚,老刑警劉巖唧领,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藻雌,死亡現(xiàn)場離奇詭異,居然都是意外死亡斩个,警方通過查閱死者的電腦和手機胯杭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來受啥,“玉大人做个,你說我怎么就攤上這事」鼍郑” “怎么了居暖?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長藤肢。 經(jīng)常有香客問我太闺,道長,這世上最難降的妖魔是什么嘁圈? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任省骂,我火速辦了婚禮,結(jié)果婚禮上丑孩,老公的妹妹穿的比我還像新娘冀宴。我一直安慰自己,他們只是感情好温学,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布略贮。 她就那樣靜靜地躺著,像睡著了一般仗岖。 火紅的嫁衣襯著肌膚如雪逃延。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天轧拄,我揣著相機與錄音揽祥,去河邊找鬼。 笑死檩电,一個胖子當(dāng)著我的面吹牛拄丰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播俐末,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼料按,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卓箫?” 一聲冷哼從身側(cè)響起载矿,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烹卒,沒想到半個月后闷盔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弯洗,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年逢勾,在試婚紗的時候發(fā)現(xiàn)自己被綠了牡整。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡敏沉,死狀恐怖果正,靈堂內(nèi)的尸體忽然破棺而出炎码,到底是詐尸還是另有隱情盟迟,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布潦闲,位于F島的核電站攒菠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏歉闰。R本人自食惡果不足惜辖众,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望和敬。 院中可真熱鬧凹炸,春花似錦、人聲如沸昼弟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舱痘。三九已至变骡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芭逝,已是汗流浹背塌碌。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留旬盯,地道東北人台妆。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像胖翰,于是被迫代替她去往敵國和親接剩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫泡态、插件搂漠、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,059評論 4 62
  • 1,情結(jié)--留在記憶力的碎片某弦,小時候某個事件讓自己產(chǎn)生會被拋棄的情緒 2桐汤,總在發(fā)生類似場景時候觸發(fā)到當(dāng)時的情緒 3...
    海鑫Hedy閱讀 180評論 0 0
  • 一怔毛、查找與替換 1员萍、替換 基本替換 規(guī)定格式替換 按顏色替換 規(guī)定條件替換 規(guī)定替換兩個字,要單元格匹配 2拣度、按格...
    武林大蝦閱讀 437評論 0 0
  • CSS和JS在網(wǎng)頁中的放置順序是怎樣的碎绎? 一般將CSS文件放在header內(nèi),頁面渲染時先生成DOM樹再根據(jù)CSS...
    Schrodinger的貓閱讀 362評論 0 0