最终效果图:

关键代码:

搜索结果控制器:

//
//  SearchResultController.m
//  帅哥_团购
//
//  Created by beyond on 14-8-15.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  当搜索框searchBar里面的文字change的时候,会创建本控制器,展示搜索结果列表,本控制器只有唯一一个成员变量,那就是从CityLocationController控制器的searchBar textDidChange:方法中传递过来的搜索文本#import "SearchResultController.h"
#import "PinYin4Objc.h"
#import "MetaDataTool.h"
#import "City.h"@interface SearchResultController ()
{// 数组,放着所有符合搜索条件的 城市对象NSMutableArray *_resultCityArr;
}
@end@implementation SearchResultController
- (void)viewDidLoad
{[super viewDidLoad];self.view.backgroundColor = [UIColor whiteColor];// 数组初始化,放着所有符合搜索条件的 城市对象_resultCityArr = [NSMutableArray array];
}// 唯一一个成员,从CityLocationController控制器的searchBar textDidChange:方法中传递过来的搜索文本
-(void)setSearchText:(NSString *)searchText
{_searchText = searchText;// 1.清除数组之前存放的搜索结果[_resultCityArr removeAllObjects];// 2.筛选城市// 拼音输出格式HanyuPinyinOutputFormat *fmt = [[HanyuPinyinOutputFormat alloc] init];// 全大写fmt.caseType = CaseTypeUppercase;// 无音调fmt.toneType = ToneTypeWithoutTone;// V字处理方式fmt.vCharType = VCharTypeWithUUnicode;// 下面是三种条件,关键代码!NSDictionary *citiesDict = [MetaDataTool sharedMetaDataTool].allCitiesDict;[citiesDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, City *city, BOOL *stop) {// SHI#JIA#ZHUANG// 1.拼音字符串,用#连接一个个拼音NSString *pinyinStr = [PinyinHelper toHanyuPinyinStringWithNSString:city.name withHanyuPinyinOutputFormat:fmt withNSString:@"#"];// 2.拼音首字母NSArray *wordsArr = [pinyinStr componentsSeparatedByString:@"#"];// 用于所有首字母拼接 如BJNSMutableString *pinyinInitial = [NSMutableString string];for (NSString *word in wordsArr) {[pinyinInitial appendString:[word substringToIndex:1]];}// 去掉所有的#  如beijingpinyinStr = [pinyinStr stringByReplacingOccurrencesOfString:@"#" withString:@""];// 3.城市名 city.name 中包含了搜索条件 如北京// 拼音 pinyinStr 中包含了搜索条件  如BEIJING// 拼音首字母 pinyinInitial 中包含了搜索条件 如BJif (([city.name rangeOfString:searchText].length != 0) ||([pinyinStr rangeOfString:searchText.uppercaseString].length != 0)||([pinyinInitial rangeOfString:searchText.uppercaseString].length != 0)){// 来到这,说明城市名中包含了搜索条件,添加到成员变量(对象数组),以便为tableView提供数据源[_resultCityArr addObject:city];}}];// 3.刷新表格[self.tableView reloadData];}#pragma mark - 数据源方法
// 符合搜索条件的结果 有多少行
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{return _resultCityArr.count;
}
// 每一行的独一无二内容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{static NSString *CellIdentifier = @"SearchResultCell";UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}// 取出本行对应的 城市对象City *city = _resultCityArr[indexPath.row];cell.textLabel.text = city.name;return cell;
}
// 友好提示,共有多少个符合条件的结果
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{return [NSString stringWithFormat:@"共%d个搜索结果", _resultCityArr.count];
}
#pragma mark - 代理方法
// 选中了符合搜索条件的所有搜索结果中的某一行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{// 取出本行对应的 城市对象City *city = _resultCityArr[indexPath.row];// 设置工具类的当前城市,其内部会拦截setter操作,更新最近访问的城市数组[MetaDataTool sharedMetaDataTool].currentCity = city;
}@end

点击 dock下面的倒数第2个定位按钮,

弹出控制器CityLocationController

