你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS_21團購_拼音搜索

iOS_21團購_拼音搜索

編輯:IOS開發綜合

最終效果圖:

\


關鍵代碼:

搜索結果控制器:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+PC9wPgo8cHJlIGNsYXNzPQ=="brush:java;">// // 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:@"#"]; // 用於所有首字母拼接 如BJ NSMutableString *pinyinInitial = [NSMutableString string]; for (NSString *word in wordsArr) { [pinyinInitial appendString:[word substringToIndex:1]]; } // 去掉所有的# 如beijing pinyinStr = [pinyinStr stringByReplacingOccurrencesOfString:@"#" withString:@""]; // 3.城市名 city.name 中包含了搜索條件 如北京 // 拼音 pinyinStr 中包含了搜索條件 如BEIJING // 拼音首字母 pinyinInitial 中包含了搜索條件 如BJ if (([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 ()
{
    // 從plist中加載的數組,共23個成員,每個成員是個字典,每個字典有兩對KV,一對是name-->A,另一對是cities--->數組(數組中的成員是字典,一個字典對應一個城市,該字典又有三對KV,分別是:name--->北京,hot---->1,districts--->數組(該數組對應的又是一個字典,代表一個區,字典中有兩對KV,分別是:name--->朝陽區,neighbours--->數組(該數組的成員是string.....)))
    NSMutableArray *_sections; // 所有的城市組信息
    // view上方是UISearchBar,下方是UITableView
    UISearchBar *_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];
    // 組名,如ABCD
    return 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
{
    // 如果搜索框裡面沒有文字,隱藏搜索結果控制器的view
    if (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()
{
    //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.更改本按鈕 變為enable
    self.enabled = YES;

    
    // 4.設置圖標
    [self setIcon:@"ic_district.png" selectedIcon:@"ic_district_hl.png"];
}

// 5.監聽點擊【Location定位】,彈出一個Popover控制器
- (void)locationBtnOnDockClicked
{
    // 禁用,只可點擊一次
    self.enabled = NO;
    // 點擊dock上面的locationBtn,彈出的Popover封裝的控制器,其上方是搜索欄,下方是tableView
    CityLocationController *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對象中字符串的值為NSMutableString
    NSArray *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;
    // 訪問過的組section
    Section *_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];
    // 臨時變量,存放所有的section
    NSMutableArray *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



















  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved