目录[-]html
iOS中有两个属性non-atomic和atomic,前者是非原子性的(线程不安全),后者是原子性的(线程安全),通常状况下不会去重写它们,但某些时候确实有重写的需求。ios
那些int、float之类的类型,你重写想出错都很难。可是强引用类型(retain)就须要注意了。安全
简单的说一下非原子性的nonatomic实现,方式以下:并发
1
2
3
4
5
6
7
8
9
10
11
12
13
|
- (
void
)setCurrentImage:(UIImage *)currentImage
{
if
(_currentImage != currentImage) {
[_currentImage release];
_currentImage = [currentImage retain];
// do something
}
}
- (UIImage *)currentImage
{
return
_currentImage;
}
|
关于atomic的实现最开始的方式以下:函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
- (
void
)setCurrentImage:(UIImage *)currentImage
{
@synchronized(self) {
if
(_currentImage != currentImage) {
[_currentImage release];
_currentImage = [currentImage retain];
// do something
}
}
}
- (UIImage *)currentImage
{
@synchronized(self) {
return
_currentImage;
}
}
|
具体讲就是retain的同步版本,原本觉得没问题,但在用GCD重绘currentImage的过程当中,有时候currentImage切换太频繁。在完成以前就把以前的currentImage释放了,程序仍然会崩溃。还须要在resize过程当中增长retain和release操做,代码以下:ui
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
// For multithreading
[self retain];
BOOL
drawTransposed;
CGAffineTransform transform = CGAffineTransformIdentity;
// In iOS 5 the image is already correctly rotated. See Eran Sandler's
// addition here: http://eran.sandler.co.il/2011/11/07/uiimage-in-ios-5-orientation-and-resize/
if
([[[UIDevice currentDevice]systemVersion]floatValue] >= 5.0) {
drawTransposed = NO;
}
else
{
switch
(self.imageOrientation) {
case
UIImageOrientationLeft:
case
UIImageOrientationLeftMirrored:
case
UIImageOrientationRight:
case
UIImageOrientationRightMirrored:
drawTransposed = YES;
break
;
default
:
drawTransposed = NO;
}
transform = [self transformForOrientation:newSize];
}
transform = [self transformForOrientation:newSize];
UIImage *image = [self resizedImage:newSize transform:transform drawTransposed:drawTransposed interpolationQuality:quality];
[self release];
return
image;
}
|
原始版本的resize函数以下:atom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality {
BOOL
drawTransposed;
CGAffineTransform transform = CGAffineTransformIdentity;
// In iOS 5 the image is already correctly rotated. See Eran Sandler's
// addition here: http://eran.sandler.co.il/2011/11/07/uiimage-in-ios-5-orientation-and-resize/
if
([[[UIDevice currentDevice]systemVersion]floatValue] >= 5.0) {
drawTransposed = NO;
}
else
{
switch
(self.imageOrientation) {
case
UIImageOrientationLeft:
case
UIImageOrientationLeftMirrored:
case
UIImageOrientationRight:
case
UIImageOrientationRightMirrored:
drawTransposed = YES;
break
;
default
:
drawTransposed = NO;
}
transform = [self transformForOrientation:newSize];
}
transform = [self transformForOrientation:newSize];
return
[self resizedImage:newSize transform:transform drawTransposed:drawTransposed interpolationQuality:quality];
}
|
可是以前在没有重写getter以前,用atomic的getter程序不会崩溃。因而我就想如今的getter和atomic本身实现的getter确定有区别。spa
最后,答案出现:在getter的return以前retain,再autorelease一次就能够了。getter函数就变成了这样:.net
1
2
3
4
5
6
7
|
- (UIImage *)currentImage
{
@synchronized(self) {
UIImage *image = [_currentImage retain];
return
[image autorelease];
}
}
|
这样能够确保currentImage在调用过程当中不会由于currentImage被释放或者改变,使它的retainCount次数变为0,再在调用时让程序直接崩溃。线程
在Memory and thread-safe custom property methods这篇文章中还提到了一种Objective-C的runtime解决方案。
Objective-C的runtime中实现了如下函数:
1
2
3
|
id <strong>objc_getProperty</strong>(id self, SEL _cmd,
ptrdiff_t
offset,
BOOL
atomic);
void
<strong>objc_setProperty</strong>(id self, SEL _cmd,
ptrdiff_t
offset, id newValue,
BOOL
atomic,
BOOL
shouldCopy);
void
<strong>objc_copyStruct</strong>(
void
*dest,
const
void
*src,
ptrdiff_t
size,
BOOL
atomic,
BOOL
hasStrong);
|
这几个函数被实现了,但没有被声名。若是要使用他们,必须本身声名。它们比用@synchronized实现的要快。由于它的实现方式与通常状况不一样,静态变量只在接收并发时才会锁住。
声名方式:
1
2
3
4
5
6
7
8
|
#define <strong>AtomicRetainedSetToFrom</strong>(dest, source) \
objc_setProperty(self, _cmd, (
ptrdiff_t
)(&dest) - (
ptrdiff_t
)(self), source, YES, NO)
#define <strong>AtomicCopiedSetToFrom</strong>(dest, source) \
objc_setProperty(self, _cmd, (
ptrdiff_t
)(&dest) - (
ptrdiff_t
)(self), source, YES, YES)
#define <strong>AtomicAutoreleasedGet</strong>(source) \
objc_getProperty(self, _cmd, (
ptrdiff_t
)(&source) - (
ptrdiff_t
)(self), YES)
#define <strong>AtomicStructToFrom</strong>(dest, source) \
objc_copyStruct(&dest, &source,
sizeof
(__typeof__(source)), YES, NO)
|
用这些宏定义,上面something的copy getter和setter方法将变成这样:
1
2
3
4
5
6
7
8
|
- (NSString *)someString
{
return
AtomicAutoreleasedGet(someString);
}
- (
void
)setSomeString:(NSString *)aString
{
AtomicCopiedSetToFrom(someString, aString);
}
|
someRect存取方法将变成这样:
1
2
3
4
5
6
7
8
9
10
|
- (NSRect)someRect
{
NSRect result;
AtomicStructToFrom(result, someRect);
return
result;
}
- (
void
)setSomeRect:(NSRect)aRect
{
AtomicStructToFrom(someRect, aRect);
}
|