//
//  CityLocationController.m
//  帅哥_团购
//
//  Created by beyond on 14-8-14.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  点击dock下面的倒数第2个定位按钮,弹出的用Popover包装的城市选择控制器,其上面是一个搜索框,下面是一个tableView(按城市的拼音分的组),当搜索框文字改变时候,(懒加载)创建一个搜索结果控制器,并且显示搜索界面在遮罩上面#import "CityLocationController.h"
// 蒙板
#import "CoverOnTableView.h"
// 元数据工具
#import "MetaDataTool.h"
// 数据模型---分组
#import "Section.h"
// 数据模型---城市
#import "City.h"
// 数据模型---行政区
#import "District.h"
//  当搜索框searchBar里面的文字change的时候,会创建本控制器,展示搜索结果列表
#import "SearchResultController.h"// 上面的searchBar高度
#define kSearchBarH 44@interface CityLocationController ()<UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>
{// 从plist中加载的数组,共23个成员,每个成员是个字典,每个字典有两对KV,一对是name-->A,另一对是cities--->数组(数组中的成员是字典,一个字典对应一个城市,该字典又有三对KV,分别是:name--->北京,hot---->1,districts--->数组(该数组对应的又是一个字典,代表一个区,字典中有两对KV,分别是:name--->朝阳区,neighbours--->数组(该数组的成员是string.....)))NSMutableArray *_sections; // 所有的城市组信息// view上方是UISearchBar,下方是UITableViewUISearchBar *_searchBar;UITableView *_tableView;// UITableView上面有一层蒙板,遮盖CoverOnTableView *_cover;// 搜索结果控制器SearchResultController *_searchResultCtrl;}@end@implementation CityLocationController- (void)viewDidLoad
{[super viewDidLoad];// 1.添加上方的搜索框UISearchBar[self addSearchBar];// 2.添加下方的tableView[self addTableView];// 3.使用工具类,加载城市数组数据[self loadCitiesMetaData];}// 1.添加搜索框UISearchBar
- (void)addSearchBar
{_searchBar = [[UISearchBar alloc] init];_searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;_searchBar.frame = CGRectMake(0, 0, self.view.frame.size.width, kSearchBarH);// 监听searchBar的获得焦点,失去焦点,字符变化等事件_searchBar.delegate = self;_searchBar.placeholder = @"请输入城市名或拼音";//    search.tintColor 渐变色//    search.barStyle 样式[self.view addSubview:_searchBar];}// 2.添加下方的tableView
- (void)addTableView
{_tableView = [[UITableView alloc] init];CGFloat tableViewH = self.view.frame.size.height - kSearchBarH;_tableView.frame = CGRectMake(0, kSearchBarH, self.view.frame.size.width, tableViewH);_tableView.dataSource = self;_tableView.delegate = self;// 重要~因为本控制器是在Popover控制器里面,Popover又设置了内容SIZE只有320, 480_tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;[self.view addSubview:_tableView];
}// 3.使用工具类,加载城市数组数据
- (void)loadCitiesMetaData
{// 从plist中加载的数组,共23个成员,每个成员是个字典,每个字典有两对KV,一对是name-->A,另一对是cities--->数组(数组中的成员是字典,一个字典对应一个城市,该字典又有三对KV,分别是:name--->北京,hot---->1,districts--->数组(该数组对应的又是一个字典,代表一个区,字典中有两对KV,分别是:name--->朝阳区,neighbours--->数组(该数组的成员是string.....)))_sections = [NSMutableArray array];NSArray *sections = [MetaDataTool sharedMetaDataTool].allSectionsArr;// 将工具类返回的section数组赋值给成员变量,以供tableView的数据源使用[_sections addObjectsFromArray:sections];
}#pragma mark - 数据源方法
#pragma mark - 数据源方法
// 共有多少分组(23个字母组)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{return _sections.count;
}
// 每一组有多少行(多少个城市就有多少行)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{// 第几组Section *s = _sections[section];// 第几组的城市数组的个数return s.cities.count;
}// 每一行的cell独一无二的内容
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{static NSString *CellIdentifier = @"CityListCell";UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}// 第几组Section *s = _sections[indexPath.section];// 第几行(城市)City *city = s.cities[indexPath.row];// 城市名cell.textLabel.text = city.name;return cell;
}
// 每一组的HeaderTitle
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{// 第几组Section *s = _sections[section];// 组名,如ABCDreturn s.name;
}
// 表格右侧的分组索引标题
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{// 重要~取出_sections数组中每一组的键为name的值(如ABCD...),并且将这些值全放到一个新的数组中,返回的这个新数组,就是分组索引的标题return [_sections valueForKeyPath:@"name"];
}
// 点击某一行时,设置当前城市
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{// 第几组Section *s = _sections[indexPath.section];// 哪一个城市City *city = s.cities[indexPath.row];// 设置工具类的当前城市,其内部会拦截setter操作,更新最近访问的城市数组[MetaDataTool sharedMetaDataTool].currentCity = city;
}#pragma mark - 搜索框代理方法// 搜索框开始编辑(开始聚焦,取得焦点)
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{// 1.动画效果,显示其右边的 取消按钮[searchBar setShowsCancelButton:YES animated:YES];// 2.动画显示遮盖(蒙板),并在内部绑定了一个,tap手势监听器if (_cover == nil) {_cover = [CoverOnTableView coverWithTarget:self action:@selector(coverClick)];}// 3.必须让cover完全覆盖在tableView上面_cover.frame = _tableView.frame;[self.view addSubview:_cover];// 4.开始全透明(看不见)_cover.alpha = 0.0;[UIView animateWithDuration:0.3 animations:^{// 让cover变成黑色[_cover alphaReset];}];
}
// 监听 遮盖 被tap点击,移除遮盖,隐藏取消按钮,退出键盘
- (void)coverClick
{// 1.动画完成后,移除遮盖[UIView animateWithDuration:0.3 animations:^{_cover.alpha = 0.0;} completion:^(BOOL finished) {[_cover removeFromSuperview];}];// 2.隐藏_searchBar最右边的取消按钮[_searchBar setShowsCancelButton:NO animated:YES];// 3.让_searchBar取消第一响应者,即退出键盘[_searchBar resignFirstResponder];// [self.view endEditing:YES];
}
// 当点击了 搜索框的键盘上面取消键时(即_searchBar失去了焦点)
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar
{[self coverClick];
}
// 当点击了 搜索框的右边的取消按钮时
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{[self coverClick];
}#pragma mark 监听搜索框的文字改变
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{// 如果搜索框里面没有文字,隐藏搜索结果控制器的viewif (searchText.length == 0) {[_searchResultCtrl.view removeFromSuperview];} else {// 懒加载,创建并显示搜索界面,frame与遮罩相同if (_searchResultCtrl == nil) {_searchResultCtrl = [[SearchResultController alloc] init];_searchResultCtrl.view.frame = _cover.frame;_searchResultCtrl.view.autoresizingMask = _cover.autoresizingMask;// 如果另一个控制器的view要展示在本控制器的view里,官方建议是让另一个控制器成为本控制器的子控制器[self addChildViewController:_searchResultCtrl];}// 传递搜索框里面的文本给 搜索结果控制器_searchResultCtrl.searchText = searchText;[self.view addSubview:_searchResultCtrl.view];}
}@end

