UITableView

UITableViewCell控件空間構(gòu)造

  • cell的子控件是contentView,contentView的子控件是imageView、textLabel、detailTextLabel
  • 可以通過移動contentView,顯示刪除按鈕,點擊刪除按鈕便可實現(xiàn)刪除對應(yīng)的cell
  • 在代碼方式制作等高cell中,cell可以通過AutoLayOut(約束)在layoutSubView或initWithStyle方法中設(shè)置子控件的位置
  • 靜態(tài)cell的數(shù)據(jù)是死的且可以自定義,動態(tài)cell數(shù)據(jù)顯示源自模型數(shù)據(jù)庫


    Snip20170205_143.png
  • 設(shè)置tableView每 cell的度,默認(rèn)是44


    Snip20170205_136.png

    Snip20170205_137.png

UITableView

  • 表頂部圖片顯示:將圖片控件添加到表頭視圖上


    Snip20170205_144.png
self.tableView.tableHeaderView
  • 凡是遵守UITableViewDataSource協(xié)議的OC對象,都可以是UITableView的數(shù)據(jù)源
  • Control負(fù)責(zé)初始化Model,并將Model傳遞給View去解析展示


    Snip20170205_140.png

Cell的重用原理

Snip20170205_141.png
  • 重用原理:
    • 當(dāng)滾動列表時,部分UITableViewCell會移出窗口,UITableView會將窗口外的UITableViewCell放入一個對象池中,等待重用。當(dāng)UITableView要求dataSource返回UITableViewCell時,dataSource會先查看這個對象池,如果池中有未使用的UITableViewCell,dataSource會用新的數(shù)據(jù)配置這個UITableViewCell,然后返回給UITableView,重新顯示到窗口中,從而避免創(chuàng)建新對象
  • 解決方案:
    • UITableViewCell有個NSString *reuseIdentifier屬性,可以在初始化UITableViewCell的時候傳入一個特定的字符串標(biāo)識來設(shè)置reuseIdentifier(一般用UITableViewCell的類名)。當(dāng)UITableView要求dataSource返回UITableViewCell時,先通過一個字符串標(biāo)識到對象池中查找對應(yīng)類型的UITableViewCell對象,如果有,就重用,如果沒有,就傳入這個字符串標(biāo)識來初始化一個UITableViewCell對象

Cell的重用代碼

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 1.定義一個cell的標(biāo)識
static NSString *ID = @”cell";
// 2.從緩存池中取出cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 3.如果緩存池中沒有cell
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
}

通過代碼自定義cell(cell的高度不一致)

  • 新建一個繼承自UITableViewCell的類
  • 重寫initWithStyle:reuseIdentifier:方法
    • 添加所有需要顯示的子控件(不需要設(shè)置子控件的數(shù)據(jù)和frame, 子控件要添加到contentView中)
    • 進(jìn)行子控件一次性的屬性設(shè)置(有些屬性只需要設(shè)置一次, 比如字體固定的圖片)
  • 提供2個模型
    • 數(shù)據(jù)模型: 存放文字?jǐn)?shù)據(jù)\圖片數(shù)據(jù)
    • frame模型: 存放數(shù)據(jù)模型\所有子控件的frame\cell的高度
    • cell擁有一個frame模型(不要直接擁有數(shù)據(jù)模型)
  • 重寫frame模型屬性的setter方法: 在這個方法中設(shè)置子控件的顯示數(shù)據(jù)和frame
  • frame模型數(shù)據(jù)的初始化已經(jīng)采取懶加載的方式(每一個cell對應(yīng)的frame模型數(shù)據(jù)只加載一次)

UITextField

  • 通過UITextField的代理方法能夠監(jiān)聽鍵盤最右下角按鈕的點擊
  • 成為UITextField的代理
self.textField.delegate = self;
  • 遵守UITextFieldDelegate協(xié)議,實現(xiàn)代理方法
  - (BOOL)textFieldShouldReturn:(UITextField *)textField;
  • 在UITextField左邊放一個view
