iOS tips 9

Class居然是有两个东西组成的,以及一个过气UIAlertview的BUG

2016-04-03 | 阅读

OC中的Class.

Class有两个部分,一个是普通Class,一个是metaClass.类的实例对象的isa指向该类,该类的isa指向该类的metaClass.所以指针指向类似上图,也就是说,类的实例方法记录在class中,而类方法记录在meta-class中.

所以方法的寻找路径是分两条的,类方法一直走metaClass,而成员方法走Class这条继承路线.

隐藏导航栏下的一条线

self.navigationController.navigationBar.shadowImage = [[UIImage alloc] init];

Xcode调试

lldb 常用命令 
po(print-object)+ 对象
p(print)+ 基本数据类型 int之类
bt 打印最后一次调用堆栈
expr 动态修改变量

NSString不能释放

通常以字面量声明的字符串,会放在全局变量区,不会被释放.

initWithStringstringWithString 都是常量,stringWithFormat形式的是放在堆栈里面的,可以进行释放的.

UI测试

创建一个UITest的Target,然后查看Test文件,其中XCUIApplication就是当前应用,在setup中启动应用lauch.在testExample具体的一个测试用例中,来编写测试的操作流程.在左下角,有一个红点,将光标放在testExample中,小红点会变得可点,通过这个小红点,可以直接录制操作,方便测试.

关于泛型

OC中提供了泛型:ObjectType,

@interface Stack<ObjectType> : NSObject
- (void)pushObject:(ObjectType)object;
- (ObjectType)popObject;
@property (nonatomic, readonly) NSArray<ObjectType> *allObjects;
@end

// 只接受 NSNumber * 的泛型
@interface Stack<ObjectType: NSNumber *> : NSObject
// 只接受满足 NSCopying 协议的泛型
@interface Stack<ObjectType: id<NSCopying>> : NSObject

不指定泛型类型的 Stack 可以和任意泛型类型转化,但指定了泛型类型后,两个不同类型间是不可以强转的,假如你希望主动控制转化关系,就需要使用泛型的协变性和逆变性修饰符了:

  • __covariant - 协变性,子类型可以强转到父类型(里氏替换原则)
  • __contravariant - 逆变性,父类型可以强转到子类型(WTF?)

修饰符 __kindof:

- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;
@property (nonatomic, readonly, copy) NSArray<__kindof UIView *> *subviews;

对于UIAlertview后弹出Window界面的输入键盘显示异常

发现了iOS上的一个过气BUG

当在一个键盘的隐藏动画完成前,弹出了一个UIAlertView时,在点击这个UIAlertView的按键后,进行了界面跳转,或者弹出了新的UIAlertview之类的,都会异常显示之前的键盘.

这个BUG的表现是,键盘所在的Window在显示是,windowLevel是1000000,而在隐藏时是0.当点击UIAlertView的按键后,这个键盘Window的windowLevel又变成了1000000了.那苹果这样做的原因是,AlertView的level只有2001,如果当前界面上有输入键盘,弹出的Alertview是无法遮住键盘的,所以,弹出时,会先检测一下当前是否有输入键盘,如果有键盘,就将键盘所在的window等级降低,而在完成点击后,再将键盘window的等级恢复.而这里我们的键盘动画尚未完成,导致UIAlertView记录了当前键盘window的状态,然后在自己结束时,重置了键盘window,却是异常显示了键盘.

解决方法,有两个,一个是使用新的UIAlertController,一个是延迟弹出UIAlertView,确保键盘动画完成.

_cmd

方法中使用_cmd,表示当前方法的selector.

NSLog(@"Current method: %@ %@",[self class],NSStringFromSelector(_cmd));

显示宏最终的内容

在Xcode中,选择 Product - > Perform Action -> Preprocess "xxx.m",就可以对这个文件进行预处理,展开所有的宏,也就可以看到真正完整的宏定义了.