每个开发者都有他们自己开发一个应用的好方法?一些开发者使用Auto-Layout,一些开发者使用图标算法,甚至一些开发者喜欢用Vim编程。
随着iOS7和Xcode5的发布,我想利用一个简单的weather app作为简单的实践来使用熟悉最新的工具和概念!
在这个系列的第二个部分,你将会学会下面的技巧来创建你的应用程序
- Cocoapods
- 在你的app中使用自动布局
- ReactiveCocoa
- OpenWeatherMap
Getting Started
按如下步骤点击开始你的程序:打开Xcode然后找到File\New\Project 。 选择Application\Empty Application 然后命名你的项目为SimpleWeather然后点击Next,选择一个文件夹保存你的工程,然后点击Create。
Cocoapods
我们将使用
Cocoapods管理下载的code,在你的工程中添加文件,根据项目需求来配置项目设置。让我们首次包含你将要使用的!
Mantle
Mantle是一个建模框架,实现了多个不同的NSCoding和NSCopying方法,还添加了许多非常便利的方法允许你实现更多的有用的功能,比如返回一个json字典,已代表你的对象。在多数情况下,mantle可以作为Core Data的替代选择。
LBBlurredImage
LBBlurredImage 是UIImageView的分类,用于设置图像并进行模糊化处理。可以在
这里看看源代码
TSMessages
TSMessages 提供了易于使用的类,用于在屏幕顶部显示小的提醒信息。你可以用这个方法来提醒你的用户一些错误。例如下面的图片的显示。
![TSMessages Error TSMessages Error](http://cdn1.raywenderlich.com/wp-content/uploads/2013/12/TSMessage.png)
ReactiveCocoa
ReactiveCocoa是我们在这个项目中使用的最后一个项目,同样是来自Github。是一个用于组合和转换值序列的框架,你可以在
这里看到源代码。
Setting Up Your Cocoapods Libraries
设置你的Cocoapods的 libraries,首先确定你已经安装了Cocoapods,照着下面的步骤做,打开终端,然后在Terminal中输入下面的命令:
which pod
你应该会得到下面的输出结果:
/usr/bin/pod
这个会根据你安装的一些文件,例如
rbenv 或者
RVM,也许你会得到不同的路径。如果在你输入命令之后返回的是“pod not found”,那么你就需要安装 cocoapods这个管理依赖库。如果你想要了解更多关于Cocoapods你可以查看
tutorial on Cocoapods。
Podfiles是用来告诉Cocoapods要导入什么开源项目,Pods要导入。
在安装完成之后按照下面的步骤来安装我们需要的类库:
打开Terminal 输入 cd 找到你当初建立simple weather工程的文件夹,然后在终端中输入 Pico
然后在打开的pico中,输入如下的命令:
platform: iOS,’7.0’
pod ‘Mantle’
pod ‘LBBlurredImage’
pod ’TSMessages’
pod ‘ReactiveCocoa’
上面的命令完成了下面的两件事情:
- 它告诉Cocoapods要安装的类库版本是要适应”iOS7.0”的
- 给了Cocoapods你需要安装类库的列表
下面是怎样在你的podfile中安装类库的步骤:在你的Terminal中输入下面的命令然后按 Enter
pod install
然后等待一下你会看到在显示屏上会出现下面的显示
$pod install
Analyzing dependencies
CocoaPods 0.28.0 is available.
Downloading dependencies
install HexColors (2.2.1)
install LBBlurredImage (0.1.0)
Install Mantle (1.3.1)
Install ReactiveCocoa (2.1.7)
Install TSMessages (0.9.4)
Generating Pods project
Integrating client project
[!]From now on use
’SimpleWeather.xcoworkspace’.
Cocoapods将会在你的工程中创建一连串的新文件,但是只是在SimpleWeather.xcworkspace中创建这些新文件。
打开SimpleWeather.xcworkspace,看一下你的工程的设置,这里会有一个Pods工程,在你的工作空间中,每个文件夹都会倒入到你的Pods文件夹,就像下面显示的一样。
![Cocoapods Project Cocoapods Project](http://cdn2.raywenderlich.com/wp-content/uploads/2013/12/SimpleWeather-Cocoapods.jpg)
确保你选择的SimpleWeather工程是下面的显示的一样:
![Select SimpleWeather Project Select SimpleWeather Project](http://cdn4.raywenderlich.com/wp-content/uploads/2013/12/SimpleWeather-Project.jpg)
然后运行你的程序,你会看到下面的显示:
![Blank App Blank App](http://cdn1.raywenderlich.com/wp-content/uploads/2013/11/blank-app.jpg)
这个也许看起来不大对劲,但是我们立刻开始添加一些文件。
Creating Your Main View Controller
这个应用程序看起来很复杂,但是我们一步一步开始。首先创建一个简单的视图控制器。现在开始添加。
选择SimpleWeather工程,点击File\New\File然后选择Cocoa Touch\Objective-C class,命名你的类:WXController然后继承自UIViewController。
确保你没有选择Targeted for iPad和With XIB for user interface,就像下面显示的一样:
![Create WXController Create WXController](http://cdn1.raywenderlich.com/wp-content/uploads/2013/11/create-controller.jpg)
打开WXController.m,在-viewDidLoad方法中写下如下的方法:
- (void)viewDidLoad{
[super viewDidLoad];
//稍后要删除的
self.view.backgroundColor = [UIColor redColor];
}
现在打开AppDelegate.m文件,然后导入两个类:
#import "WXController.h"
#import <TSMessage.h>
眼尖的读者会发现WXController 导入和 TSMessage的导入方式不一样!这是肿么回事,往回看看你创建podfile 文件的时候,使用的是Cocoapods导入TSMessage 并把它添加到了你的工作空间,所以你可以使用括号代替引号。
在-application:didFinishLaunchingWithOptions:中写下如下的代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//1
self.window.rootViewController = [[WXController alloc] init];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
//2
[TSMessage setDefaultViewController:self.window.rootViewController];
return YES;
}
下面告诉你上面的代码都在干点什么
1.初始化根视图控制器,然后设置WXController。通常情况下,这个视图控制器是一个UINavigationController或者UITabBarController,但是在这个案例当中,你是设置WXController作为代替。
2.为了将TSMessages设置为
默认的视图控制器显示,通过这样,你不再需要,手动的指定显示的控制器。
创建好之后,运行你的程序你会看到像下面一样的显示
![WXController WXController](http://cdn5.raywenderlich.com/wp-content/uploads/2013/11/wxcontroller-red.jpg)
状态栏是一个有点难以阅读对红色背景。还好,有一个简单的方法,使状态栏了很多更清晰易读。
在iOS7 中的
UIViewController 中有新的API来控制状态栏,打开WXController 在
-viewDidLoad
:方法后直接添加方法,像下面显示的那样:
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent;
}
再运行你的程序你会看到如下图的显示:
![Create WXController with Light Status Bar Create WXController with Light Status Bar](http://cdn4.raywenderlich.com/wp-content/uploads/2013/11/wxcontroller-red-status.jpg)
Setting Up Your App’s Views
现在可以为你的应用添加图片,把图片下载到本地可以方便使用,在 这里下载。 背景图片来自Flickr用户 idleformat,天气图片来自Dribbble用户 heeyeun
选择Xcode ,然后点击File\Add Files to “SimpleWeather”….找到图片文件夹,然后xcode会弹出Copy items into destination group’s folder (if needed) 然后点击添加。
打开WXController.h 然后在里面添加委托协议,在
@interface
行写:
<UITableViewDataSource,UITableViewDelegate,UIScrollViewDelegate>
现在打开WXController.m, 您可以使用热键Control-Command-Up 控制指令最多的H和M文件之间快速切换。
在 WXController.m:文件顶部添加下面的导入代码
#import <LBBlurredImage/UIImageView+LBBlurredImage.h>
LBBlurredImage.h是用来链接 用Cocoapods导入的LBBlurredImage工程,你可以使用这个Library 来模糊你的背景图片.
你应该为WXController 创建一个样板文件导入。填写属性
@interface WXController ()
@property (nonatomic,strong) UIImageView *backgroundImageView;
@property (nonatomic,strong) UIImageView *blurredImageView;
@property (nonatomic,strong) UITableView *tableView;
@property (nonatomic,assign) CGFloat screenHeight;
@end
现在开始在你的工程中创建和设置你的视图,”啥”,你说,哪里有IBOutlets?
提示:所有的视图都会在代码中实现和设置:
![Table Flip](http://cdn5.raywenderlich.com/wp-content/uploads/2013/11/table-flip.jpg)
坚持住:不要崩溃,每个开发者都有他自己的开发爱好。在这里有一些谈论http://www.youtube.com/watch?v=XciUazpOfFU&feature=c4-overview&list=UUz3cM4qLljXcQ8oWjMPgKZA(但是需要梯子),每个人用不同的开发方式,Storyboards,NIBs和代码,都有自己的拥护者和批判者。
如果在非常复杂的构图应用程序中其实没有必要自动布局,这样有可能会导致性能下降,然而通过这个案例的学习,你将学会如何使用代码来完成。
你将会创建三个视图然后彼此影响,就像你看到的GIF显示的那样
![Exploded Screens Exploded Screens](http://cdn4.raywenderlich.com/wp-content/uploads/2013/11/screens.jpg)
打开WXController.m文件,然后在-viewDidLoad中设置背景颜色,就像下面代码显示的那样:
//1
self.screenHeight = [UIScreen mainScreen].bounds.size.height;
UIImage *background = [UIImage imageNamed:@“bg”];
//2
self.backgroundImageView = [[UIImageView alloc] initWithImage:background];
self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:self.backgroundImageView];
//3
self.blurredImageView = [[UIImageView alloc] init];
self.blurredImageView.contentMode = UIViewContentModeScaleAspectFill;
self.blurredImageView.alpha = 0;
[self.blurredImageView setImageToBlur:background blurRadius:10 completionBlock:nil];
[self.view addSubView:self.blurredImageView];
//4
self.tableView = [[UITableView alloc] init];
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.separatorColor = [UIColor colorWithWhite:1 alpha:0.2];
self.tableView.pagingEnabled = YES;
[self.view addSubView:self.tableView];
这是一段简单易懂的代码:
1.得到和储存屏幕的高,最后在主页上显示,你将会需要他们
2.创建一个静态的背景图片,然后添加到视图上
3.利用LBBlurredImage创建一个模糊的图片,从零开始初始化,以便backgroundImageView从一开始可见。
4.利用提供的数据创建一个容易操控的tableView 。WXController将会设置代理和数据源,除了scroll view代理。注意:你将会设置pagingEnabled为YES。
在WXController.m:文件@implementation块中添加UITableView的代理和数据源
//1
#pragma mark -UITableViewDataSource
//2
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
//TODO:Return count of forecast
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = @“CellIdentifier”;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
}
//3
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
cell.textLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.textColor = [UIColor whiteColor];
// TODO:Setup the cell
return cell;
}
#pragma mark -UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//TODO:Determine cell height based on screen
return 44;
}
尽管在上面的代码中有很多的占位符,告诉你到了哪里
1.Pragma 标记是帮助你组织你的代码的一个很好的方法。
2.你的表视图有两个部分,一个是每小时的天气预报,另一个是每天的天气预报。你需要总是返回这两个部分。
3.天气预报Cells不应该被选择,给他们一个半透明的黑色背景和白色文本。
最后,我们需要在WXController.m:文件中添加下面的方法:
- (void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
CGRect bounds = self.view.bounds;
self.backgroundImage.frame = bounds
self.blurredImageView.frame = bounds;
self.tableView.frame = bounds;
}
接下来,运行你的程序你就会看到下面的显示:
![Image Background Image Background](http://cdn1.raywenderlich.com/wp-content/uploads/2013/11/background.jpg)
还是
-viewDidLoad
,添加代码来设置你的布局框架和边缘
//1
CGRect headerFrame = [UIScreen mainScreen].bounds;
//2
CGFloat inset = 20;
//3
CGFloat temperatureHeight = 110;
CGFloat hiloHeight = 40;
CGFloat iconHeight = 30;
//4
CGRect hiloFrame = CGRectMake(inset, headerFrame.size.height - hiloHeight,headerFrame.size.width - (2*inset),hiloHeight);
CGRect temperatureFrame = CGRectMake(inset, headerFrame.size - (temperatureHeight + hiloHeight), headerFrame.size.width - (2 * inset), temperatureHeight);
CGRect iconFrame = CGRectMake(inset , temperatureFrame.origin.y - iconHeigh, iconHeight, iconHeight);
//5
CGRect conditionFrame = iconFrame;
conditionsFrame.size.width = self.view.bounds.size.width - (((2 * inset) + iconHeight) +10);
conditionsFrame.origin.x = iconFrame.origin.x +(iconHeight +10);
这个相当于例行的代码,但是这将起到下面的效果
1.设置了你的每个表的头,都拥有相同的尺寸,你将利用UITableView 的分页的到时间段的和每天的天气预报的部分。
2.创建一个可以嵌入均匀地隔开和正中显示
3.为你地多种多样地视图创建和初始化高度。设置配置标准
4.为你的标签和图标设置标准
5.拷贝icon框架,调整文本空间的扩张,并且把图标移动到对的位置,你将会看见怎样
添加下面的代码到你的
-viewDidLoad
:方法中
// 1 UIView *header = [[UIView alloc] initWithFrame:headerFrame]; header.backgroundColor = [UIColor clearColor]; self.tableView.tableHeaderView = header; // 2 // bottom left UILabel *temperatureLabel = [[UILabel alloc] initWithFrame:temperatureFrame]; temperatureLabel.backgroundColor = [UIColor clearColor]; temperatureLabel.textColor = [UIColor whiteColor]; temperatureLabel.text = @"0°"; temperatureLabel.font = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:120]; [header addSubview:temperatureLabel]; // bottom left UILabel *hiloLabel = [[UILabel alloc] initWithFrame:hiloFrame]; hiloLabel.backgroundColor = [UIColor clearColor]; hiloLabel.textColor = [UIColor whiteColor]; hiloLabel.text = @"0° / 0°"; hiloLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:28]; [header addSubview:hiloLabel]; // top UILabel *cityLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, self.view.bounds.size.width, 30)]; cityLabel.backgroundColor = [UIColor clearColor]; cityLabel.textColor = [UIColor whiteColor]; cityLabel.text = @"Loading..."; cityLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:18]; cityLabel.textAlignment = NSTextAlignmentCenter; [header addSubview:cityLabel]; UILabel *conditionsLabel = [[UILabel alloc] initWithFrame:conditionsFrame]; conditionsLabel.backgroundColor = [UIColor clearColor]; conditionsLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:18]; conditionsLabel.textColor = [UIColor whiteColor]; [header addSubview:conditionsLabel]; // 3 // bottom left UIImageView *iconView = [[UIImageView alloc] initWithFrame:iconFrame]; iconView.contentMode = UIViewContentModeScaleAspectFit; iconView.backgroundColor = [UIColor clearColor];
[header addSubview:iconView];
看到这么大块 的代码,很不淡定了,但是这个可以用来显示各种各样 的控制器在你的视图中。总结:
1.你的表的头部设置
2.创建显示必须的天气标签
3.为每个天气图标添加图片
运行你的程序,你将会看到下面的截屏显示的图片
![Labels and Views Labels and Views](http://cdn5.raywenderlich.com/wp-content/uploads/2013/12/built-layout.jpg)
用手指推动找个表,你会看到有一种回弹的效果。
Retrieving Weather Data
你肯定注意到了都不显示的”Loading......”,但是这里并没有做什么,是时候来让它做些什么了。
接下来就是我们要做的事情:
1.找到当地的图案
2.从API endpoint下载JSON 数据
3.
WXCondition
s和
WXDailyForecast
s的JSON图谱
4.通知UI我们获取新的数据
让我们开始吧,点击File\New\File…选择Cocoa Touch\Objective-C class命名为WXClient然后是继承自NSObject。
按照上面的步骤创建下面的三个类:
- WXManager继承自NSObject
- WXCondition 继承自MTLModel
- WXDailyForecast继承自WXCondition
Creating Your Weather Model
你的模型会使用Mantle来时刻获取数据的变化
打开WXCondition.h文件来修改,完成下面的代码
// 1 @interface WXCondition : MTLModel <MTLJSONSerializing> // 2 @property (nonatomic, strong) NSDate *date; @property (nonatomic, strong) NSNumber *humidity; @property (nonatomic, strong) NSNumber *temperature; @property (nonatomic, strong) NSNumber *tempHigh; @property (nonatomic, strong) NSNumber *tempLow; @property (nonatomic, strong) NSString *locationName; @property (nonatomic, strong) NSDate *sunrise; @property (nonatomic, strong) NSDate *sunset; @property (nonatomic, strong) NSString *conditionDescription; @property (nonatomic, strong) NSString *condition; @property (nonatomic, strong) NSNumber *windBearing; @property (nonatomic, strong) NSNumber *windSpeed; @property (nonatomic, strong) NSString *icon; // 3 - (NSString *)imageName;
@end
这是一段进阶的代码,来看看下面的解释
1.MTLJSONSerializing协议告诉Mantle serializer,这个对象如何映射JSON到Objective-c 属性中
2.这些都是你的天气属性,你将使用它们使得你的数据将更好的展现在你的显示屏上
3.这是一个简单的帮助方法,来便利天气状况的图片文件
运行你的软件,但是失败了,为啥?猜猜看,如果你需要小小的帮助那你就看看下面
Solution Inside: Solution | Show |
---|---|
// 1
static
NSDictionary*_imageMap=nil;
if(! _imageMap){
// 2
_imageMap= @{
@"01d":@"weather-clear",
@"02d":@"weather-few",
@"03d":@"weather-few",
@"04d":@"weather-broken",
@"09d":@"weather-shower",
@"10d":@"weather-rain",
@"11d":@"weather-tstorm",
@"13d":@"weather-snow",
@"50d":@"weather-mist",
@"01n":@"weather-moon",
@"02n":@"weather-few-night",
@"03n":@"weather-few-night",
@"04n":@"weather-broken",
@"09n":@"weather-shower",
@"10n":@"weather-rain-night",
@"11n":@"weather-tstorm",
@"13n":@"weather-snow",
@"50n":@"weather-mist",
};
}
return _imageMap;
}
// 3
-(
NSString*)imageName{
return[WXCondition imageMap][self.icon];
}
这是上面的代码要干啥:
1.创建一个静态的NSDictionary 使得每个WXCondition使用同样的数据地图
2.用代码获取图片文件
3.清除普通信息获得图片文件名
下面是一段见的获取JSON数据响应的事例
|
做到这一点,你将利用Objective-c的
Key-Value Coding 和Mantle的
MTLJSONAdapter。
仍然是在WXCondition.m文件中,设置你的"JSON to model properties"通过添加+JSONKeyPathsByPropertyKey方法来映射到MTLJSONSerializing协议要求
|
WXCondition
的属性名称,而词典的值是从JSON机码路径。
您可能已经注意到,有一个与JSON数据被映射到Objective-C的性能的方式突出问题。该物业的日期是类型的NSDate ,但JSON有作为Unix的时间存储一个NSInteger 。你需要两个莫名其妙之间进行转换。
Mantle刚刚的功能来解决这个问题给你:
MTLValueTransformer。此类允许你声明一个块,详细说明如何从值转换。
为一个特定的属性创建一个transformer,你可以添加一个类方法作为属性的开头以JSONTransformer作为结束。
它可能比解释的更能够让你明白,所以为WXCondition.m中NSDate添加下面的transformer。
|
告诉你上面都干了啥:
1.你可以使用获得变换值,并通过Objective-c属性返回MTLValueformer。
2.您只需要详细说明如何一次Unix时间和的NSDate之间进行转换,所以才重用,-dateJSONTransformer日出和日落
这下价值转型是有点讨厌,但它只是使用OpenWeatherMap的API和他们自己的格式JSON响应方式的结果。weather 关键是一个JSON数组,但你“再只关注单一的天气状况。
在 WXCondition.m使用相同的结构,-dateJSONTransformer ,您可以创建一个NSArray和NSString的之间的转换?该解决方案提供如下,如果你不能完全得到它。
Solution Inside: Solution | Show |
---|---|
在WXCondition.m添加以下的方法和宏定义。
|
|
max
.
温度关键分歧放在一边,其他都一样。所以,你真正需要做的是改变日常预报的键映射
打开WXDailyForecast.m并重写+JSONKeyPathsByPropertyKey如下:
|
1.得到WXCondition映射,并创建它的可变副本。
2.改变最大和最小的键映射到你所需要的日常预测
3.返回新的映射
生成并运行您的应用程序,有没有什么新的东西,看看自从上次运行,但这是一个好地方,检查你的应用程序编译和运行没有任何错误。
![Labels and Views Labels and Views](http://cdn4.raywenderlich.com/wp-content/uploads/2013/11/built-layout.jpg)