self.textField.leftView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 8, 0)];
self.textField.leftViewMode = UITextFieldViewModeAlways;

索引條

  • 設(shè)置索引條上 字顏
   self.tableView.sectionIndexColor = [UIColor redColor];
  • 設(shè)置索引條的背景顏
self.tableView.sectionIndexBackgroundColor = [UIColor blackColor];
  • 返回每 組的索引標(biāo)題(數(shù)組中都是NSString對象)
 - (NSArray<NSString *>*)sectionIndexTitlesForTableView:(UITableView *)tableView {
}

Frame自定義不等高的cell

  • 給模型增加frame數(shù)據(jù)
    • 所有子控件的frame
    • cell的高度
    @interface XMGStatus : NSObject
 /** 頭像的frame */
 @property (nonatomic, assign) CGRect iconFrame;
 // .....
 /** cell的高度 */
 @property (nonatomic, assign) CGFloat cellHeight;
 @end
  • 重寫模型cellH屬性的get方法
 - (CGFloat)cellHeight{
if (_cellHeight == 0) {
// ... 計算所有子控件的frame、cell的高度
}
   return _cellHeight;
}
  • 在控制器中
    • 實現(xiàn)一個返回cell高度的代理方法
    • 在這個方法中返回indexPath位置對應(yīng)cell的高度
/**
   返回每一行cell的具體高度
*/
    - (CGFloat)tableView:(UITableView *)tableView     heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    XMGStatus *status = self.statuses[indexPath.row];
    return status.cellH;
}
  • 給cell傳遞模型數(shù)據(jù)
   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *ID = @"status";
// 訪問緩存池
XMGStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 設(shè)置數(shù)據(jù)(傳遞模型數(shù)據(jù))
cell.status = self.statuses[indexPath.row];
return cell;
}
  • 新建一個繼承自UITableViewCell的子類,比如XMGStatusCell
@interface XMGStatusCell : UITableViewCell
@end
  • 在XMGStatusCell.m文件中
  • 重寫-initWithStyle:reuseIdentifier:方法
  • 在這個方法中添加所有可能顯示的子控件
  • 給子控件做一些初始化設(shè)置(設(shè)置字體、文字顏色等)
  /**
    * 在這個方法中添加所有的子控件
  */
    - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// ......
}
return self;
}
  • 在XMGStatusCell.h文件中提供一個模型屬性,比如XMGStatus模型
  @class XMGStatus;
@interface XMGStatusCell : UITableViewCell
/** 團(tuán)購模型數(shù)據(jù) */
@property (nonatomic, strong) XMGStatus *status;
@end
  • 在XMGStatusCell.m文件中重寫模型屬性的set方法
    • 在set方法中給子控件設(shè)置模型數(shù)據(jù)
     - (void)setStatus:(XMGStatus *)status{
   _status = status;
   // .......
}
  • 重寫-layoutSubviews方法
    • 一定要調(diào)用[super layoutSubviews]
    • 在這個方法中設(shè)置所有子控件的frame
      /**
      * 在這個方法中設(shè)置所有子控件的frame
      */
      - (void)layoutSubviews{
               [super layoutSubviews];
         // ......
}

AutoLayOut自定義等高的cell

  • 新建一個繼承自UITableViewCell的子類,比如XMGTgCell
@interface XMGTgCell : UITableViewCell
@end
  • 在XMGTgCell.m文件中
    • 重寫-initWithStyle:reuseIdentifier:方法
    • 在這個方法中添加所有的子控件
    • 給子控件做一些初始化設(shè)置(設(shè)置字體、文字顏色等)
    • 添加子控件的完整約束
    /**
      * 在這個方法中添加所有的子控件
     */
      - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// ......
}
return self;
}
  • 在XMGTgCell.h文件中提供一個模型屬性,比如XMGTg模型
   @class XMGTg;
   @interface XMGTgCell : UITableViewCell
   /** 團(tuán)購模型數(shù)據(jù) */
   @property (nonatomic, strong) XMGTg *tg;
@end
  • 在XMGTgCell.m中重寫模型屬性的set方法
    • 在set方法中給子控件設(shè)置模型數(shù)據(jù)
   - (void)setTg:(XMGTg *)tg{
_tg = tg;
   // .......
   }
  • 在控制器中
  • 注冊cell的類型
[self.tableView registerClass:[XMGTgCell class] forCellReuseIdentifier:ID];
  • 給cell傳遞模型數(shù)據(jù)
   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    // 訪問緩存池
   XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
   // 設(shè)置數(shù)據(jù)(傳遞模型數(shù)據(jù))
   cell.tg = self.tgs[indexPath.row];
return cell;
}

字典轉(zhuǎn)模型第三方框架

  • Mantle
  • 所有模型都必須繼承自MTModel
  • JSONModel
  • 所有模型都必須繼承自JSONModel
  • MJExtension
  • 不需要強制繼承任何其他類

Frame(微博)自定義等高的cell

  • 新建一個繼承自UITableViewCell的子類,比如XMGTgCell
@interface XMGTgCell : UITableViewCell
@end
  • 在XMGTgCell.m文件中
    • 重寫-initWithStyle:reuseIdentifier:方法
    • 在這個方法中添加所有的子控件
    • 給子控件做一些初始化設(shè)置(設(shè)置字體、文字顏色等)
   /**
   * 在這個方法中添加所有的子控件
   */
   - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
// ......
}
return self;
}
  • 重寫-layoutSubviews方法
  • 一定要調(diào)用[super layoutSubviews]
  • 在這個方法中計算和設(shè)置所有子控件的frame
    /**
      * 在這個方法中計算所有子控件的frame
    */
    - (void)layoutSubviews{
     [super layoutSubviews];
// ......
}
  • 在XMGTgCell.h文件中提供一個模型屬性,比如XMGTg模型
@class XMGTg;

@interface XMGTgCell : UITableViewCell
/** 團(tuán)購模型數(shù)據(jù) */
@property (nonatomic, strong) XMGTg *tg;
@end
  • 在XMGTgCell.m中重寫模型屬性的set方法
  • 在set方法中給子控件設(shè)置模型數(shù)據(jù)
    - (void)setTg:(XMGTg *)tg{
_tg = tg;
// .......
}
  • 在控制器中
    • 注冊cell的類型
[self.tableView registerClass:[XMGTgCell class] forCellReuseIdentifier:ID];
  • 給cell傳遞模型數(shù)據(jù)
      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 訪問緩存池
XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 設(shè)置數(shù)據(jù)(傳遞模型數(shù)據(jù))
cell.tg = self.tgs[indexPath.row];
return cell;
}

StoryBoard(微博)自定義等高的cell

  • 新建一個繼承自UITableViewCell的子類,比如XMGTgCell
@interface XMGTgCell : UITableViewCell
@end
  • 在storyboard文件中,找到UITableView里面的cell(動態(tài)cell)
    • 修改cell的class為XMGTgCell
    • 綁定循環(huán)利用標(biāo)識
    • 添加子控件,設(shè)置子控件約束
    • 將子控件連線到類擴(kuò)展中
@interface XMGTgCell()
@property (weak, nonatomic) IBOutlet UIImageView *iconImageView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *buyCountLabel;
@end
  • 在XMGTgCell.h文件中提供一個模型屬性,比如XMGTg模型
@class XMGTg;
@interface XMGTgCell : UITableViewCell
/** 團(tuán)購模型數(shù)據(jù) */
@property (nonatomic, strong) XMGTg *tg;
@end
  • 在XMGTgCell.m中重寫模型屬性的set方法
    • 在set方法中給子控件設(shè)置模型數(shù)據(jù)
    - (void)setTg:(XMGTg *)tg{
  _tg = tg;
// .......
}
  • 在控制器中
    • 給cell傳遞模型數(shù)據(jù)
      - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *ID = @"tg";
// 訪問緩存池
XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 設(shè)置數(shù)據(jù)(傳遞模型數(shù)據(jù))
cell.tg = self.tgs[indexPath.row];
return cell;
}

