属性修饰符 atomic & nonatomic

目前为止, 在苹果的官方文档上, 已经找不到对这两个属性修饰符的介绍, 网络上对其细节说明也是千奇百怪, 各执一词.

atomic(原子性)

  1. 顾名思义, 表示原子性, 这个概念其实并不新鲜, 早在linux系统下编程本身也是有这个东西的, 所谓原子, 就是不可再化分, 已经是最小的操作单位(所谓操作指的是对内存的读写), 网上很多地方都在讨论 Objective-C 下的 atomic 不安全, 不能保证数据的并发性, 实际上有一点误导了大家, 认为 atomic 本身是不安全的. 实际上, 并非 atomic 不安全, 而是网上一些说法有问题.

  2. atomic关键字会保证属性生成的成员变量在同一时间只能有一条线程对其进行读/写操作, 本质上是在 setter 方法和 getter 方法中添加了一个.

// @property(retain) UITextField *userName;
// 系统生成的代码如下:

- (UILabel *) titleLabel {
    UITextField *label = nil;
    @synchronized(self) {
        label = [[_titleLabel retain] autorelease];
    }
    return label;
}

- (void) setTitleLabel:(UILabel *)titleLabel {
    @synchronized(self) {
      [_titleLabel release];
      _titleLabel = [titleLabel retain];
    }
}
  1. 这里需要说明的是 atomic 仅仅是保证了 setter 方法和 getter 方法的完整性, 确保任何线程在获取数据的时候, 都会得到一个完整的数据.

nonatomic(非原子性)

  1. 没有保证 getter 和 setter 存取方法的线程安全.
- (void)setCurrentImage:(UIImage *)currentImage
{
    if (_currentImage != currentImage) {
        [_currentImage release];
        _currentImage = [currentImage retain];
    }
}

- (UIImage *)currentImage
{
    return _currentImage;
}

Others

  1. atomic要比nonatomic慢大约20倍. 一般如果条件允许, 我们可以让服务器来进行加锁操作.
  2. 虽然 atomic 保证了 setter & getter 的读写安全, 但不能保证其它方法造成的线程安全问题, 比如NSArry对象调用addObject:方法在 atomic 下是没有线程安全保证的.

使用UIView实现视图的转场动画

1. 声明动画块(animation Block)

[UIView beginAnimations:@"View Flip" content:NULL];

beginAnimations: content:方法接受两个参数,第一个是动画块标题,只有在更直接地使用Core Animation(即用于实现动画的框架)时才会用到这个标题,对于上面的实例,可以使用nil替换。第二个参数是一个指针,指向关联到这个动画快的对象(或者任何C语言数据类型)。这里使用空数据(NULL或者nil),因为没有必要指定对象。

2. 指明动画的持续时间

[UIView setAnimationDuration:0.25];

类方法setAnimationDuration:设定了动画的持续时间,它告诉了 UIView 动画应该运行多长时间(以秒为单位)。

3. 设置动画曲线(animation curve)

[UIView setAnimationCure:UIViewAnimationCureEaseInOut];

这决定了动画的运行速度。默认情况下,动画曲线是一条线性曲线,使动画匀速运行。示例中的UIViewAnimationCureEaseInOut指定了“慢速开始,中间加速,慢慢停止”。这样动画看起来会更加自然,不那么呆板。

4. 指定要使用的转场动画类型

[UIView setAnimationTransition:UIViewAnimationFlipFromRight forView:xxxView cache:YES];

在写此篇博客时,iOS提供了5种视图转场类型:

typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
    UIViewAnimationTransitionNone,  //一个视图突然变成另一个视图(若需要此种效果,根本无需创建一个动画快)
    UIViewAnimationTransitionFlipFromLeft,  // 左侧翻入
    UIViewAnimationTransitionFlipFromRight,  // 右侧翻入
    UIViewAnimationTransitionCurlUp,  // 向上卷起
    UIViewAnimationTransitionCurlDown,  // 向下卷起
};

cache会在动画开始生成一个快照,并在动画执行过程的每一步使用这个快照(对这个快照做动画变换),而不是重新绘制视图。应该始终对动画进行缓存(也就是说此参数应该始终传 YES),除非视图外观在动画执行过程中需要改变。

5. 调用 commitAnimations 方法

typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
    [UIView commitAnimations];
};

在第一步创建动画块开始一直到调用commitAnimations,中间所有的动作都会被制成动画。
由于 Cocoa Touch 在后台使用了 Core Animation(说人话其实就是底层封装了 Core Animation),所以我们能够使用极少的代码制作出非常复杂而精美的动画。