Objective-C

NSString特性分析学习

Runtime系列1--从一个崩溃谈起

Runtime系列2--Method Swizzling

Foundation

Runtime

  • objc_msgSend

metaclass

  • Method Swizzling

当使用Method Swizzling时,如下代码中调用[self swizzed_method]相当于调用替换之前的[self method]

- (void)swizzed_method {
  [self swizzed_method];
}

Objective-C中集合类簇实际对应的对象类型。

对应的类簇
NSArray __NSArrayI
NSMutableArray __NSArrayM
NSDictionary __NSDictionaryI
NSMutableDictionary __NSDictionaryM

Equality

一个isEqual的判断示例:

- (BOOL)isEqual:(id)object {
  if (self == object) {
    return YES;
  }
  if (![object isKindOfClass:[NSArray class]]) {
    return NO;
  }
  return [self isEqualToArray:(NSArray *)object];
}
  • isEqual的判定结果与hash无关;

  • 对于NSArray对象,只要其子项满足isEqualToStringisEqualToDictionary等值比较,isEqual返回YES;同时NSArraycontainsObject:(id)object判断的结果由与objectisEqual的返回值决定;

  • 对于NSMutableArray对象,调用removeObject:(id)object,一旦子项中的对象与objectisEqual返回YES,该子项将被移除。

由于字符串驻留优化技术, 所有静态定义的不可变字符串对象 ,如果字符串表意相同,那么这些对象都指向同一个驻留字符串值,其类型为__NSCFConstantString

// 静态定义
NSString *a = @"Hello";
NSString *b = @"Hello";
BOOL wtf = (a == b); // YES
// 非静态定义
NSString *c = [NSString stringWithFormat:@"Hello"];
BOOL ass = (a == c); // NO

泛型

定义

泛型可用于制定容器中对象的类型:

NSArray<NSString *> *strings = @[@"sun", @"yuan"];
NSDictionary<NSString *, NSNumber *> *mapping = @{@"a": @1, @"b": @2};

协变性和逆变性(似乎只能在自定义泛型中使用)

不指定类型的容器可以喝任意泛型类型转化,但指定泛型类型之后,两个不同类型之间不能强转,需要通过__covariant,__contravariant修饰;

  • __covariant - 协变性,子类型可以强转到父类型(里氏替换原则)eg: NSArray <NSString *> 类型的对象赋值给 NSArray

  • __contravariant - 逆变性,父类型可以强转到子类型(WTF?)eg:将一个NSArray 的对象赋值给NSArray<NSNumber > * 对象

类型检查

__kindof相对于id更加具体的制定了对象的类型:

@property (nonatomic, readonly, copy) NSArray<__kindof UIView *> *subviews;

在调用时也不需要强转类型,同时也不会有编译警告:

UIButton *button = [view.subviews lastObject];

isKindOfClass && isMemberOfClass

  • isMemberOfClass 判断是否是某个类的成员;

  • isKindOfClass 判断是否是某个类或其子类的成员;

API Reference

修改UIStatusBarStyle

IOS 7 OR LATER

  • info.plist 设置UIViewControllerBasedStatusBarAppearance为YES;

  • 在UIViewController中重写preferredStatusBarStyle,并在需要改变UIStatusBarStyle时调用[self setNeedsStatusBarAppearanceUpdate];

  • 在UINavigationController重写preferredStatusBarStyle方法,返回topViewController的UIStatusBarStyle。

(UIStatusBarStyle)preferredStatusBarStyle {

  UIViewController *viewController = self.topViewController;

  return [viewController preferredStatusBarStyle];

}
  • info.plist 设置UIViewControllerBasedStatusBarAppearance为NO;

  • 直接调用[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault修改statusBarStyle。

UINavigationBar属性

  • edgesForExtendedLayout设置ViewController延伸的枚举,默认UIRectEdgeAll,ViewController视图会延伸到UINavigationBarUITabBarUIRectEdgeNone则不会延伸。

  • automaticallyAdjustsScrollViewInsets默认YES,视图初始状态从UINavigationBar下面开始,从UITabBar顶部结束,当edgesForExtendedLayout属性设置为UIRectEdgeAll时,视图可以穿透UINavigationBarUITabBar,作用相当于自动设置了contentInsets。

  • extendedLayoutIncludesOpaqueBars属性是对edgesForExtendedLayout的补充,当 NavigationBar、TabBar、TooBar 不透明 时 ,设置为YES,视图任将扩展到不透明区域,设置为NO,则不会扩展到不透明区域。

  • modalPresentationCapturesStatusBarAppearance控制在present一个viewController时,是否由被present的viewController控制statusBarStyle,默认为NO。

自定义UINavigationBar样式

  • 设置阴影线条image

    // 隐藏阴影黑线
    [self.navigationController.navigationBar setShadowImage:[[UIImage alloc] init]];
    // 显示阴影黑线
    [self.navigationController.navigationBar setShadowImage:nil];
    
  • 设置背景图片

    [self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
    

Tips

宏与静态常量

定义常量

.h //
extern NSString * const kConstExternFoo;
.m //
NSString * const kConstExternFoo = @"ConstExternFoo";

static全局变量 & static局部变量

  • 局部变量:static修饰的局部变量延长了该变量的生命周期,任然只能局部访问,但当再次调用该局部区域(函数)时,该变量存储的是上次调用该局部区域的值,相当于只能"局部访问"的全局变量;

  • 全局变量:static修饰的全局变量限制了该变量只能在该文件中访问。

results matching ""

    No results matching ""