源码

首页 » 归档 » 源码 » iOS 开发中你是否遇到这些经验问题(二)-ios学习从入门到精通尽在姬长信

iOS 开发中你是否遇到这些经验问题(二)-ios学习从入门到精通尽在姬长信

分享最热门的ios资讯

img-600.jpg

授权转载,作者:判若两人丶Github

前言:

在上一篇文章中我相信资助了很多的小伙伴, 那么在这篇文章希望还能资助到你!

1.在Block中一起使用weakSelf与strongSelf的含义

我们都会声明一个弱引用在block中使用, 目的就是防止循环引用, 那么weakSelf与strongSelf一起使用目的是什么呢?首先先界说2个宏:

#define LRWeakSelf(type)  __weak typeof(type) weak##type = type;

#define LRStrongSelf(type)  __strong typeof(type) type = weak##type;

我们创建一个shop而且在shop.myBlock代码块中使用弱引用LRWeakSelf(shop);

LRShop *shop = [[LRShop alloc]init];
shop.string = @"welcome to our company";
//弱引用
LRWeakSelf(shop);
shop.myBlock = ^{
   NSLog(@"%@",weakshop.string);
};
shop.myBlock();

LRWeakSelf(shop);与LRStrongSelf(shop);一起使用

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也销毁了, 看起来是没什么区别:

2353624-c1696fcf48988ab8.png

仅仅使用LRWeakSelf(shop);而且在myBlock中增加一个延迟3秒在输出就会出现问题, 虽然工具销毁了, 输出的值却是null

//弱引用
 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();

2353624-0a71a7b33f4010c4.png

如果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);一起使用的好处, 不只能打印出我想要的值,而且也不会造成循环引用 , 在开发中这两个要领可以凭据实际情况进行使用!

2.使用UIAppearance注意的问题

如果不熟悉可以点击了解, UIAppearance它的目的就是设置全局显示样式, 我们知道只要带UI_APPEARANCE_SELECTOR这个宏, 我们就可以使用UIAppearance比如这样设置:

1471858986368283.png

我们知道UIBarButtonItem它是有状态的比如UIControlStateNormal或者是UIControlStateDisabled状态

如果通过UIAppearance设置UIControlStateDisabled状态下的颜色是不好使的, 因为使用appearance会有一些延迟, 导致在差别状态下的颜色不好使, 我们只要强制刷面目目样一下就可以了:

// 刷面目目样
[self.navigationController.navigationBar layoutIfNeeded];

所以以后使用UIAppearance在某个状态下设置颜色,字体等不好使, 只需要在对应的位置用layoutIfNeeded刷面目目样一下就可以了!

3. UITextField使用注意

先贴一个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;
}

但是这个署理要领监听会有问题如下图:

1471859055522022.png

1471859061255358.png

所以我们要监听UITextField的文字改变不建议使用署理, 我们用addTarget监听文字

[textField addTarget:self action:@selector(textEditingChanged) forControlEvents:UIControlEventEditingChanged];

4.UITextView添加占位文字的正确要领

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要领:

QQ截图20160822174533.png

封装好的自界说TextView可以直接使用:Demo下载

5.自界说控件里如何拿到导航控制器进行页面跳转?

(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];

6.修改了leftBarButtonItem如何恢复系统侧滑返回功能

在开发中系统的leftBarButtonItem不是我们想要的, 如果我们修改了leftBarButtonItem那么系统自带的侧滑返回功能就不好使了!

2353624-d88551fa660a2b9c.png

//设置署理
self.interactivePopGestureRecognizer.delegate = self;
#pragma mark - 
//实现署理要领:return YES :手势有效, NO :手势无效
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    //当导航控制器的子控制器个数 大于1 手势才有效
    return self.childViewControllers.count > 1;
}

7.重面目目样认识Bounds

我们之前对Bounds理解就是以自己的左上角为坐标原点, 也就是说Bounds的x值y值是0, 但是Bounds的x值y值有可能是正数也可能是负数, 纷歧定是0那么Bounds真正是什么意思呢 ?

Bounds: 是以自己内容的左上角为坐标原点, 计算出自己的位置和大小

Frame: 是以父类内容的左上角为坐标原点, 计算出自己的位置和大小

那什么是内容呢 ? 首先内容是抽象的, 一个控件不仅仅只有一层矩形框的, 他有很多图层的, 这个内容其实就可以抽象成一个控件的内部图层

内容:就是内部的乳, 它的子控件也属于内容,也就是说修改了Buonds子控件的位置也会随着改变

2353624-3e44a071a098a8a7.png

上图蓝色和绿色是属于一个控件, 只不过蓝色是控件自己, 绿色是控件的内容, 我们改变这个控件的Bounds的x值y值为-20, 内容位置改变, 控件自己位置不变!

8.跟枚举相关的一些符号的含义

1471859212336226.png

上图是一个苹果官方的一个枚举, 我们主要是看<<的用处, 如果在枚举中只要<<那它的含义就是可以通过|进行组合使用:

//随便添加一个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");
    }

通过以上要领就能判断组合的状态, 在开发中这个<<意义很大的, 如果多个条件中, 任何一个条件满足我们也可用带<<的枚举给外界组合使用, 就像苹果官方添加<<使用是一样的!

9.Xib相关的一些问题

下图我们可以看出来, 如果通过xib加载出来的view尺寸是不正确的, 在xib中这个view不管你怎么设置都是治标不治本,我们会在layoutSubviews通过自己的宽度来计算子控件的尺寸!

//在这里拿出的宽度是不正确的
- (void)awakeFromNib {}
//对尺寸计算我们一般拿到这个要领中计算(拿到自己宽度计算子控件的尺寸)
- (void)layoutSubviews {
    [super layoutSubviews];
    //在这里拿到自己的宽度是正确的
}

2353624-7c73503f8a1601d0.png

那我们也会想到, 如果控制器的view也是xib创建的, 我们该怎么办 ? 其实不管控制器是在哪里创建的, 我们只要只在viewDidLayoutSubviews要领中拿到控制器尺寸来计算子控件尺寸都是正确的, 所以说建议大家以后在viewDidLayoutSubviews计算尺寸:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    //在这里计算尺寸
}

喜欢的小伙伴请点赞一下吧!如果有不足的地方,请大家及时帮助纠正与增补,顺便谈谈你的建议!

用意志战胜身体的惰性!

(0)

本文由 姬長信 创作,文章地址:https://blog.isoyu.com/archives/1070.html
采用知识共享署名4.0 国际许可协议进行许可。除注明转载/出处外,均为本站原创或翻译,转载前请务必署名。最后编辑时间为:8月 23, 2016 at 07:59 上午

关键词:

热评文章

发表评论

[必填]

看不清?

提交后请等待三秒以免造成未提交成功和重复