xib自定義等高cell

  • 新建一個繼承自UITableViewCell的子類,比如XMGTgCell
@interface XMGTgCell : UITableViewCell
@end
  • 新建一個xib文件(文件名最好跟類名一致,比如XMGTgCell.xib)
    • 修改cell的class為XMGTgCell
    • 綁定循環(huán)利用標(biāo)識
    • 添加子控件,設(shè)置子控件約束
    • 將子控件連線到類擴(kuò)展中
@interface XMGTgCell()
@property (weak, nonatomic) IBOutlet UIImageView *iconImageView;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *buyCountLabel;
@end
  • 在XMGTgCell.h文件中提供一個模型屬性,比如XMGTg模型
@class XMGTg;
@interface XMGTgCell : UITableViewCell
/** 團(tuán)購模型數(shù)據(jù) */
@property (nonatomic, strong) XMGTg *tg;
@end
  • 在XMGTgCell.m中重寫模型屬性的set方法
    • 在set方法中給子控件設(shè)置模型數(shù)據(jù)
     - (void)setTg:(XMGTg *)tg{
    _tg = tg;
// .......
}
  • 在控制器中
    • 注冊xib文件
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([XMGTgCell class]) bundle:nil] forCellReuseIdentifier:ID];
  • 給cell傳遞模型數(shù)據(jù)
        - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// 訪問緩存池
XMGTgCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
// 設(shè)置數(shù)據(jù)(傳遞模型數(shù)據(jù))
cell.tg = self.tgs[indexPath.row];
return cell;
}

StoryBoard(微博)-自定義不等的cell

  • 對比自定義等高cell,需要幾個額外的步驟(iOS8開始才支持)
    • 添加子控件和contentView之間的間距約束
    • 設(shè)置tableViewCell的真實行高和估算行高
//告訴tableView所有cell的真實高度是自動計算(根據(jù)設(shè)置的約束來計算)
self.tableView.rowHeight = UITableViewAutomaticDimension;
//告訴tableView所有cell的估算高度
self.tableView.estimatedRowHeight = 44;
  • 如果要支持iOS8之前
    • 如果cell內(nèi)部有自動換行的label,需要設(shè)置preferredMaxLayoutWidth屬性
-(void)awakeFromNib
{
//手動設(shè)置文字的最大寬度(目的是:讓label知道自己文字的最大寬度,進(jìn)而能夠計算出自己的frame)
self.text_label.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 20;
}
  • 設(shè)置tableView的cell估算高度
//告訴tableView所有cell的估算高度(設(shè)置了估算高度,就可以減少tableView:heightForRowAtIndexPath:方法的調(diào)用次數(shù))
self.tableView.estimatedRowHeight = 200;
  • 在代理方法中計算cell的高度
XMGStatusCell *cell;
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//創(chuàng)建一個臨時的cell(cell的作用:根據(jù)模型數(shù)據(jù)布局所有的子控件,進(jìn)而計算出cell的高度)
if (!cell) {
cell = [tableView dequeueReusableCellWithIdentifier:ID];
}
//設(shè)置模型數(shù)據(jù)
cell.status = self.statuses[indexPath.row];
return cell.height;
}
-(CGFloat)height{
//強制布局cell內(nèi)部的所有子控件(label根據(jù)文字多少計算出自己最真實的尺寸)
[self layoutIfNeeded];
//計算cell的高度
if (self.status.picture) {
return CGRectGetMaxY(self.pictureImageView.frame) + 10;
} else {
return CGRectGetMaxY(self.text_label.frame) + 10;
}
}

數(shù)據(jù)刷新

  • 添加數(shù)據(jù)

  • 刪除數(shù)據(jù)

  • 更改數(shù)據(jù)

  • 全局刷新方法(最常用)

[self.tableView reloadData];
//屏幕上的所有可視的cell都會刷新一遍
  • 局部刷新方法

    • 添加數(shù)據(jù)
