在上一篇文章中我相信帮助了不少的小伙伴, 那么在这篇文章但愿还能帮助到你!
相关文章:
iOS开发中你是否遇到这些经验问题(一) ios
咱们都会声明一个弱引用在block
中使用, 目的就是防止循环引用, 那么weakSelf
与strongSelf
一块儿使用目的是什么呢? 首先先定义2个宏:api
#define LRWeakSelf(type) __weak typeof(type) weak##type = type; #define LRStrongSelf(type) __strong typeof(type) type = weak##type;
咱们建立一个shop
而且在shop.myBlock
代码块中使用弱引用LRWeakSelf(shop);
app
LRShop *shop = [[LRShop alloc]init];
shop.string = @"welcome to our company"; //弱引用 LRWeakSelf(shop); shop.myBlock = ^{ NSLog(@"%@",weakshop.string); }; shop.myBlock();
LRWeakSelf(shop);
与LRStrongSelf(shop);
一块儿使用ide
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
也销毁了, 看起来是没什么区别:字体
仅仅使用LRWeakSelf(shop);
而且在myBlock
中增长一个延迟3秒在输出就会出现问题, 虽然对象销毁了, 输出的值倒是null
ui
//弱引用 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
有值,对象也销毁了, 我就再也不截图给你们看了!atom
//弱引用 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);
一块儿使用的好处, 不但能打印出我想要的值,并且也不会形成循环引用 , 在开发中这两个方法能够根据实际状况进行使用!spa
若是不熟悉能够点击了解, UIAppearance
它的目的就是设置全局显示样式, 咱们知道只要带UI_APPEARANCE_SELECTOR
这个宏, 咱们就可使用UIAppearance
好比这样设置:scala
咱们知道UIBarButtonItem
它是有状态的好比UIControlStateNormal
或者是UIControlStateDisabled
状态
若是经过UIAppearance
设置UIControlStateDisabled
状态下的颜色是很差使的, 由于使用appearance
会有一些延迟, 致使在不一样状态下的颜色很差使, 咱们只要强制刷新一下就能够了:3d
// 刷新 [self.navigationController.navigationBar layoutIfNeeded];
因此之后使用UIAppearance
在某个状态下设置颜色,字体等很差使, 只须要在对应的位置用layoutIfNeeded
刷新一下就能够了!
先贴一个UITextField
如何设置占位文字的颜色, 若是不先设置占位文字, 占位文字的颜色是无论用的:
//先设置占位文字 textField.placeholder = @"设置了占位文字内容之后, 才能设置占位文字的颜色"; //占位文字颜色 [textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"];
你们监听UITextField
文字的改变会用到代理:
#pragma mark - <UITextFieldDelegate> - (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
方法:
(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 - <UIGestureRecognizerDelegate> //实现代理方法: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]; //在这里计算尺寸 }