以前在掘金社區是沒有原做權限的, 因此這篇文章在以前是經過連接分享的, 如今有原做權限因此爲了方便從新上傳一下文章!在上一篇文章中我相信幫助了不少的小夥伴, 那麼在這篇文章但願還能幫助到你!ios
咱們都會聲明一個弱引用在block
中使用, 目的就是防止循環引用, 那麼weakSelf
與strongSelf
一塊兒使用目的是什麼呢? 首先先定義2個宏:git
#define LRWeakSelf(type) __weak typeof(type) weak##type = type;
#define LRStrongSelf(type) __strong typeof(type) type = weak##type;複製代碼
咱們建立一個shop
而且在shop.myBlock
代碼塊中使用弱引用LRWeakSelf(shop);
github
LRShop *shop = [[LRShop alloc]init];
shop.string = @"welcome to our company";
//弱引用
LRWeakSelf(shop);
shop.myBlock = ^{
NSLog(@"%@",weakshop.string);
};
shop.myBlock();複製代碼
LRWeakSelf(shop);
與LRStrongSelf(shop);
一塊兒使用api
LRShop *shop = [[LRShop alloc]init];
shop.string = @"welcome to our company";
//弱引用
LRWeakSelf(shop);
shop.myBlock = ^{
//強引用
LRStrongSelf(shop)
NSLog(@"%@",shop.string);
};
shop.myBlock();複製代碼
這2個打印結果都是shop.string
有值而且shop
也銷燬了, 看起來是沒什麼區別:app
僅僅使用LRWeakSelf(shop);
而且在myBlock
中增長一個延遲3秒在輸出就會出現問題, 雖然對象銷燬了, 輸出的值倒是null
ide
//弱引用
LRWeakSelf(shop);
shop.myBlock = ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",weakshop.string);
});
};
shop.myBlock();複製代碼
若是LRWeakSelf(shop);
與LRStrongSelf(shop);
一塊兒使用輸出的shop.string
有值,對象也銷燬了, 我就再也不截圖給你們看了!字體
//弱引用
LRWeakSelf(shop);
shop.myBlock = ^{
//強引用
LRStrongSelf(shop)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"%@",shop.string);
});
};
shop.myBlock();複製代碼
經過上面一堆的解釋, 咱們明顯發現LRWeakSelf(shop);
與LRStrongSelf(shop);
一塊兒使用的好處, 不但能打印出我想要的值,並且也不會形成循環引用 , 在開發中這兩個方法能夠根據實際狀況進行使用!ui
若是不熟悉能夠點擊瞭解, UIAppearance
它的目的就是設置全局顯示樣式, 咱們知道只要帶UI_APPEARANCE_SELECTOR
這個宏, 咱們就可使用UIAppearance
好比這樣設置:atom
咱們知道UIBarButtonItem
它是有狀態的好比UIControlStateNormal
或者是UIControlStateDisabled
狀態 若是經過UIAppearance
設置UIControlStateDisabled
狀態下的顏色是很差使的, 由於使用appearance
會有一些延遲, 致使在不一樣狀態下的顏色很差使, 咱們只要強制刷新一下就能夠了:spa
// 刷新
[self.navigationController.navigationBar layoutIfNeeded];複製代碼
因此之後使用UIAppearance
在某個狀態下設置顏色,字體等很差使, 只須要在對應的位置用layoutIfNeeded
刷新一下就能夠了!
先貼一個UITextField
如何設置佔位文字的顏色, 若是不先設置佔位文字, 佔位文字的顏色是無論用的:
//先設置佔位文字
textField.placeholder = @"設置了佔位文字內容之後, 才能設置佔位文字的顏色";
//佔位文字顏色
[textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];複製代碼
你們監聽UITextField
文字的改變會用到代理:
#pragma mark -- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { //這裏監聽文字改變 return YES; } 複製代碼
可是這個代理方法監聽會有問題以下圖:
因此咱們要監聽UITextField
的文字改變不建議使用代理, 咱們用addTarget
監聽文字
[textField addTarget:self action:@selector(textEditingChanged) forControlEvents:UIControlEventEditingChanged];複製代碼
UITextView
的佔位文字屬於它內部的一個功能, 咱們在控制器
或者用代理
來處理佔位文字一些功能是不合理的, 因此咱們要自定義UITextView
把相關內部的東西都封裝起來! (1)給外界提供佔位文字與佔位文字顏色:
/** 佔位文字 */
@property (nonatomic, copy)NSString *placeholder;
/** 佔位文字顏色 */
@property (nonatomic, strong)UIColor *placeholderColor;複製代碼
(2)設置佔位文字的默認值, 若是不設置默認值,外界不用你提供的方法會有崩潰現象:
// 設置默認字體
self.font = [UIFont systemFontOfSize:17];
// 設置默認的佔位文字顏色
self.placeholderColor = [UIColor grayColor];複製代碼
(3)內部添加佔位文字的label:
/** 佔位文字label */
@property (nonatomic, weak) UILabel *placeholderLabel;
//懶加載
- (UILabel *)placeholderLabel
{
if (_placeholderLabel == nil) {
UILabel *placeholderLabel = [[UILabel alloc] init];
placeholderLabel.numberOfLines = 0;
[self addSubview:placeholderLabel];
_placeholderLabel = placeholderLabel;
}
return _placeholderLabel;
}複製代碼
(4)經過監聽文字改變,來顯示或隱藏佔位文字:
// 監聽文字
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChangeNotification) name:UITextViewTextDidChangeNotification object:nil];
//監聽的方法
- (void)textDidChangeNotification {
// 有文字就隱藏佔位文字
self.placeholderLabel.hidden = self.hasText;
}複製代碼
(5)若是佔位文字被修改, 顏色被修改, 字體被修改, 咱們在內部須要重寫set
方法, 若是經過代碼修改了textView
文字(不是佔位文字)不會發通知
也須要重寫set
方法:
封裝好的自定義TextView能夠直接使用:Demo下載
(1)若是有UITabBarController
咱們會這樣獲取導航控制器:
UIViewController *viewC = [[UIViewController alloc]init];
// 取出當前的導航控制器
UITabBarController *tabBarVc = (UITabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
//The view controller associated with the currently selected tab item
//當前選擇的導航控制器
UINavigationController *navC = (UINavigationController *)tabBarVc.selectedViewController;
[navC pushViewController:viewC animated:YES];複製代碼
(2)若是經過modal
出來的控制器而且用UITabBarController
很差使, 咱們會這樣獲取導航控制器:
UIViewController *viewC = [[UIViewController alloc]init];
//獲取最終的根控制器
UIViewController *rootC = [UIApplication sharedApplication].keyWindow.rootViewController;
//若是是modal出來的控制器,它就會經過presentedViewController拿到上一個控制器
UINavigationController *navC = (UINavigationController *)rootC.presentedViewController;
[navC pushViewController:viewC animated:YES];複製代碼
在開發中系統的leftBarButtonItem
不是咱們想要的, 若是咱們修改了leftBarButtonItem
那麼系統自帶的側滑返回功能就很差使了!
//設置代理 self.interactivePopGestureRecognizer.delegate = self; #pragma mark -//實現代理方法:return YES :手勢有效, NO :手勢無效 - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { //當導航控制器的子控制器個數 大於1 手勢纔有效 return self.childViewControllers.count > 1; } 複製代碼
咱們以前對Bounds
理解就是以本身的左上角爲座標原點, 也就是說Bounds
的x
值y
值是0
, 可是Bounds
的x
值y
值有多是正數也多是負數, 不必定是0
那麼Bounds
真正是什麼意思呢 ?
Bounds
: 是以本身內容
的左上角爲座標原點, 計算出本身的位置和大小Frame
: 是以父類內容
的左上角爲座標原點, 計算出本身的位置和大小 那什麼是內容
呢 ? 首先內容
是抽象的, 一個控件不只僅只有一層矩形框的, 他有不少圖層
的, 這個內容
其實就能夠抽象成一個控件的內部圖層
內容
:就是內部的東西, 它的子控件也屬於內容
,也就是說修改了Buonds
子控件的位置也會跟着改變
上圖藍色和綠色是屬於一個控件, 只不過藍色是控件自己, 綠色是控件的內容
, 咱們改變這個控件的Bounds
的x
值y
值爲-20
, 內容位置改變, 控件自己位置不變!
上圖是一個蘋果官方的一個枚舉, 咱們主要是看<<
的用處(它是C
語言中的位運算左移
), 若是在枚舉中只要<<
那它的含義就是能夠經過|
進行組合使用
:
//隨便添加一個UITextField
UITextField *field = [UITextField new];
//能夠經過 | 組合使用UIControlEventEditingDidBegin, UIControlEventValueChanged,UIControlEventEditingDidEnd
[field addTarget:self action:@selector(textFieldDidChanged) forControlEvents:UIControlEventEditingDidBegin | UIControlEventValueChanged | UIControlEventEditingDidEnd];
[self.view addSubview:field];複製代碼
若是枚舉沒有<<
就不能組合使用, 那它有什麼規律呢1 << n 表明:2的n次方
:
//1 << 16 表明:2的16次方
UIControlEventEditingDidBegin = 1 << 16,
//1 << 17 表明:2的17次方
UIControlEventEditingChanged = 1 << 17,
//1 << 18 表明:2的18次方
UIControlEventEditingDidEnd = 1 << 18,
//1 << 19 表明:2的19次方
UIControlEventEditingDidEndOnExit = 1 << 19,複製代碼
原來這樣的枚舉能夠組合使用, 那蘋果官方是怎麼知道咱們多個條件組合使用了呢 ?
NSUInteger controlEvents = UIControlEventEditingDidBegin | UIControlEventValueChanged | UIControlEventEditingDidEnd;
/**
//經過 & 符號來判斷是否包含:
UIControlEventEditingDidBegin,
UIControlEventValueChanged,
UIControlEventEditingDidEnd
*/
if (controlEvents & UIControlEventEditingDidBegin) {
NSLog(@"UIControlEventEditingDidBegin");
}else if (controlEvents & UIControlEventValueChanged) {
NSLog(@"UIControlEventValueChanged");
}else if (controlEvents & UIControlEventEditingDidEnd) {
NSLog(@"UIControlEventEditingDidEnd");
}複製代碼
經過以上方法就能判斷組合的狀態, 在開發中這個<<
意義很大的, 若是多個條件中, 任何一個條件知足咱們也可用帶<<
的枚舉給外界組合使用, 就像蘋果官方添加<<
使用是同樣的!
下圖咱們能夠看出來, 若是經過xib
加載出來的view
尺寸是不正確的, 在xib
中這個view
無論你怎麼設置都是治標不治本,咱們會在layoutSubviews
經過本身的寬度來計算子控件的尺寸!
//在這裏拿出的寬度是不正確的
- (void)awakeFromNib {}
//對尺寸計算咱們通常拿到這個方法中計算(拿到本身寬度計算子控件的尺寸)
- (void)layoutSubviews {
[super layoutSubviews];
//在這裏拿到本身的寬度是正確的
}複製代碼
那咱們也會想到, 若是控制器的view
也是xib
建立的, 咱們該怎麼辦 ? 其實無論控制器是在哪裏建立的, 咱們只要只在viewDidLayoutSubviews
方法中拿到控制器尺寸來計算子控件尺寸都是正確的, 因此說建議你們之後在viewDidLayoutSubviews
計算尺寸:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
//在這裏計算尺寸
}複製代碼
喜歡的小夥伴請點贊一下吧!若是有不足的地方,請你們及時幫忙糾正與補充,順便談談你的建議! 原文閱讀