/
pxSVGLayer.m
142 lines (129 loc) · 4.74 KB
/
pxSVGLayer.m
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//
// pxSVGLayer.m
// pxSVG
//
// Created by Yury Popov on 12 мая.
// Copyright (c) 2015 PhoeniX. All rights reserved.
//
#import "pxSVGLayer.h"
#import "pxSVGImage.h"
@interface pxSVGLayer ()
@property NSOperation *loadOperation;
@property NSOperation *parseOperation;
@property CGRect contentRect;
@end
@implementation pxSVGLayer
+ (NSOperationQueue*)loadQueue
{
static NSOperationQueue *lq;
if (!lq) {
lq = [NSOperationQueue new];
lq.name = @"pxSVG Load queue";
[lq setMaxConcurrentOperationCount:10];
}
return lq;
}
+ (NSOperationQueue*)parseQueue
{
static NSOperationQueue *pq;
if (!pq) {
pq = [NSOperationQueue new];
pq.name = @"pxSVG Parser queue";
[pq setMaxConcurrentOperationCount:10];
}
return pq;
}
- (void)dealloc
{
if (self.loadOperation) [self.loadOperation cancel];
if (self.parseOperation) [self.parseOperation cancel];
}
- (void)loadURL:(NSURL *)url
{
[self clean];
__weak pxSVGLayer *weakself = self;
__block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSURLResponse *resp;
NSError *err;
NSData *data;
data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadRevalidatingCacheData timeoutInterval:30] returningResponse:&resp error:&err];
if ([op isCancelled]) return;
NSString *str = data?[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]:nil;
NSBlockOperation *sync = [NSBlockOperation blockOperationWithBlock:^{
if ([op isCancelled]) return;
if (!weakself) return;
weakself.loadOperation = nil;
op = nil;
NSError *error = err;
if (!error && [resp isKindOfClass:[NSHTTPURLResponse class]] && (((NSHTTPURLResponse*)resp).statusCode != 200))
error = [NSError errorWithDomain:@"pxSVGLoader.httpStatus" code:((NSHTTPURLResponse*)resp).statusCode userInfo:nil];
if (!error && !str)
error = [NSError errorWithDomain:@"pxSVGLoader.emptyData" code:0 userInfo:nil];
if (error) return [weakself loadError:error];
[weakself loadString:str];
}];
[[NSOperationQueue mainQueue] addOperations:@[sync] waitUntilFinished:YES];
}];
op.name = url.absoluteString;
op.threadPriority = 0.1f;
[[self.class loadQueue] addOperation:self.loadOperation=op];
}
- (void)loadData:(NSData *)data
{
[self loadString:[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]];
}
- (void)loadString:(NSString *)string
{
[self clean];
__weak pxSVGLayer *weakself = self;
__block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
pxSVGImage *img = [pxSVGImage svgImageWithXML:string];
if ([op isCancelled]) return;
NSBlockOperation *sync = [NSBlockOperation blockOperationWithBlock:^{
if ([op isCancelled]) return;
if (!weakself) return;
weakself.parseOperation = nil;
op = nil;
if (!img) return [weakself loadError:[NSError errorWithDomain:@"pxSVGParser.parseError" code:0 userInfo:nil]];
[weakself loadImage:img];
}];
[[NSOperationQueue mainQueue] addOperations:@[sync] waitUntilFinished:YES];
}];
op.threadPriority = 0.1f;
[[self.class parseQueue] addOperation:self.parseOperation=op];
}
- (void)loadImage:(pxSVGImage*)image
{
[self clean];
__weak pxSVGLayer *weakself = self;
__block NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
CALayer *img = [image makeLayer];
if ([op isCancelled]) return;
NSBlockOperation *sync = [NSBlockOperation blockOperationWithBlock:^{
if ([op isCancelled]) return;
if (!weakself) return;
[weakself addSublayer:img];
weakself.parseOperation = nil;
op = nil;
weakself.contentRect = image.bounds;
if ([weakself.svgDelegate respondsToSelector:@selector(svgLayerDidLoadImage:)])
[weakself.svgDelegate svgLayerDidLoadImage:weakself];
}];
[[NSOperationQueue mainQueue] addOperations:@[sync] waitUntilFinished:YES];
}];
op.threadPriority = 0.1f;
[[self.class parseQueue] addOperation:self.parseOperation=op];
}
- (void)loadError:(NSError *)error
{
if ([self.svgDelegate respondsToSelector:@selector(svgLayer:didFailedLoad:)])
[self.svgDelegate svgLayer:self didFailedLoad:error];
}
- (void)clean
{
if (self.loadOperation) [self.loadOperation cancel];
if (self.parseOperation) [self.parseOperation cancel];
while (self.sublayers.count) [self.sublayers.firstObject removeFromSuperlayer];
self.contentRect = CGRectZero;
}
@end