Dock下方的Location按钮

//
//  DockItemLocation.m
//  帅哥_团购
//
//  Created by beyond on 14-8-13.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  dock下方倒数第2个按钮【定位】,继承自DockItem,点击本按钮,负责创建一个封装了控制器CityLocationController的Popover控制器,本按钮同时还负责监听屏幕的横竖屏切换通知,同时还负责监听CityLocationController控制器里面的某一行被选中时,发出的CityDidChanged通知,目的是能够让本按钮掌控Popover控制器的位置,以及其出现和隐藏#import "DockItemLocation.h"
// 点击dock上面的locationBtn,弹出的Popover封装的控制器,其上方是搜索栏,下方是tableView
#import "CityLocationController.h"
// 工具类中currentCity获取当前城市
#import "MetaDataTool.h"
#import "City.h"// 按钮上面是图片,下面是文字,这是图片在高度上的比例
#define kImageHeightRatioInBtn 0.5@interface DockItemLocation()<UIPopoverControllerDelegate>
{//popover控制器,创建出来之后,show方法显示,因此不可以是局部变量,必须用成员变量记住,否则方法btnClick调用完毕就销毁了,还如何 显示捏?UIPopoverController *_popoverCtrl;
}
@end
@implementation DockItemLocation- (id)initWithFrame:(CGRect)frame
{self = [super initWithFrame:frame];if (self) {// 1.调用父类的方法,设置内部的图片[self setIcon:@"ic_district.png" selectedIcon:@"ic_district_hl.png"];// 2.自动伸缩self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;// 3.设置默认的文字[self setTitle:@"定位中" forState:UIControlStateNormal];self.titleLabel.font = [UIFont systemFontOfSize:16];self.titleLabel.textAlignment = NSTextAlignmentCenter;[self setTitleColor:[UIColor whiteColor] forState:UIControlStateDisabled];[self setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];// 4.设置图片属性self.imageView.contentMode = UIViewContentModeCenter;// 5.监听点击【Location定位】,弹出一个Popover控制器[self addTarget:self action:@selector(locationBtnOnDockClicked) forControlEvents:UIControlEventTouchDown];// 6.添加监听城市改变的通知,当接收到其他其他东东(如工具类里面的setterCurrentCity方法中)发出的kCityChangeNote通知,就会调用下面的方法[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cityDidChanged) name:kCityChangeNote object:nil];}return self;
}
// 6.添加监听城市改变的通知,当接收到其他其他东东(如工具类里面的setterCurrentCity方法中)发出的kCityChangeNote通知,就会调用下面的方法
- (void)cityDidChanged
{// 0.先从工具类中,获取当前选中城市City *city = [MetaDataTool sharedMetaDataTool].currentCity;// 1.更改本按钮 显示的城市名称[self setTitle:city.name forState:UIControlStateNormal];// 2.关闭popover(代码关闭popover不会触发代理方法)[_popoverCtrl dismissPopoverAnimated:YES];// 3.更改本按钮 变为enableself.enabled = YES;// 4.设置图标[self setIcon:@"ic_district.png" selectedIcon:@"ic_district_hl.png"];
}// 5.监听点击【Location定位】,弹出一个Popover控制器
- (void)locationBtnOnDockClicked
{// 禁用,只可点击一次self.enabled = NO;// 点击dock上面的locationBtn,弹出的Popover封装的控制器,其上方是搜索栏,下方是tableViewCityLocationController *cityVC = [[CityLocationController alloc] init];// 唯一一个不是继承自UIViewController的控制器,它继承自NSObject//popover控制器,创建出来之后,show方法显示,因此不可以是局部变量,必须用成员变量记住,否则方法btnClick调用完毕就销毁了,还如何 显示捏?_popoverCtrl = [[UIPopoverController alloc] initWithContentViewController:cityVC];// 设置这个Popover控制器的显示的大小_popoverCtrl.popoverContentSize = CGSizeMake(320, 480);// 代理,监听Popover控制器的XX事件_popoverCtrl.delegate = self;// 因为其他方法也要显示,_popoverCtrl,所以抽取成自定义方法[self showPopoverCtrl];// 因为屏幕旋转时,弹出的popover的指向的位置就不对了,所以有必要注册监听屏幕旋转的通知// 先移除监听器,保证健壮性[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];// 再添加一个监听器,一旦设备出现UIDeviceOrientationDidChangeNotification,就会调用observer的selector方法[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(screenDidRotated) name:UIDeviceOrientationDidChangeNotification object:nil];
}
// 5-1,因为侦听到屏幕旋转了,也要再次显示_popoverCtrl,所以抽取成自定义方法
- (void)showPopoverCtrl
{// 显示到哪里? 如果目标view是self自己,则rect使用bounds,因为bounds的原点才是相对于自己// 如果目标view是self.superView,则rect使用frame,因为frame的原点才是相对于父控件[_popoverCtrl presentPopoverFromRect:self.bounds inView:self permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
// 5-2,再添加一个监听器,一旦设备出现UIDeviceOrientationDidChangeNotification,就会调用observer的selector方法
- (void)screenDidRotated
{if (_popoverCtrl.popoverVisible) {// 1.    关闭之前位置上面的_popoverCtrl[_popoverCtrl dismissPopoverAnimated:NO];// 2.    0.5秒后创建新的位置上的_popoverCtrl[self performSelector:@selector(showPopoverCtrl) withObject:nil afterDelay:0.5];}
}
#pragma mark - popOver代理方法
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{// 消失前,让定位按钮恢复可以点击状态self.enabled = YES;// 消失前,即popover被销毁的时候,移除注册的监听器(通知)[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
}#pragma mark - 销毁时,移除当前对控制器对屏幕的监听,防止野指针
- (void)dealloc
{[[NSNotificationCenter defaultCenter] removeObserver:self];
}#pragma mark - 覆写调整图片和文字在按钮中的Frame
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{CGFloat btnW = contentRect.size.width;CGFloat imgH = contentRect.size.height * kImageHeightRatioInBtn;return CGRectMake(0, 0, btnW, imgH);
}- (CGRect)titleRectForContentRect:(CGRect)contentRect
{CGFloat btnW = contentRect.size.width;CGFloat textH = contentRect.size.height * (1 - kImageHeightRatioInBtn);// 文字在下面,图片在上面CGFloat textY = contentRect.size.height - textH;return CGRectMake(0, textY, btnW, textH);
}#pragma mark - json转成Plist
- (void)json2plist
{// json文件读取成为数组NSString *filePath = @"/Users/beyond/Desktop/cities.json";NSData *data = [NSData dataWithContentsOfFile:filePath];// options:// NSJSONReadingMutableContainers  返回可变容器,NSMutableDictionary或NSMutableArray// NSJSONReadingAllowFragments:允许JSON字符串最外层既不是NSArray也不是NSDictionary,但必须是有效的JSON Fragment。例如使用这个选项可以解析 @“123” 这样的字符串。// NSJSONReadingMutableLeaves:返回的JSON对象中字符串的值为NSMutableStringNSArray *arr = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];// 数组写到文件后,就是plist[arr writeToFile:@"/Users/beyond/Desktop/cities.plist" atomically:YES];
}@end

用到的工具类

@interface MetaDataTool : NSObject
singleton_interface(MetaDataTool)// readonly只可读,NSArray,不允许外部随便增删改
// 所有的城市分组数组,数组中的元素是section对象
@property (nonatomic, strong, readonly) NSArray *allSectionsArr;// 所有城市字典,Key是城市名,Value是城市对象
@property (nonatomic, strong, readonly) NSMutableDictionary *allCitiesDict;// 当前选中的城市, 当点击了控制器下方的tableView的某一行时,会设置当前城市,拦截setter操作,更新最近访问的城市数组
@property (nonatomic, strong) City *currentCity; // 当前选中的城市@end
//
//  MetaDataTool.m
//  帅哥_团购
//
//  Created by beyond on 14-8-14.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  元数据管理类
// 1.城市数据
// 2.下属分区数据
// 3.分类数据#import "MetaDataTool.h"
// 一个分组模型
#import "Section.h"
#import "City.h"//#import "TGCategory.h"
//#import "TGOrder.h"
// 沙盒里面放的是所有曾经访问过的城市名字
#define kFilePath [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"visitedCityNamesArr.data"]
@interface MetaDataTool ()
{// 数组,存储曾经访问过城市的名称NSMutableArray *_visitedCityNamesArr;// 访问过的组sectionSection *_visitedSection; // 最近访问的城市组数组}@end@implementation MetaDataTool
singleton_implementation(MetaDataTool)- (id)init
{if (self = [super init]) {// 初始化项目中的所有元数据// 1.初始化城市数据[self loadCitiesData];}return self;
}// 1.初始化城市数据
- (void)loadCitiesData
{// 所有城市对象组成的字典,Key是城市名,Value是城市对象_allCitiesDict = [NSMutableDictionary dictionary];// 临时变量,存放所有的sectionNSMutableArray *tempSectionsArr = [NSMutableArray array];// 1.创建一个热门城市分组Section *hotSection = [[Section alloc] init];// 组名是 热门hotSection.name = @"热门";// 分组的成员cities,初始化hotSection.cities = [NSMutableArray array];// 为了将热门这一组加在分组数组的最前面,准备了一个临时的section数组[tempSectionsArr addObject:hotSection];// 2.添加A-Z分组,到临时section数组后面// 加载plist数据NSArray *sectionsArr = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Cities.plist" ofType:nil]];for (NSDictionary *dict in sectionsArr) {// 创建城市分组对象模型Section *section = [[Section alloc] init];// 调用分类方法,将字典转成模型[section setValuesWithDict:dict];// 将所有的section对象,加到临时的section对象数组的后面[tempSectionsArr addObject:section];// 遍历每一组的所有城市,找出热门的加到hotSection里面for (City *city in section.cities) {if (city.hot) {// 如果是热门城市[hotSection.cities addObject:city];}// 并且将所有的城市对象,以城市名作为键,存入字典中[_allCitiesDict setObject:city forKey:city.name];}}// 3.从沙盒中读取之前访问过的城市名称_visitedCityNamesArr = [NSKeyedUnarchiver unarchiveObjectWithFile:kFilePath];// 如果是首次使用,则沙盒中返回的是空数组,需要懒加载,创建一个数组if (_visitedCityNamesArr == nil) {_visitedCityNamesArr = [NSMutableArray array];}// 4.创建并添加一个section, 最近访问城市组(section)_visitedSection = [[Section alloc] init];_visitedSection.name = @"最近访问";_visitedSection.cities = [NSMutableArray array];// 5.遍历沙盒中取出来的城市名组成的数组,转成一个个城市对象for (NSString *name in _visitedCityNamesArr) {// 根据城市名,从对象字典中取出城市对象,并添加到最近访问城市组(section)中的城市对象数组City *city = _allCitiesDict[name];[_visitedSection.cities addObject:city];}// 6.如果最近访问城市组(section)中的城市对象数组中有城市,那么就可以将最近访问组插入到sections最前面if (_visitedSection.cities.count) {[tempSectionsArr insertObject:_visitedSection atIndex:0];}// 将所有的section组成的数组赋值给成员变量供调用者访问_allSectionsArr = tempSectionsArr;
}
// 当点击了控制器下方的tableView的某一行时,会设置当前城市,拦截setter操作,更新最近访问的城市数组,发出CityDidChanged通知给Dock上的定位按钮,让它隐藏popoverCtroller
- (void)setCurrentCity:(City *)currentCity
{_currentCity = currentCity;// 1.先从最近访问的城市名数组中,移除该的城市名[_visitedCityNamesArr removeObject:currentCity.name];// 2.再将新的城市名插入到数组的最前面(最近访问的在最前)[_visitedCityNamesArr insertObject:currentCity.name atIndex:0];// 3.同时,要将新的城市对象,放到_visitedSection的城市对象数组的最前面[_visitedSection.cities removeObject:currentCity];[_visitedSection.cities insertObject:currentCity atIndex:0];// 4.归档最近访问的城市名组成的数组,以便下次再解档[NSKeyedArchiver archiveRootObject:_visitedCityNamesArr toFile:kFilePath];// 5.每一次点击,拦截setter当前城市之后,都要发出通知,做什么用???[[NSNotificationCenter defaultCenter] postNotificationName:kCityChangeNote object:nil];}
@end

iOS_21团购_拼音搜索相关推荐

  1. 聚划算今日团购_聚划算今日团购清…

    聚划算今日团购_聚划算正在进行的团购_聚划算今日团购 聚划算,淘宝网官方的团购... 团购通 分享到:开心网,新浪微博,搜狐微博,人人网,豆瓣,百度搜藏,发送给朋友 团购网站详情 网站名称:聚划算 网 ...

  2. 判断 小程序_社区团购小程序商城系统,可以从哪些方面判断?

    原标题:社区团购小程序商城系统,可以从哪些方面判断? 社区商城系统属于电子商务行业品种,有数据表明发现,有72%的客户是通过网络渠道了解服务商.了解产品.了解行业的,那么你要做的就是在网络中辨识真伪. ...

  3. 供销大集有潜力吗_社区团购遭点名批评,互联网巨头真的只是惦记那几捆白菜吗?| 吴坚浙商频道...

    12月11日,<人民日报>发表评论批评搞社区团购的互联网巨头:"别只惦记着几捆白菜.几斤水果的流量,科技创新的星辰大海.未来的无限可能性,其实更令人心潮澎湃."就在不久 ...

  4. 拼团小程序源码_小程序拼团+团购+分销模式,玩转小程序用户裂变

    我们应该都点过朋友扔过来的拼团.砍价链接,拼团.砍价的模式能达到迅速裂变的效果.现在很多大大小小的商家都已经注册了微信小程序,玩起了社交裂变,提高品牌的曝光度,也为门店销量带来了明显的效果.微信小程序 ...

  5. 小程序获取用户手机号_社区团购小程序应该如何推广才能获取更多用户?

    如今社交裂变已成为时下最流行的引流方式,而最好用的社交裂变工具无疑是拥有巨大用户量的微信小程序了.那么作为开展社区团购的有效工具,社区团购小程序应该如何推广才能获取更多用户呢?今天赤焰信息就为大家解答 ...

  6. 框架鲜花商城系统测试_分销、团购、秒杀、优惠券小程序商城源码免费分享(Java语言)...

    Open-shop是一套完全开源的微信小程序商场系统,真正前后台全部开源 Open-Shop小程序商城,包括:分销(支持三级).团购(拼多多模式).秒杀.优惠券.等功能,前后端全部开源.做全网最开源. ...

  7. 开发转运维有什么好点的理由_芜湖好点的团购社区费用

    大揭密:哪些人真正在十荟团赚了大钱:做团长还是开发团长?(100%干货,果断收藏!)社区团购百团大战已经烧了三年多,十荟团不仅活下来了,还迅速向全国各地扩张.十荟团总部位于北京,十荟团通过小程序,基于 ...

  8. java实现团购功能_[Java教程]jquery组件团购倒计时功能

    [Java教程]jquery组件团购倒计时功能 0 2014-05-12 12:00:04 本文网址:http://www.shaoqun.com/a/90954.html *特别声明:以上内容来自于 ...

  9. 魔方机器人需要特制魔方吗_火影忍者手游:如果新春水门金币团购,你会夸魔方良心吗?...

    因为水门的人气较高,所以今年的新春水门大家都跟去年的新春卡卡西对标,没想到,魔方直接把水门提到A忍,这样的话,如果是点券售卖就是1980点券,似乎很多玩家也都已经认为这个忍者会是点券购买了,但是,在最 ...

  10. 小程序引入的echarts过大如何解决_小程序如何解决社区团购的痛点

    首先小猪V5社区团购小程序带我们先来了解一下,什么是社区团购.社区团购是以小区为单位,以微信为载体整合多个社区社群资源,为社区居民提供日常所需商品.生活服务,集中化管理运营的一种商业模式.那么社区团购 ...

最新文章

  1. n维椭球体积公式_混凝土工程量计算规则及公式
  2. python使用imbalanced-learn的KMeansSMOTE方法进行上采样处理数据不平衡问题
  3. 深度探索c++对象模型读书笔记:Data语意学-Data Member的绑定
  4. Code Review最佳实践
  5. Springboot使用Log4j2的配置详解
  6. 移动app测试之怎么避免bug漏测
  7. Jerry的反省:程序员不要轻易说出“这个功能技术上无法实现“
  8. 火焰效果材质实现_「游戏开发」使用Unity实现魔法火焰效果
  9. CakePHP 中文手册
  10. linux内核兼容性,各种glibc和Linux内核版本的兼容性
  11. 2019牛客多校 Round2
  12. 设计模式讲解2:static proxy和decorator的不同点
  13. C标准库源码解读(VC9.0版本)——ctype.h
  14. LOCAL_PRIVILEGED_MODULE 详解(3)
  15. CentOS 使用shc加密脚本
  16. 尝试破解使用网络验证的小软件
  17. SAP产品成本计算流程
  18. 推荐8个免费好用的网站
  19. 公民身份证校验规则最新最全最严格(包含最后一位校验码校验)
  20. Linux网络配置后无法正常上网

热门文章

  1. 使用CXF+Spring发布WebService,启动报错
  2. python语句中print(type(1j))_Python语句 print(type(1J))的输出结果是:________
  3. Android 激活设备管理器后就无法再次打开设备管理器界面
  4. 寡人的难题 (数据结构作业)
  5. 90°光混频器原理分析
  6. Vue 项目使用 又拍云 云存储服务
  7. ERROR sqoop.Sqoop: Got exception running Sqoop: java.lang.NullPointerException 解决方案【SOLVED】
  8. 【bootstraptable】JS访问用户媒体设备摄像头,进行拍照保存
  9. 相对丰度会歪曲实际丰度,联合16S扩增子测序和总菌qPCR获得的绝对丰度可靠吗?...
  10. 像西方知识分子那样登场