一句话笔记,某段时间内遇到或看到的某个可记录的点。 2017-04-05
- <UITableViewCellContentView:.width == 0> 约束冲突
- iOS 可能用到的
__attribute__
,很是妙
一、<UITableViewCellContentView:.width == 0> 约束冲突
出现这个约束冲突是在UITableViewCell 中的:
约束提示对于这个问题感觉有点奇怪,在网上一搜 iOS10 正式版不能计算出正确高度 #242 就更加奇怪了, 里面的推测各种,情景和答案也各种。
而我这边在产生约束警告的那个 Cell 中, 这边改了一个 numberOfLines 的值,就产生了冲突。
// 正常的,不会有冲突
_addressLabel.numberOfLines = 1;
// 一改,冲突就来了
_addressLabel.numberOfLines = 0;
对 numberOfLines
好好看了下
// this determines the number of lines to draw and what to do when sizeToFit is called. default value is 1 (single line). A value of 0 means no limit
// if the height of the text reaches the # of lines or the height of the view is less than the # of lines allowed, the text will be
// truncated using the line break mode.
简单的说,它只是决定行数啊,默认是1 , 0 是没有限制行数,这样貌似和约束不会有直接的关联啊?
最后,看到了 sunny 的这个回复, 以及 @greedbell 在 iOS10 正式版不能计算出正确高度 #242 的回复后,试了下再添加一层包装 View 之后就好了。
sunny 的这个回复然后在 cell 中再添加了一个 backView ,然后就解决了这个冲突。
[self.backView mas_updateConstraints:^(MASConstraintMaker *make) {
make.edges.mas_equalTo(UIEdgeInsetsZero);
}];
同时很好奇,为什么会有 UITableViewCellContentView.width = 0
的约束? 可以好好想想,这是如何保证 contentView 更好的工作呢?
二、 iOS 可能用到的 attribute
最近听小伙伴说到 __attribute__
一些妙用,然后发现自己不太熟悉,于是去了解了下关于这块的点,虽说不怎么推荐用它,但感觉至少还是得啥意思嘛。下面笔记了下几个可能用到的:
- 该类或方法、属性什么版本可用的
- 该类或方法、属性废弃,不可用
- 当作用域结束时,及时cleanup
- 该方法子类必须调用父类
- 该对象替换名字,可做模糊用
- 该类可以用另一个名字
- 该类不可以子类化
2-1、该类或方法、属性什么版本可用的
__attribute__((availability(ios,introduced=2_0,deprecated=9_0,obsoleted=10_0)));
- introduced:版本号类型 === 开始的版本
- deprecated:版本号类型 === 废弃的版本
- obsoleted:版本号类型 === 移除的版本
- unavailable:平台类型 === 标识那些平台不可用 (ios、macos、tvos、watchos)
- message: 文本类型 === 过时时提示的文字
- replacement:文本类型 === 废弃替换的文本
当然系统其实为我们推荐了用的宏:
-
NS_AVAILABLE_IOS
在什么版本以上可用
@property(nonatomic,assign) UIAlertViewStyle alertViewStyle NS_AVAILABLE_IOS(5_0);
-
NS_DEPRECATED_IOS
在什么区间的版本可以用
- (void)alertViewCancel:(UIAlertView *)alertView NS_DEPRECATED_IOS(2_0, 9_0);
>**2-2、该类或方法、属性废弃,不可用**
attribute((deprecated("","")))
* 第一个参数: 过时的提示语
* 第二个参数 : 让编译器替换的内容
举例:
-
(void)testMethod1 attribute((deprecated("此方法废弃请替换","testMethod2")));
-
(void)testMethod2;
![使用 testMethod1 的提示](https://img.haomeiwen.com/i784630/30487ac2d8560b2f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
另外系统为我们提供的则是:`NS_DEPRECATED_IOS`, 而且考虑到了版本的问题:
- (CGSize)sizeWithFont:(UIFont *)font NS_DEPRECATED_IOS(2_0, 7_0, "Use -sizeWithAttributes:") __TVOS_PROHIBITED;
######另外注意: 不可用 —— `NS_UNAVAILABLE`:
define UNAVAILABLE_ATTRIBUTE attribute((unavailable))
- (instancetype)init NS_UNAVAILABLE
{
return nil;
}
>**2-3、cleanup**
作用:离开作用域之后执行指定的方法。
- (void)testStr {
__strong NSString *string attribute((cleanup(strCleanUp))) = @"testString";
NSLog(@"%@",string);
}
static void strCleanUp(__strong NSString *string){
NSLog(@"cleanUp call %@",string);
}
点击事件也可以
- (void)testBlock {
__strong void(^block)(void) attribute((cleanup(blockCleanUp), unused)) = ^{
NSLog(@"本身需要做的的事情");
};
}
static void blockCleanUp(__strong void(^block)(void)){
NSLog(@"最后想做的事情");
// 最后要做的事情
(block)();
}
此时就想到当时 [孙源直播时的那个提问](http://www.jianshu.com/p/f2c5d894be6e),另辟方式的让 block 的答案,瞬间稍微理解了点当时的第六种方法。
>** 2-4、该方法子类必须调用父类**
允许一个子类覆盖父类中的一个特定方法,但期望覆盖方法也会调用父类中的被覆盖的方法。
此时就需要提供一个属性来指定一个方法需要在子类中的覆盖方法中调用super。
`__attribute__((objc_requires_super))`这个属性放在方法的尾部。
- (void)testMethod2 attribute((objc_requires_super));
![提示需要调用父类方法](https://img.haomeiwen.com/i784630/a0f44ccb8dd982f5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
@implementation TestSonAttribute
- (void)testMethod2 {
[super testMethod2];
}
@end
>** 2-5、该对象替换名字,可做模糊用**
attribute((objc_runtime_name("TestNewName")))
@interface TestAttribute : NSObject
TestAttribute *test = [[TestAttribute alloc] init];
NSLog(@"test == %@",[test class]);
正常情况下:
test == TestAttribute
但是在 @protocol和 @interface声明之前声明了` __attribute__((objc_runtime_name("TestNewName")))` 之后 就变成这样子了:
test == TestNewName
想想有时为了混淆,防止反编译会有作用的。
>** 2-6、该类可以用另一个名字**
有时我们会遇到某个页面改版的需求,也许此时要重新写过整个页面,此时重新写过一个类后,会犹豫要不要删除以前的那个类,特别是之前那个类是以前的同事写的后,时间又急,此时用到这个东东也许会有帮助。
@compatibility_alias
import <Foundation/Foundation.h>
@interface TestAttribute : NSObject
- (void)testMethod;
@end
@compatibility_alias TestAgainAttribute TestAttribute;
使用后:
TestAttribute *test = [[TestAttribute alloc] init];
NSLog(@"test == %@",[test class]);
TestAgainAttribute *testAgain = [[TestAgainAttribute alloc] init];
NSLog(@"testAgain == %@",[testAgain class]);
看打印:
test == TestAttribute
testAgain == TestAttribute
同时也是调用其方法:
[testAgain testMethod];
暂时还没具体用过,虽说感觉很厉害的,但是不推荐用,否则有时没注意到这个,遇到 Bug 之后找不到出处的。
>** 2-7、该类不可以子类化**
在 @protocol和 @interface声明之前声明`__attribute__((objc_subclassing_restricted))`
attribute((objc_subclassing_restricted))
@interface TestAttribute : NSObject
然后子类就直接运行不过了。。。
![子类直接报错](https://img.haomeiwen.com/i784630/6fc74fecc17c374a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
想想有时,某些类有些特殊要求的情况下,这样提示还是能避免很多错误的。
> 总的说来,对于` __attribute__` 也许我们直接用的会比较少,但是还是要了解的。另外再想想对于我们自己项目中,能否也写出一些 `NS_AVAILABLE_IOS`、`NS_DEPRECATED_IOS` 的宏呢,毕竟确实随着项目的迭代会出现一些需要放弃的方法,以及需要优化替代的方法。
#####备注参考:
https://github.com/forkingdog/UITableView-FDTemplateLayoutCell/issues/242
http://blog.sunnyxx.com/2016/05/14/clang-attributes/
http://nshipster.com/__attribute__/
网友评论