Skip to content

Commit 55d736d

Browse files
committed
添加内容
1 parent 165520d commit 55d736d

File tree

1 file changed

+178
-1
lines changed

1 file changed

+178
-1
lines changed

chapter5/adding_to_functionalReactivePixels.md

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,181 @@
101101
[self.view addSubView:self.pageViewController.view];
102102
}
103103
```
104-
我要指出的是,简便起见,在我的应用里我禁用了横向展示,因为这不是一本关于`autoresizingMask`或者`autoLayout`的书。你可以通过[Eria Sadun的书]()了解更多关于`autoLayout`方面的细节。
104+
我要指出的是,简便起见,在我的应用里我禁用了横向展示,因为这不是一本关于`autoresizingMask`或者`autoLayout`的书。你可以通过[Eria Sadun的书](http://www.amazon.com/Layout-Demystified-Edition-Mobile-Programming/dp/0321967194)了解更多关于`autoLayout`方面的细节。
105+
106+
下面我们来了解一下UIPageViewController的数据源协议和代理协议。
107+
108+
```
109+
- (void)pageViewController:(UIPageViewController *)pageViewController
110+
didFinishAnimating: (BOOL)finished
111+
previousViewControllers:(NSArray *)previousViewControllers
112+
transitionCompleted:(BOOL)completed{
113+
self.title = [[self.pageViewController.viewControllers.firstObject photoModel] photoName];
114+
[self.delegate userDidScroll:self toPhotoAtIndex:[self.pageViewController.viewControllers.firstObject photoIndex]];
115+
}
116+
117+
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(FRPPhotoViewController *)viewController{
118+
return [self photoViewControllerForIndex:viewController.photoIndex - 1];
119+
}
120+
121+
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(FRPPhotoViewController *)viewController {
122+
return [self photoViewControllerForIndex:viewController.photoIndex + 1];
123+
}
124+
125+
```
126+
虽然这些方法没有技术上的`reactive`,却体现出一定意义上的实用性。我很佩服这种在特殊类型的视图控制器上的抽像,干得漂亮,Apple!
127+
128+
我们的视图控制器创建方法,类似下面这样:
129+
130+
```
131+
- (FRPPhotoViewController *)photoViewControllerForIndex:(NSInteger)index{
132+
if (index >= 0 && index < self.photoModelArray.count){
133+
FRPPhotoModel *photoModel = self.photoModelArray[index];
134+
135+
FRPPhotoViewController *photoViewController = [[FRPPhotoViewController alloc] initWithPhotoModel:photoModel index:index];
136+
137+
return photoViewController;
138+
}
139+
140+
//Index was out of bounds, return nil
141+
return nil;
142+
}
143+
```
144+
它基本上创建比配置了一个我们将要使用的UIViewController的子视图控制器FRPPhotoViewController。下面是他的头文件:
145+
146+
```
147+
@class FRPPhotoModel;
148+
149+
@interface FRPPhotoViewController : UIViewController
150+
- (instancetype)initWithPhotoModel:(FRPPhotoModel *)photoModel index:(NSInteger)photoIndex;
151+
152+
@property (nonatomic, readonly) NSInteger photoIndex;
153+
@property (nonatomic, readonly) FRPPhotoModel * photoModel;
154+
155+
@end
156+
157+
```
158+
这个视图控制器非常简单:显示一个photoModel下的高清图片,并提示photoImporter(单例对象)下载这个图片。它是如此简单,我现在就告诉你它的全部实现。
159+
160+
```
161+
//Model
162+
#import "FRPPhotoModel.h"
163+
164+
//Utilities
165+
#import "FRPPhotoImporter.h"
166+
#import <SVProgressHUD.h>
167+
168+
@interface FRPPhotoViewController ()
169+
//Private assignment
170+
@property (nonatomic, assign) NSInteger photoIndex;
171+
@property (nonatomic, strong) FRPPhotoModel *photoModel;
172+
173+
//Private properties
174+
@property (nonatomic, weak) UIImageView * imageView;
175+
176+
@end
177+
178+
@implementation FRPPhotoViewController
179+
180+
- (instancetype)initWithPhotoModel:(FRPPhotoModel *)photoModel index:(NSInteger)photoIndex{
181+
self = [self init];
182+
if (!self) return nil;
183+
184+
self.photoModel = photoModel;
185+
self.photoIndex = photoIndex;
186+
187+
return self;
188+
}
189+
190+
- (void)viewDidLoad{
191+
[super viewDidLoad];
192+
193+
//Configure self's view
194+
self.view.backGroundColor = [UIColor blackColor];
195+
196+
//Configure subViews
197+
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
198+
199+
RAC(imageView, image) = [RACObserve(self.photoModel, fullsizeData) map:^id (id value){
200+
return [UIImage imageWithData:value];
201+
}];
202+
203+
imageView.contentMode = UIViewContentModeScaleAspectFit;
204+
[self.view addSubView:imageView];
205+
self.imageView = imageView;
206+
}
207+
208+
- (void)viewWillAppear:(BOOL)animated{
209+
[super viewWillAppear:animated];
210+
[SVProgressHUD show];
211+
212+
//Fetch data
213+
[[FRPPhotoImporter fetchPhotoDetails:self.photoModel]
214+
subscribeError:^(NSError *error){
215+
[SVProgressHUD showErrorWithStatus:@"Error"];
216+
}
217+
completed:^{
218+
[SVProgressHUD dismiss];
219+
}];
220+
}
221+
222+
@end
223+
224+
```
225+
就像我们的collectionViewCell中那样,我们将UIImageView的image属性和数据模型的某个属性映射后的值绑定,所不同的是ViewController不需要考虑复用,所以我们不必计较怎么取消imageView的订阅---当imageView对象解除分配的时候,订阅将会被取消。
226+
227+
这个实现里面另一个有趣的部分在`viewWillAppear:`里:
228+
229+
```
230+
[SVProgressHUD show];
231+
//Fetch data
232+
[[FRPPhotoImporter fetchPhotoDetails:self.photoModel]
233+
subscribeError:^(NSError * error){
234+
[SVProgressHUD showErrorWithStatus:@"Error"];
235+
}
236+
completed:^{
237+
[SVProgressHUD dismiss];
238+
}];
239+
```
240+
没有收到错误或者完成信息之前,我们必须给用户展示网络请求的状态。你看,500px的受欢迎的照片的API接口只返回了一个照片的大概信息,但我们需要这个照片更详细的信息,所以我们必须调用第二个API接口来获取每一个照片的详细信息(包括全尺寸照片的URL)。
241+
242+
```
243+
+ (NSURLRequest *)photoURLRequest:(FRPPhotoModel *)photoModel{
244+
return [AppDelegate.apiHelper urlRequestForPhotoID:photoModel.identifier.integerValue];
245+
}
246+
```
247+
248+
我们还没有实现`fetchPhotoDetails:`方法,所以现在我们回到`FRPPhotoImporter`中,在头文件中定义这个方法,在实现文件中实现它。
249+
250+
```
251+
+ (RACReplaySubject *)fetchPhotoDetails:(FRPPhotoModel *)photoModel {
252+
RACReplaySubject * subject = [RACReplaySubject subject];
253+
NSURLRequest *request = [self photoURLRequest:photoModel];
254+
255+
[NSURLConnection sendAsynchronousRequest:request
256+
queue:[NSOperationQueue mainQueue]
257+
completionHandler:^ (NSURLResponse *response, NSData * data, NSError *connectionError){
258+
if(data){
259+
id results = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil][ @"photo" ];
260+
261+
[self configurePhotoModel:photoModel withDictionary:results];
262+
[self downloadFullsizedImageForPhotoModel:photoModel];
263+
264+
[subject sendNext:photoModel];
265+
[subject sendCompleted];
266+
}
267+
else{
268+
[subject sendError:connectionError];
269+
}
270+
}];
271+
272+
return subject;
273+
}
274+
```
275+
276+
这种方法跟前面我们看到的`importPhotos`方法模式一样,我们的`downloadFullsizedImageForPhotoModel:`方法跟`downloadThumbnailForPhotoModel:`方法也是一样的。除了这两者之外,还有什么重要的抽象方法呢?让我们来完成我们的缩略图方法。
277+
278+
```
279+
--待续 page56
280+
```
281+

0 commit comments

Comments
 (0)