@(iOS Study)[實戰(zhàn)技術]
- 作者: Liwx
- 郵箱: 1032282633@qq.com
目錄
- 02.實戰(zhàn)技術 父子控制器,常量Const,開發(fā)中常見問題
- 開發(fā)中常見問題/常量Const/父子控制器
- 1.super,superClass,class關鍵字
- super,superClass,class介紹
- super關鍵字
- 2.項目奇怪的bug
- bug1. 已添加文件到項目中,卻提示未定義
- bug2. 重復添加文件到項目中
- bug3. 導入.m文件
- 3.const的使用
- const與宏的區(qū)別
- const的簡單使用
- const開發(fā)中使用場景
- static和extern使用
- static和const聯合使用
- extern和const聯合使用
- 4.父子控制器
- 父子控制器簡介
- 父子控制器相關知識點
- 父子控制器的簡單使用
- 5.開發(fā)中常見問題
- UIScrollView的自動布局
- UIScrollView自動布局步驟(重要)
- size和center設置注意點
- bounds和frame簡介
- bounds和frame介紹
開發(fā)中常見問題/常量Const/父子控制器
1.super,superClass,class關鍵字
super,superClass,class介紹
- 關鍵字在方法中的意義
self: 方法調用者
class: 獲取方法調用者的類對象
superclass:獲取方法調用者的父類對象
super關鍵字
-
super關鍵字的介紹
- super:不是一個指針,編譯指示器(標識符)
- super的本質:其實還是當前對象去調用,只不過讓當前對象去調用父類方法
- super不是父類對象,指的是父類方法
注意
:[super class]表示用self調用父類方法,[super superclass]表示用self調用父類的方法(獲取父類方法)super的案例說明
@implementation SubPerson
- (void)test
{
// [super class]表示用self調用父類方法,[super superclass]表示用self調用父類的方法(獲取父類方法)
NSLog(@"%@ %@ %@ %@",[self class], [self superclass], [super class], [super superclass]);
// 正確打印結果: SubPerson Person SubPerson Person √
// 錯誤打印結果: SubPerson Person Person NSObject X
}
@end
2.項目奇怪的bug
bug1. 已添加文件到項目中,卻提示未定義
- 已添加文件到項目中,卻提示未定義bug
- 導致該bug的原因
- 在創(chuàng)建文件/從其他地方拖進工程的時候,沒有勾選以下選項
創(chuàng)建的時候未勾選該選項,導致沒添加到編譯列表
- 在創(chuàng)建文件/從其他地方拖進工程的時候,沒有勾選以下選項
從其他地方拖進工程的時候,沒有勾選Targets項,導致沒添加到編譯列表
- 解決方案: 在
項目文件/Build Phases/Complie Sources
將文件(.m文件)
添加到編譯列表
bug2. 重復添加文件到項目中
- 重復添加文件,提示錯誤
- 解決方案: 找出重復文件,將文件移除.
bug3. 導入.m文件
- 不小心導入了.m文件
3.const的使用
const與宏的區(qū)別
-
const與宏的區(qū)別
- 1.
編譯時刻
:const:編譯時期 宏:預編譯時期
- 2.
編譯檢測
: const有編譯檢測,宏沒有編譯檢測.如#define WXKey @"123"488 ,這樣宏不會提示錯誤. - 3.
宏可以替換方法和函數,const不行
- 4.
大量使用宏,容易造成預編譯時期過長
. - 有博客提到:大量使用宏,會導致內存暴增,有異議.
- 1.
蘋果使用const為了迎合swift
'#'號是預編譯指令
- 預編譯時期:項目一打開的時候,有個
自動讀條時期
,這個時期就是在做預編譯操作
,如果定義了大量的宏,可能會導致自動讀條的時間變長,是開發(fā)效率變低,蘋果官方建議盡量少使用宏
.
const的簡單使用
-
const的作用
- 1.用來
修飾右邊
變量(基本變量,指針變量,對象等) - 2.只要被
const修飾的變量,只讀
- 1.用來
-
const使用原則
-
放在const右邊被修飾的變量為只讀
.
-
const筆試題
// 1.原因:const修飾的是p,所以p為只讀;const在*之后,const沒修飾*p,所以*p是變量.
int * const p; // p:只讀 *p:變量
// 2.原因: const修飾的是*p1,所以*p1為只讀;const沒修飾p1,所以p1是變量.
int const *p1; // p1:變量 *p1:只讀
// 3.原因: const修飾*p2,所以*p2為只讀;const沒修飾p2,所以p2為變量
const int *p2; // p2:變量 *p2:只讀
// 4.原因: 第一個const修飾*p3,所以*p3為只讀;第二個const修飾p3,所以p3為只讀
int const * const p3; // p3:只讀 *p3:只讀
// 5.原因: 第一個const修飾*p4,所以*p4為只讀;第二個const修飾p4,所以p4為只讀
const int * const p4; // p4:只讀 *p4:只讀
const開發(fā)中使用場景
- 1.當代碼多處(不同方法中)共用同一個只讀(無需修改)的字符串,比如多處(不同方法中)用到setValue:forKey:時都需要用到同一個key時,可以使用以下方法定義const字符串常量.
NSString * const key = @"key";
static和extern使用
-
static和extern的作用
- static作用:
1.描述局部變量,局部變量被
static修飾,生命周期延長(整個app運行過程中都在),作用域不變
.
2.局部變量被static修飾,只會分配一次內存,程序一啟動就會分配
.
3.修飾全局變量,全局變量被static修飾,生命周期不變,作用域會變,只能在當前文件下使用
.-
extern作用:
聲明
一個全局變量,不能定義變量
.
static和const聯合使用
- static和const聯合使用場景
// 用于KVC的key時,可以static和const聯合使用
static NSString * const ageKey = @"age";
extern和const聯合使用
開發(fā)規(guī)范
:全局變量不能在自己的文件下定義,搞一個專門文件,去管理所有全局變量-
extern和const聯合使用使用場景(聲明全局常量的時候)
- 創(chuàng)建Const.h和Const.m文件用來存放全局常量
- 在Const.h中使用extern和const聲明 NSString * const nameKey;
注意
:不能在.h文件中賦值. - 在Const.m中定義NSString * const nameKey = @"name";
開發(fā)中存放常量的文件中,常量可以按功能模塊劃分.
// Const.m
#import "Const.h"
/*********我的********/
NSString * const nameKey = @"nameKey";
/*********發(fā)現********/
NSString * const discoveryKey = @"discoveryKey";
// Const.h
/*********我的********/
extern NSString * const nameKey;
/*********發(fā)現********/
extern NSString * const discoveryKey;
- 模仿系統(tǒng)實現extern
// Const.h
// WXKIT_EXTERN相當于extern
#define WXKIT_EXTERN extern __attribute__((visibility ("default")))
WXKIT_EXTERN NSString * const nameKey;
4.父子控制器
父子控制器簡介
父子控制器應用場景-
多控制器管理者
:導航控制器,tabBarController,內部原理就是采取父子控制器去管理
.
任何控制器都可以成為父控制器
父子控制器設計原則:把A控制器的view添加到B控制器的view上,那么A控制器必須要成為B控制器子控制器
.
父子控制器相關知識點
- 調試時
已知問題可以先列出來
,以防忘記,遺漏處理已經存在的問題
/*
問題:
1.每次都創(chuàng)建控制器
2.每次都添加view
3.控制器被銷毀
*/
-
調用dismissViewControllerAnimated:completion:方法時,dismiss實現內部實現
- 1.判斷下當前控制器是不是modal,如果是,就會dismiss
- 2.如果不是,判斷下父控制器是不是modal,如果是,就會dismiss
- 3.繼續(xù)判斷,直到沒有
-
只有
導航控制器子控制器才能獲取self.navigationController
.- 使用
self.navigationController
時,會判斷自己是不是導航控制器子控制器
,如果不是,判斷自己的父控制器是不是導航控制器子控制
器,繼續(xù)判斷,直到沒有父控制器.
- 使用
父子控制器的簡單使用
- 父子控制的簡單使用
#import "ViewController.h"
#import "SocietyViewController.h"
#import "TopLineViewController.h"
#import "HotViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *topView;
@property (nonatomic, weak) UIButton *selectedBtn;
@property (weak, nonatomic) IBOutlet UIView *contentView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1.添加所有子控制器
[self setUpAllChildViewController];
// 2.通過控制器標題,設置按鈕顯示的文字
[self setupTopButton];
}
// ----------------------------------------------------------------------------------
// 初始化
#pragma mark - 初始化
/** 初始化頂部button */
- (void)setupTopButton
{
NSInteger count = self.topView.subviews.count;
for (NSInteger i = 0; i < count; i++) {
// 取出button
UIButton *btn = self.topView.subviews[i];
// 取出子控制器
UIViewController *vc1 = self.childViewControllers[i];
// 設置btn顯示的文字
[btn setTitle:vc1.title forState:UIControlStateNormal];
// 設置btn選中狀態(tài)的文字顏色,需在storyboard中將按鈕Type修改為Custom,否則系統(tǒng)默認會把按鈕渲染成藍色
[btn setTitleColor:[UIColor redColor] forState:UIControlStateSelected];
// 設置默認選中
if (i == 0) {
[self btnClick:btn];
}
}
}
/** 添加所有子控制器 */
- (void)setUpAllChildViewController
{
// 1.添加社會控制器
SocietyViewController *vc1 = [[SocietyViewController alloc] init];
vc1.title = @"社會";
[self addChildViewController:vc1];
// 2.添加頭條控制器
TopLineViewController *vc2 = [[TopLineViewController alloc] init];
vc2.title = @"頭條";
[self addChildViewController:vc2];
// 3.添加熱點控制器
HotViewController *vc3 = [[HotViewController alloc] init];
vc3.title = @"熱點";
[self addChildViewController:vc3];
}
// ----------------------------------------------------------------------------------
// 添加頂部三個按鈕的監(jiān)聽
#pragma mark - 事件監(jiān)聽
/** 監(jiān)聽頂部三個button的點擊 */
- (IBAction)btnClick:(UIButton *)btn {
// 1.切換選中狀態(tài)
[self changeSelectedBtn:btn];
// 2.設置子控制器view的屬性
// 2.1 根據button的tag值,取出對應的控制器
UIViewController *vc = self.childViewControllers[btn.tag];
// 2.2 設置控制器view的背景顏色和button的背景顏色一樣
vc.view.backgroundColor = btn.backgroundColor;
// 2.3 設置子控制器的view的frame
vc.view.frame = self.contentView.bounds;
// 3.將子控制器的view添加到contentView
// 3.1 先移除當前控制器view的所有子控件
[self.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
// 3.2 添加子控件的view到當前控制器的contentView上
[self.contentView addSubview:vc.view];
}
/** 切換按鈕選中狀態(tài) */
- (void)changeSelectedBtn:(UIButton *)btn
{
self.selectedBtn.selected = NO;
self.selectedBtn = btn;
self.selectedBtn.selected = YES;
}
@end
- NSArray類的
makeObjectsPerformSelector
方法的使用
// 數組調用該方法時,表示數組里每個元素會執(zhí)行test方法
[arr makeObjectsPerformSelector:@selector(test)];
-
UIButon的Type如果是System
,系統(tǒng)默認會把按鈕渲染成藍色
5.開發(fā)中常見問題
UIScrollView的自動布局
-
UIScrollView的自動布局思考
- 1.確定好
UIScrollView的滾動范圍contentSize
- 2.怎么確定?
搞一個view添加到UIScrollView上,這個view用來確定UIScrollView的滾動范圍
- 3.通過
設置這個view約束.來告訴UIScrollView滾動范圍
- 4.如何計算contentSize呢秧荆?
要計算contentSize必須清楚每個subviews的frame
,而subviews的frame居然又要依賴scrollView
?
- 1.確定好
-
UIScrollView的自動布局原則
- 1.
UIScrollView的contentSize依賴于subviews
. - 2.UIScrollView的
contentSize必須根據其子控件如UIView的4條邊來確定
. - 3.
注意
:如果只設置UIScrollView子控件的上下左右間距為0,是不能確定contentSize的,必須設置其子控件UIView的尺寸才能確定4條邊.
- 1.
UIScrollView自動布局步驟(重要)
- UIScrollView自動布局實現步驟
- 1.
給UIScrollView添加一個UIView,作為UIScrollView的contentView.
之后要添加其他子控件可以往contentView上添加,這樣UIScrollView就只有contentView一個子控件,便于布局 - 2.
設置contentView的尺寸(寬,高)
,因為UIScrollView的contentSize是由它的子控件的frame決定的
,contentView是UIScrollView的子控件,所以必須設置contentView的size才能確定contentSize
. - 3.設置
contentView的約束
,比如設置約束上下左右間距都為0.
- 1.
size和center設置注意點
size和center如果一起使用時,如果
設置的是frame的size,必須先設置尺寸frame.size,再設置center
.如果設置的是bounds的size,就無需考慮先后順序
.因為center就是根據bounds中的size決定的
.設置frame的size屬性,先設置尺寸frame.size,再設置center.
- (void)viewDidLoad {
[super viewDidLoad];
// 創(chuàng)建redView
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
// 先設置尺寸
CGRect frame = redView.frame;
frame.size = CGSizeMake(200, 200);
redView.frame = frame;
// 再設置center
redView.center = CGPointMake(self.view.bounds.size.width * 0.5, self.view.bounds.size.height * 0.5);
}
- 設置bounds的size屬性,無需先后順序.
- (void)viewDidLoad {
[super viewDidLoad];
// 創(chuàng)建redView
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
// 設置center
redView.center = CGPointMake(self.view.bounds.size.width * 0.5, self.view.bounds.size.height * 0.5);
// 設置尺寸
CGRect bounds = redView.bounds;
bounds.size = CGSizeMake(200, 200);
redView.bounds = bounds;
}
bounds和frame簡介
bounds和frame介紹
-
frame和bounds的區(qū)別
-
frame
:以父控件的左上角為原點
-
bounds
:以自己左上角為原點
,x,y = 0,(X)
-
-
frame和bounds描述一個矩形
- frame:可視范圍
- bounds:描述 可視范圍 在 內容范圍 區(qū)域
-
bounds本質:
修改內容原點
位置- 子控件是相對于控件
內容范圍
frame:相對于父控件,位置永遠不變
frame:相對于內容,就會改變
- 子控件是相對于控件