NSArray *indexPaths = @[
[NSIndexPath indexPathForRow:0 inSection:0],
[NSIndexPath indexPathForRow:1 inSection:0]
];
[self.tableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationRight];
  • 刪除數(shù)據(jù)
NSArray *indexPaths = @[
[NSIndexPath indexPathForRow:0 inSection:0],
[NSIndexPath indexPathForRow:1 inSection:0]
];
[self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];
  • 更新數(shù)據(jù)(沒有添加和刪除數(shù)據(jù),僅僅是修改已經(jīng)存在的數(shù)據(jù))
NSArray *indexPaths = @[
[NSIndexPath indexPathForRow:0 inSection:0],
[NSIndexPath indexPathForRow:1 inSection:0]
];
[self.tableView relaodRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationMiddle];
  • 左滑出現(xiàn)刪除按鈕

    • 需要實現(xiàn)tableView的代理方法
/**
*只要實現(xiàn)了這個方法,左滑出現(xiàn)Delete按鈕的功能就有了
*點擊了“左滑出現(xiàn)的Delete按鈕”會調(diào)用這個方法
*/
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{

//刪除模型

[self.wineArray removeObjectAtIndex:indexPath.row];


//刷新

[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];

}


/**

*修改Delete按鈕文字為“刪除”

*/

- (NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath{

return @"刪除";

}
  • 左滑出現(xiàn)N個按鈕

  • 需要實現(xiàn)tableView的代理方法

/**
*只要實現(xiàn)了這個方法,左滑出現(xiàn)按鈕的功能就有了
(一旦左滑出現(xiàn)了N個按鈕,tableView就進(jìn)入了編輯模式, tableView.editing = YES)
*/
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{


}


/**
*左滑cell時出現(xiàn)什么按鈕
*/
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewRowAction *action0 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"關(guān)注" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
NSLog(@"點擊了關(guān)注");


//收回左滑出現(xiàn)的按鈕(退出編輯模式)
tableView.editing = NO;
}];


UITableViewRowAction *action1 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"刪除" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
[self.wineArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}];


return @[action1, action0];
}
  • 進(jìn)入編輯模式
// self.tabelView.editing = YES;
[self.tableView setEditing:YES animated:YES];
//默認(rèn)情況下,進(jìn)入編輯模式時,左邊會出現(xiàn)一排紅色的“減號”按鈕
  • 在編輯模式中多選
//編輯模式的時候可以多選
self.tableView.allowsMultipleSelectionDuringEditing = YES;
//進(jìn)入編輯模式
[self.tableView setEditing:YES animated:YES];
//獲得選中的所有行
self.tableView.indexPathsForSelectedRows;

代理的使用步驟

  • 定義一份代理協(xié)議
  • 協(xié)議名字的格式一般是:類名+ Delegate
  • 比如UITableViewDelegate
  • 設(shè)計代理的細(xì)節(jié)
    • 一般都是@optional(讓代理可以有選擇性去實現(xiàn)一些代理方法)
  • 方法名一般都以類名開頭
    • 比如- (void)scrollViewDidScroll:
  • 一般都需要將對象本身傳出去
  • 比如tableView的代理方法都會把tableView本身傳出去
  • 必須要遵守NSObject協(xié)議(基協(xié)議)

  • 比如@protocol XMGWineCellDelegate <NSObject>

  • 聲明一個代理屬性

    • 代理的類型格式:id<協(xié)議> delegate
@property (nonatomic, weak) id<XMGWineCellDelegate> delegate;
  • 設(shè)置代理對象

  • 代理對象遵守協(xié)議,實現(xiàn)協(xié)議里面相應(yīng)的方法

  • 當(dāng)控件內(nèi)部發(fā)生了一些事情,就可以調(diào)用代理的代理方法通知代理

  • 如果代理方法是@optional,那么需要判斷方法是否有實現(xiàn),直接調(diào)用可能會報錯
if ([self.delegate respondsToSelector:@selector(wineCellDidClickPlusButton:)]) {
[self.delegate wineCellDidClickPlusButton:self];
}

iOS監(jiān)聽某些事件的方法

  • 通知(NSNotificationCenter\NSNotification)
  • 任何對象之間都可以傳遞消息
  • 使用范圍
  • 1個對象可以發(fā)通知給多個對象
  • 1個對象可以接受多個對象發(fā)出的通知
  • 要求:必須得保證通知的名字在發(fā)出和監(jiān)聽時是一致的
  • KVO
    • 僅僅是能監(jiān)聽對象屬性的改變(靈活度不如通知和代理)
  • 代理
  • 使用范圍
  • 1個對象只能設(shè)置一個代理(假設(shè)這個對象只有1個代理屬性)
  • 1個對象能成為多個對象的代理
  • 如何選擇?
    • 代理比通知規(guī)范
    • 建議使用代理多于通知,能使用代理盡量使用代理

通知

  • 基本概念

    • 每一個應(yīng)用程序都有一個通知中心(NSNotificationCenter)實例,專門負(fù)責(zé)協(xié)助不同對象之間的消息通信

    • 任何一個對象都可以向通知中心發(fā)布通知(NSNotification),描述自己在做什么。其他感興趣的對象(Observer)可以申請在某個特定通知發(fā)布時(或在某個特定的對象發(fā)布通知時)收到這個通知

    • 一個完整的通知一般包含3個屬性:

      • -(NSString *)name; // 通知的名稱

      • -(id)object; // 通知發(fā)布者(是誰要發(fā)布通知)

      • -(NSDictionary *)userInfo; // 一些額外的信息(通知發(fā)布者傳遞給通知接收者的信息內(nèi)容)

    • 初始化一個通知(NSNotification)對象

      • +(instancetype)notificationWithName:(NSString *)aName object:(id)anObject;

      • +(instancetype)notificationWithName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

      • -(instancetype)initWithName:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo;

  • 發(fā)布通知

    • 通知中心(NSNotificationCenter)提供了相應(yīng)的方法來幫助發(fā)布通知

    • -(void)postNotification:(NSNotification *)notification;

      • 發(fā)布一個notification通知,可在notification對象中設(shè)置通知的名稱、通知發(fā)布者、額外信息等
    • -(void)postNotificationName:(NSString *)aName object:(id)anObject;

      • 發(fā)布一個名稱為aName的通知,anObject為這個通知的發(fā)布者
    • -(void)postNotificationName:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;

      • 發(fā)布一個名稱為aName的通知,anObject為這個通知的發(fā)布者,aUserInfo為額外信息
  • 注冊通知監(jiān)聽器

    • 通知中心(NSNotificationCenter)提供了方法來注冊一個監(jiān)聽通知的監(jiān)聽器(Observer)
      • -(void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject;
      • observer:監(jiān)聽器,即誰要接收這個通知
      • aSelector:收到通知后,回調(diào)監(jiān)聽器的這個方法,并且把通知對象當(dāng)做參數(shù)傳入
      • aName:通知的名稱。如果為nil,那么無論通知的名稱是什么,監(jiān)聽器都能收到這個通知
      • anObject:通知發(fā)布者。如果為anObject和aName都為nil,監(jiān)聽器都收到所有的通知
      • -(id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block;
        • name:通知的名稱
        • obj:通知發(fā)布者
        • block:收到對應(yīng)的通知時,會回調(diào)這個block
        • queue:決定了block在哪個操作隊列中執(zhí)行,如果傳nil,默認(rèn)在當(dāng)前操作隊列中同步執(zhí)行
  • 取消注冊通知監(jiān)聽器

    • 通知中心不會保留(retain)監(jiān)聽器對象,在通知中心注冊過的對象,必須在該對象釋放前取消注冊。否則,當(dāng)相應(yīng)的通知再次出現(xiàn)時,通知中心仍然會向該監(jiān)聽器發(fā)送消息。因為相應(yīng)的監(jiān)聽器對象已經(jīng)被釋放了,所以可能會導(dǎo)致應(yīng)用崩潰

    • 通知中心提供了相應(yīng)的方法來取消注冊監(jiān)聽器

      • -(void)removeObserver:(id)observer;
      • -(void)removeObserver:(id)observer name:(NSString *)aName object:(id)anObject;
    • 一般在監(jiān)聽器銷毀之前取消注冊(如在監(jiān)聽器中加入下列代碼):

      • -(void)dealloc {
        //[super dealloc]; 非ARC中需要調(diào)用此句
        [[NSNotificationCenter defaultCenter] removeObserver:self];
        }
  • UIDevice通知

    • UIDevice類提供了一個單粒對象,它代表著設(shè)備,通過它可以獲得一些設(shè)備相關(guān)的信息,比如電池電量值(batteryLevel)、電池狀態(tài)(batteryState)、設(shè)備的類型(model,比如iPod、iPhone等)、設(shè)備的系統(tǒng)(systemVersion)
  • 通過[UIDevice currentDevice]可以獲取這個單粒對象

  • UIDevice對象會不間斷地發(fā)布一些通知,下列是UIDevice對象所發(fā)布通知的名稱常量:

    • UIDeviceOrientationDidChangeNotification // 設(shè)備旋轉(zhuǎn)
    • UIDeviceBatteryStateDidChangeNotification // 電池狀態(tài)改變
    • UIDeviceBatteryLevelDidChangeNotification // 電池電量改變
    • UIDeviceProximityStateDidChangeNotification // 近距離傳感器(比如設(shè)備貼近了使用者的臉部)
  • 鍵盤通知

    • 我們經(jīng)常需要在鍵盤彈出或者隱藏的時候做一些特定的操作,因此需要監(jiān)聽鍵盤的狀態(tài)

    • 鍵盤狀態(tài)改變的時候,系統(tǒng)會發(fā)出一些特定的通知

      • UIKeyboardWillShowNotification // 鍵盤即將顯示
      • UIKeyboardDidShowNotification // 鍵盤顯示完畢
      • UIKeyboardWillHideNotification // 鍵盤即將隱藏
      • UIKeyboardDidHideNotification // 鍵盤隱藏完畢
      • UIKeyboardWillChangeFrameNotification // 鍵盤的位置尺寸即將發(fā)生改變
      • UIKeyboardDidChangeFrameNotification // 鍵盤的位置尺寸改變完畢
  • 系統(tǒng)發(fā)出鍵盤通知時,會附帶一下跟鍵盤有關(guān)的額外信息(字典),字典常見的key如下:

    • UIKeyboardFrameBeginUserInfoKey // 鍵盤剛開始的frame
    • UIKeyboardFrameEndUserInfoKey // 鍵盤最終的frame(動畫執(zhí)行完畢后)
    • UIKeyboardAnimationDurationUserInfoKey // 鍵盤動畫的時間
    • UIKeyboardAnimationCurveUserInfoKey // 鍵盤動畫的執(zhí)行節(jié)奏(快慢)
  • 通知和代理的選擇

    • 共同點

      • 利用通知和代理都能完成對象之間的通信
        (比如A對象告訴D對象發(fā)生了什么事情, A對象傳遞數(shù)據(jù)給D對象)
    • 不同點

      • 代理 : 1個對象只能告訴另1個對象發(fā)生了什么事情
      • 通知 : 1個對象能告訴N個對象發(fā)生了什么事情, 1個對象能得知 N個對象發(fā)生了什么事情
  • 總結(jié)
    • 子類指向父類,需要強轉(zhuǎn)一下
    • 擋在最前面的控件先處理事件。
    • 給某個類使用kvo監(jiān)聽,運行過程中系統(tǒng)默認(rèn)會給他增加一個子類,這樣會增加性能消耗,isa指向真實類 [wine valueForKeyPath:”isa” ];或[wine class]可以獲取對象的類名 ,使用kvo方法valueForKeyPath可以獲取私有屬性的值
    • 代理可以傳遞事件和數(shù)據(jù),目的是解耦
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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