iOS_21團購_【運行時】將字典轉成物件模型

來源:互聯網
上載者:User

標籤:ios

最終:



核心代碼:

NSObject+Dict.h

////  NSObject+Dict.h//  帥哥_團購////  Created by beyond on 14-8-14.//  Copyright (c) 2014年 com.beyond. All rights reserved.//  使用運行時,將dict轉成對象#import <Foundation/Foundation.h>@interface NSObject (Dict)// 一個對象,調用此方法,參數 傳遞一個字典,便可以通過運行時,自動將字典中所有的值V,賦值到對象對應的成員屬性上面去- (void)setValuesWithDict:(NSDictionary *)dict;@end
NSObject+Dict.m
////  NSObject+Dict.m//  帥哥_團購////  Created by beyond on 14-8-14.//  Copyright (c) 2014年 com.beyond. All rights reserved.//#import "NSObject+Dict.h"// 運行時需要#import <objc/message.h>#import <objc/runtime.h>@implementation NSObject (Dict)// 一個對象,調用此方法,參數 傳遞一個字典,便可以通過運行時,自動將字典中所有的值V,賦值到對象對應的成員屬性上面去- (void)setValuesWithDict:(NSDictionary *)dict{    // 本類的類名    Class c = [self class];        while (c) {        // 1.獲得本類 所有的成員變數        unsigned int outCount = 0;        Ivar *ivars = class_copyIvarList(c, &outCount);                for (int i = 0; i<outCount; i++) {            Ivar ivar = ivars[i];                        // 2.屬性名稱            NSMutableString *name = [NSMutableString stringWithUTF8String:ivar_getName(ivar)];                        // 刪除最前面的_            [name replaceCharactersInRange:NSMakeRange(0, 1) withString:@""];                        // 3.取出屬性值            NSString *key = name;            if ([key isEqualToString:@"desc"]) {                key = @"description";            }            if ([key isEqualToString:@"ID"]) {                key = @"id";            }            // 取出參數字典中對應的值            id value = dict[key];            // 健壯性判斷,如果字典中沒有這個鍵對應的值,則進入下一次for迴圈            if (!value) continue;                        // 4.構造SEL            // 首字母            NSString *cap = [name substringToIndex:1];            // 首字母變大寫            cap = cap.uppercaseString;            // 將大寫字母調換掉原首字母            [name replaceCharactersInRange:NSMakeRange(0, 1) withString:cap];            // 拼接set            [name insertString:@"set" atIndex:0];            // 拼接冒號:            [name appendString:@":"];            SEL selector = NSSelectorFromString(name);                        // 5.屬性類型,如果是基本類型,要轉成對象            NSString *type = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];                        if ([type hasPrefix:@"@"]) {                // 若為物件類型,直接發送訊息                objc_msgSend(self, selector, value);            } else  {                // 若為非物件類型,即基本物件類型,則要轉成物件類型                if ([type isEqualToString:@"d"]) {                    objc_msgSend(self, selector, [value doubleValue]);                } else if ([type isEqualToString:@"f"]) {                    objc_msgSend(self, selector, [value floatValue]);                } else if ([type isEqualToString:@"i"]) {                    objc_msgSend(self, selector, [value intValue]);                }  else {                    objc_msgSend(self, selector, [value longLongValue]);                }            }        }        // for迴圈遍曆完了本類中所有的成員之後,擷取其父類繼續上述操作,直至其父類為空白        c = class_getSuperclass(c);    }}@end/* class_getSuperclass Returns the superclass of a class.  Class class_getSuperclass(Class cls) Parameters cls A class object. Return Value The superclass of the class, or Nil if cls is a root class, or Nil if cls is Nil.  Discussion You should usually use NSObject‘s superclass method instead of this function.  Availability Available in iOS 2.0 and later. Declared In objc/runtime.h */


Cities.plist檔案轉物件模型:



一組對應的模型Section.m

////  CitySectionByLetter.m//  帥哥_團購////  Created by beyond on 14-8-14.//  Copyright (c) 2014年 com.beyond. All rights reserved.//  資料模型,一個組Section,成員1:組名,如B組  成員2:是一個數組,cities,裝著B組這個組下面所有的城市,數組中每個成員是一個City對象#import "Section.h"//城市模型#import "City.h"@implementation Section// 關鍵!字典中cities對應的值還是字典數組,而我們需要的是city對象數組,所以要攔截setCities方法,將字典數組,遍曆,轉成一個個對象,並添加到一個數組中,再將對象數組賦值給成員屬性cities- (void)setCities:(NSMutableArray *)cities{        //攔截【運行時】將字典中的key--cities對應的值:字典數組 賦值到成員cities,而應該是把它轉成一個個對象之後,再賦值給成員屬性            // 當cities為空白或者裡面裝的已經是物件模型,就可以直接賦值,而不用再調用分類方法將字典轉成物件模型了    id obj = [cities lastObject];    if (![obj isKindOfClass:[NSDictionary class]]){        _cities = cities;        return;    }                NSMutableArray *cityArr = [NSMutableArray array];    for (NSDictionary *dict in cities) {        City *city = [[City alloc] init];        // 調用分類中運行時方法,將字典中的K - V 轉成對象        [city setValuesWithDict:dict];        [cityArr addObject:city];    }    // 最後,再將對象數組,賦值給成員屬性cities數組    _cities = cityArr;}@end

一個城市對應的模型

////  City.m//  帥哥_團購////  Created by beyond on 14-8-14.//  Copyright (c) 2014年 com.beyond. All rights reserved.//  資料模型,一個city,成員1:城市名,如北京  成員2:是一個數組,districts,裝著北京這個城市下面所有的行政區,數組中每個成員是一個District對象#import "City.h"// 資料模型#import "District.h"@implementation City// 關鍵!字典中districts對應的值還是字典數組,而我們需要的是district對象數組,所以要攔截setDistricts方法,將字典數組,遍曆,轉成一個個對象,並添加到一個數組中,再將對象數組賦值給成員屬性districts- (void)setDistricts:(NSMutableArray *)districts{    //攔截【運行時】將字典中的key--cities對應的值:字典數組 賦值到成員cities,而應該是把它轉成一個個對象之後,再賦值給成員屬性    NSMutableArray *districtArr = [NSMutableArray array];    for (NSDictionary *dict in districts) {        District *district = [[District alloc] init];        // 調用分類中運行時方法,將字典中的K - V 轉成對象        [district setValuesWithDict:dict];        [districtArr addObject:district];    }    // 最後,再將對象數組,賦值給成員屬性districts數組    _districts = districtArr;}@end

CityLocationController.m

////  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高度#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,下方是UITableView    UISearchBar *_searchBar;    UITableView *_tableView;    // UITableView上面有一層蒙板,遮蓋    CoverOnTableView *_cover;      //    TGSearchResultController *_searchResult;}@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].allSections;    // 將工具類返回的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"];}#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];}@end









聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.