zoukankan      html  css  js  c++  java
  • C_obj

    Objective-C,面向对象的C语言,iOS系统及移动应用开发语言,集成开发环境xcode。
     
    New Project新建应用,xcode会生成main函数、主代理类(加载MainWindow.xib,控制AppViewController加载AppViewController.xib进入应用)、App-info.plist。
    Classes:类声明(.h)及实现(.m),通常xib界面->IBOutlet、IBAction - .h(@property) - .m(@synthesize)
    Resources:资源png、数据plist(数据可加载到NSArray)、界面xib(Nib文件源于NeXTStep收购,与NSString相关)
    Frameworks框架:Cocoa Touch提供Interface Builder所需的界面元素
     
    Nib界面AppViewController.xib,使用Interface Builder设计界面,将界面元素、交互动作与File's Owner里的IBOutlet成员和IBAction方法绑定。
     
    头文件AppViewController.h,引入库,声明协议支持,声明成员、属性、方法。
    #import <UIKit/UIKit.h> //引入库UIKit.framework,#import避免重复引入
    @interface AppViewController : UIViewController //单继承
    <UIPickerViewDataSource,UIPickerViewDelegate> { //多协议(声明并实现协议方法即可,这里是数据源和控制代理)
    IBOutlet UIPickerView *pickerView; //Interface Builder可以将界面上的选取器UIPickerView与此成员绑定
    NSArray *activities, *feelings; //内部数据成员,为数据源和代理提供支持;还支持plist文件、sqlite数据库
    }
    //方法默认是原子的,noatomic配置非原子特性;retain引用copy复制assign赋值readonly只读readwrite读写
    @property (noatomic,retain) UIPickerView *pickerView;//属性声明与实现文件里的@synthesize一起辅助编译器生成属性读写方法
    //减号表示实例方法,加号表示类方法
    -(IBAction) sendButtonTapped: (id) sender;//Interface Builder可以将界面上的按钮的Touch Up Inside事件与此方法绑定
     
    实现文件AppViewController.m,引入头文件,声明成员,实现方法,内存释放
    #import "AppViewController.h"
    @implementation AppViewController
    @synthesize pickerView;//结合头文件中的属性声明,IBOutlet与Nib的关联,此变量可以引用界面元素UIPickerView
    //实现协议UIPickerViewDataSource需要的方法
    -(NSInteger)numberOfComponentsInPickerView: (UIPickerView *)pickerView { return 2; }
    -(NSInteger)pickerView: (UIPickerView *)pickerView //UIPickerView需要知道选择器有多少部件(列),每个部件有多少行
    numberOfRowsInComponent: (NSInteger)component { return component == 0 ? [activities count] : [feelings count]; }
    //实现协议UIPickerViewDelegate需要的方法
    -(NSString *)pickerView: (UIPickerView *)pickerView //获取某个部件,某行需要的数据
    titleForRow: (NSInteger)row forComponent: (NSInteger)component
    { return component == 0 ? [activities objectAtIndex:row] : [feelings objectAtIndex:row]; }
    //实现初始化方法及清理内存
    -(void)viewDidLoad { [super viewDidLoad]; //初始化字符串数组,@"hehe"是NSString的简写,与普通的char*区别
    activities = [[NSArray alloc] initWithObjects:@"haha", @"hehe", nil]; feelings = ~~~; }
    -(void)dealloc { [activities release]; [feelings release]; [super dealloc]; } //释放数组内存
     
    • InstaTwit:即推
      1. 模板:View-based Application视图,主视图InstaTwitViewController
      2. 界面:标题Label,提示Label,选取器PickerView(IBOutlet、UIPickerViewDataSource、UIPickerViewDeletate),按钮Button(IBAction);在.h中添加IBOutlet、@property、IBAction,在.m中添加@synthesize、-(void)dealloc{[var release];}
      3. 主视图实现选取器数据源和代理InstaTwit : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>,单继承多协议(接口实现);数据源、代理。
        数据源根据内部数组NSArray提供:部件(列)数、各部件行数
        -(NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView
        -(NSInteger)pickerView:(UIPickerView*)pickerView numberOfRowsInComponent:(NSInteger)component
        代理提供:各部件各行的内容
        -(NSString*)pickerView:(UIPickerView*)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
      4. 按钮事件:根据选择行[pickView selectedRowInComponent:0]从内部数组获取字符串,按模式[NSString stringWithFormat:@"我在%@,我觉得%@啊!", activity, feeling]拼出消息,调Twitter接口发布即推NSData=[NSURLConnection sendSynchronouseRequest:NSMutableURLRequest returningResponse:NSURLResponse error:NSError]。
      5. 扩展:自定义输入开头UITextField,键盘会自动激活,其Return按钮可自定义文字(如:完成),为让键盘消失需要绑定事件UITextField.Did End on Exit到IBAction,并调用[sender resignFirstResponder],sender就是输入框UITextField。
    • Drink Mixer:调酒师
      1. 模板:Navigation-based Application导航,主视图RootViewController:UITableViewController
      2. 表格视图UITableViewController相关协议:段落数、各段落行数、各段落各行单元格(IndexPath封装段落和行编号)
        -(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
        -(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
        -(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
        表格单元格通常可以按键值重用:
        UITableViewCell* cell=[tableView dequeueReusableCellWithIndentifier:@"cell"];
        if(cell == null) cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"] autorelease];
      3. 从plist加载饮料数据:plist通常是数组,而数组元素可以是NSString饮料名或NSDictionary封装名称、配方等
        NSString *path=[[NSBundle mainBundle] pathForResource:@"DrinkArray" ofType:"plist"];
        [[NSMutableArray alloc] initWithContentsOfFile:path];
      4. 细节视图:DrinkDetailViewController,饮料名称UITextField(不可更改)、成分和方法UITextView
        表格单元格点击事件:新建细节视图并压栈,导航模板内部有UINavigationController控制多个视图
        -(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{
        [[DrinkDetailViewController alloc] initWithNibName:@"DrinkDetailViewController" bundle:nil];
        [self.navigationController pushViewController:drinkDetailViewController animated:YES];}
        细节视图可以仅设置模型NSDictionary *drink,而在将要显示时提取drink中的名称、配方等信息
        -(void)viewWillAppear:(BOOL)animated{//给各UI元素赋值,维护数据NSDictionary* drink;}
      5. HIG(Human Interface Guide)建议表格视图必须有披露指示器(有多项操作)或披露指示元素(有下级详情)
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;//表格每行右侧显示普通箭头符号
      6. 扩展:添加新饮料AddDrinkViewController,继承细节视图xib,代码中添加“保存”、“取消”按钮。
        “保存”时输入不合法将提示,表明需要“模式视图”,在“添加”按钮的IBAction里压入视图
        [[AddDrinkViewController alloc]initWithNibName:@"DrinkDetailViewController" bundle:nil];
        [self presentModalViewController:addDrinkVC animated:YES];
        模式视图没有顶部导航栏,所以需要手动添加导航栏,同时“保存”和“取消”按钮也有了布局空间。
        [[UINavigationController alloc] initWithRootViewController:addDrinkVC];
        导航控制器自带左右按钮,为“保存”和“取消”按钮提供支持,声明IBAction save|cancel方法。
        self.navigationItem.leftBarButtonItem=[[[UIBarButtonItem alloc] initWithBarButtonSystetmItemCancel target:self action:@selector(cancel:)] autorelease];
        self.navigationItem.rightBarButtonItem=[[[UIBarButtonItem alloc] initWithBarButtonSystemItemSave target:self action:@selector(save:)] autorelease];
        保存或取消后需要退出模式视图
        [self dismissModalViewControllerAnimated:YES]
        实际输入时,键盘挡住下半屏幕,需要滚动视图UIScrollView将所有元素嵌入Embed Objects In,并设置滚动视图大小
        -(void)viewDidLoad{scrollView.contentSize=self.view.frame.size;}//滚动视图大小就是内部view的大小
        键盘的出现和消失,需要系统通知的支持,可以在添加视图的出现viewWillAppear或消失viewWillDisappear时向默认通知中心订阅或取消事件
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:null];//方法keyboardDidShow响应UIKeyboardDidShowNotification通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:null];//方法keyboardDidHide响应UIKeyboardDidHideNotification通知
        [[NSNotificationCenter defaultCenter] removeObserver:self];//添加视图消失时取消响应通知
        键盘事件时需要改变滚动视图可是空间大小,这样滚动视图就可以显示出滚动条,方便输入配方等信息
        -(void)keyboardDidShow:(NSNotification*)notif{
        if(keyboardVisible)return;//需要记住键盘状态,因为切换输入框时键盘都在
        NSDictionary* info=[notif userInfo];//系统通知带有字典,封装事件细节
        CGSize keyboardSize=[[info objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue].size;//键盘大小
        scrollView.frame.height -= keyboardSize.height;//可视空间高度变小
        keyboardVisible=true;}//标记键盘出现状态
        实际添加数据,并通知视图更新显示
        NSMutableDictionary* newDrink=[[NSMutableDictionary alloc] init];
        [newDrink setValue:nameTextField.text forKey:NAME_KEY];//键值用常量constants.h值#define NAME_KEY "name";
        [self.drinks addObject:newDrink];
        -(void)viewWillAppear:(BOOL)animated{[self.tableView reloadData];}//表格视图RootViewController重新载入数据
      7. 排序显示数据:每次添加新饮料都需要排序
        NSSortDescriptor *nameSorter=[[NSSordDescriptor alloc] initWithKey:NAME_KEY ascending:YES selector:@selector(caseInsensitiveCompare:)];//大小写不敏感排序方法caseInsensitiveCompare
        [self.drinks sortUsingDescriptors:[NSArray arrayWithObject:nameSorter]];
      8. 持久保存数据:应用退出时系统会通知UIApplicationWillTerminateNotification,需要在频繁保存和应用崩溃间权衡
        RootViewController持有drinks数据,与AddDrinkViewController在显示或消失时注册通知不同,表格视图需要在viewDidLoad和viewDidUnload注册通知:表格视图会频繁地出现和消失,比如细节视图或添加视图出现。
        [self.drinks writeToFile:path atomically:YES];//path为之前载入plist的路径NSString,因为文件权限的问题会失败
      9. 删除与编辑已有数据:编辑模式,表格属性里选中Allow Selection While Editing支持选择某项进行编辑
        根视图右侧有添加按钮,左侧再添加编辑按钮即可:viewDidLoad里设置导航按钮
        self.navigationItem.leftBarButtonItem=self.editButtonItem;//表格视图内建支持,取消注释即可
        -(void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath{
        if(editingStyle==UITableViewCellEditingStyleDelete){[self.drinks removeObjectAtIndex:indexPath.row];
        [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath] withRowAnimation:UITableViewRowAnimationFade];}}//数据和视图都清除一行
        选择行时判断是否编辑模式
        -(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{
        if(!self.editing){//显示细节视图}else{
        editingDrinkVC.drink=[self.drinks objectAtIndex:indexPath.row];}//使用drink对象标识是编辑或添加模式视图
        显示和保存时判断是否编辑模式
        -(void)viewWillAppear:(BOOL)aniamted{if(self.drink != nil){//设置界面控件显示值}}
        -(IBAction)save:(id)sender{if(self.drink != nil){[drinkArray removeObject:drink]; self.drink=nil;}}//先删后存
    • iBountyHunter:赏金猎人
      1. 模板:Window-based Application,主视图UITabBarController标签包含逃犯和被捕表格UITableView。
      2. 视图:标签UITabBarController,逃犯FugitiveListViewController(带导航)
      3. 将标签加入主窗口:
        -(void)applicationDidFinishingLaunching:(UIApplication*)application{
        [window addSubView:tabcontroller.view];[window makeKeyAndVisible];}
      4. 使用Core Data存取数据:
        受控实体类:Fugitive:NSManagedObject,通常从模型生成实体类,字段以@property形式出现,完全由Core Data自动管理
        受控对象模板:iBountyHunter.xcdatamodel,添加对应字段即可(Interface Builder)
        受控对象上下文:构建NSFetchRequest交给受控对象上下文存取实体,新建实体时不能再手动初始化Fugitive,而应交给它
        iBountyHunterAppDelegate* appDelegate=(iBountyHunterAppDelegate*)[[UIApplication sharedApplication] delegate];
        NSManagedObjectContext* managedObjectContext=appDelegate.managedObjectContext;
        持久存储协调器:配置上下文从SQLite存取数据
      5. 取出数据:从受控对象上下文查询数据,不关心是来自sqlite、memory、binary file,在viewWillAppear时读取
        NSFetchRequest* request=[[NSFetchRequest alloc] ini];
        NSEntityDescription* entity=[NSEntityDescription entityForName:@"Fugitive" inManagedObjectContext:managedObjectContext];//从受控对象上下文读取实体模型
        NSSordDescriptor* sortDescriptor=[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];//按name字段排序
        [request setEntity:entity];//指定实体
        [request setSortDescriptor:[NSArray arrayWithObject:sortDescriptor]];//指定排序
        NSError* error;//保存错误信息
        NSMutableArray* mutableFetchResults=[[managedObjectContext exucuteFetchRequest:request error:&error] mutableCopy];//取出逃犯数据,存入items变量
        if(mutableFetchResults==nil){NSLog(@"Can't Load Fugitive data!");}
      6. 持久存储协调器:
        -(NSPersistentStoreCoordinator*)persistentStoreCoordinator{
        if(persistentStoreCoordinator==nil){
        NSURL* storeURL=[NSURL fileURLWithPath:[[self applicationDocumentDirectory] stringByAppendPathComponent:@"iBountyHunter.sqlite"]];//从文档目录读取数据库文件
        persistentStoreCoordinator=[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];//为受控对象上下文配置持久存储协调器,由协调器负责实际读写数据库
        if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]){NSLog(@"Unresolved error %@",error);abort();}
        return persistentStoreCoordinator;}
        应用安装后是只读的,目录结构为:iBountyHunter.app程序、Documents+Library(Preferences+Caches)文档目录、tmp临时,应用启动时需要检查Documents目录是否有一份数据拷贝,需要时从资源目录拷贝过来(在applicationDidFinishLaunching调用)
        -(void)createEditableCopyOfDatabaseIfNeeded(
        NSFileManager* fileManager=[NSFileManager defaultManager];
        NSString* documentsDirectory=[self applicationDocumentsDirectory];//可读写数据库文件在文档目录
        NSString* writableDBPath=[documentsDirectory stringByAppendingPathComponent:@"iBountyHunter.sqlite"];
        BOOL dbexists=[fileManager fileExistsAtPath:writableDBPath];//判断数据库文件是否存在
        if(!dbexists){NSString* defaultDBPath=[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"iBountyHunter.sqlite"];//应用资源数据库路径
        if(![fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error]){
        NSLog(@"Failed to create writable database file with message %@",[error localizedDescription]);}}
      7. 细节视图:FugitiveDetailViewController,姓名Label、编号Label、描述TextView、赏金Label;数据Fugitive
        -(void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath{
        FugitiveDetailViewController* fugitiveDetailViewController=[[FugitiveDetailViewController alloc] initWithNibName:@"FugitiveDetailViewControoler" bundle:nil];//加载逃犯视图
        fugitiveDetailViewController.fugitive=[self.items objectAtIndex:indexPath.row];//细节视图需要逃犯实体
        [self.navigationController pushViewController:fugitiveDetailViewController animated:YES];}//压入视图堆栈
        然后再FugitiveDetailViewController的viewWillAppear中向UI填充Fugitive数据
      8. 增加被捕信息:添加到逃犯细节视图方便编辑已被捕,NSNumber* captured;NSDate* captdate;
        数据迁移:给数据模型添加版本控制DataModel->AddModelVersion|SetCurrentVersion,Core Data需要知道所有模型版本已方便从各种旧版数据迁移到最新版数据。
        -(NSPersistentStoreCoordinator*)persistentStoreCoordinator{
        NSDictionary* options=[NSDictionary dictionaryWithObjectAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption,[NSNumber numberWithBool:YES],NSInferMappingModelAutomaticallyOption,nil];
        [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];//之前options为nil,这里启用轻量级数据迁移,通常添加属性、改名可行,高级有映射模型
        “已抓获?”使用分段控件UISegmentedControll(可同时显示YES|NO,开关控件仅交替显示ON|OFF不合意图、复选框不是标准控件需自己定制),点击是否已抓获时的动作
        -(IBAction)capturedToggleChanged:(id)sender{
        if(capturedToggle.selectedSegmentIndex==0){//分段控件有属性selectedSegmentIndex标识所选项
        fugitive.captdate=[NSDate date];//now此时已抓获
        fugitive.captured=[NSNumber numberWithBool:YES];//标记已抓获
        }else{fugitive.captdate=nil;}//标记未抓获
        fugitive是受控对象,上下文会在应用退出时自动检查并保存数据,但通常我们需要即时保存预防应用崩溃导致数据丢失
        [managedObjectContex save:&error];
        新建受控实体:新的实体被managedObjectContext知道所以会自动保存,校验[fugitive validateForInsert],回滚rollback
        [NSEntiryDescription insertNewObjectForEntityForName:@"Fugitive" inManagedObjectContext:managedObjectContext];
      9. 被捕视图:CapturedListViewController,获取逃犯列表时过滤数据,NSFetchRequest(Entity实体,Predicate谓词,sort排序]
        NSPredicate* captured=[NSPredicate predicateWithFormat:@"captured=YES"];
        [request setPredicate:captured];//过滤已抓获的逃犯
        列表与逃犯视图FugitiveListViewController类似,重用细节视图FugitiveDetailViewController
        谓词Predicate还可以从数据模型获取(xcode可视化编辑不易出错):Add Fetch Request -> Edit Predicate
        NSFetchRequest* request=[managedObjectModel fetchRequetFromTemplateWithName:@"capturedFugitives" substitutionVariables:[NSDictionary dictionaryWithObject:capturedFlag forKey:@"captured"]];
      10. 性能调优:逃犯视图和被捕视图有两个数组,如果移至viewDidLoad会有两个问题(仅加载一次细节视图修改后不会反应出变化、viewDidLoad在applicationDidFinishLaunching复制数据之前运行读取会有问题),而应该使用NSFetchedResultsController(专门设计与表格视图配合高效工作,可以仅保留需要显示的数据15个左右在内存中)
        CapturedListViewController支持协议NSFetchedResultsControllerDelegate并添加成员属性NSFetchedResultsController*
        在viewWillAppear中检查resultsController不为空时加载数据,
        resultsController=[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"captured_list.cache"];
        resultsController.delegate=self;//被捕视图是它的代理并支持NSFetchedResultsControllerDelegate协议,数据变化时通知
        [self.tableView reloadData];加载数据
        更新表格视图数据协议与代理
        -(NSInteger)numberOfSectionsInTableView:(UITableView*)tableView{
        return [[self.resultsController sections] count];}//数据控制器知道有多少段落,sectionNameKeyPath按属性名分组
        -(NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{
        return [[[self.resultsController sections] objectAtIndex:section] numberOfObjects];//各段落行数
        -(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
        Fugitive* fugitive=[self.resultsController objectAtIndexPath:indexPath];}//重用标识单元格,取出数据(选择行类似)
        数据改变时需要视图刷新数据,否则界面不会更新。数据变化时控制器resultsController会通知代理capturedListView
        -(void)controllerDidChangeContent:(NSFetchedResultsController*)controller{[self.tableView reloadData];}
        这里完全载入数据还有优化的余地:仅更新显示单元格
      11. 扩展:逃犯照片,CapturedPhotoViewController,@property (nonatomic,retain) UIImageView* fugitiveImage;
        在FugitiveDetailViewController视图添加showInfoButton
        -(IBAction)showInfoButtonPressed:(id)sender{
        CapturedPhotoViewController* controller=[[CapturedPhotoViewController alloc] initWithNubName:@"CapturedPhotoViewController" bundle:nil];
        controller.fugitive=self.fugitive;//从细节视图传入逃犯信息Fugitive
        controller.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal;//翻转动画效果切换
        [self presentModalViewController:controller animated:YES];
        数据模型添加image属性,再次迁移,
        -(void)viewWillAppear:(BOOL)animated{
        self.fugitiveImage.image=[[[UIImage alloc] initWithData:fugitive.image] autorelease];}
        照片视图CapturedPhotoViewController,照片UIImageView
        -(void)takePictureButton:(id)sender{
        if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){//iTouch不支持相机
        UIActionSheet* photoSourceSheet=[[UIActionSheet alloc] initWithTitle:@"Select Fugitive Picture" delegate:self cancelButton:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Take New Photo",@"Choose Existing Photo",nil,nil];//选择相片源表单的通知协议UIActionSheetDelegate
        [photoSourceSheet showInView:self.view];//选择相片源:相机、图片库、取消
        }else{UIImagePickerController* picker=[[UIImagePickerController alloc] init];
        picker.sourceType=UIImagePickerControllerSourceTypePhotoLibrary;
        picker.delegate=self;//选择图片后自己会被通知,协议UIImagePickerControllerDelegate
        picker.allowsEditing=YES;//允许照相后编辑图片
        [self presentModalViewController:picker animated:YES];}
        选择相片源表单协议UIActionSheetDelegate
        -(void)actionSheet:(UIActionSheet*)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex{
        UIImagePickerController* picker=[[UIImagePickerController alloc] init];
        picker.delegate=self;picker.allowEditing=YES;
        switch(buttonIndex){case 0:picker.sourceType=UIImagePickerControllerSourceTypeCamera;break;//相机
        case 1:picker.sourceType=UIImagePickerControllerSourceTypePhotoLibrary;break;//图片库
        defalt:[picker release];return;//用户选择了取消
        [self presentModalViewController:picker animated:YES];}//拍照或选择相片
        选择图片后的协议UIImagePickerControllerDelegate
        -(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(Image*)image editingInfo:(NSDictionary*)editingInfo{self.fugitive.image=UIImagePNGRepresentation(image);//保存照片,Core Data会存入库
        [self dismissModalViewControllerAnimated:YES];[picker release];}//关掉窗口、释放照片选取器
        -(void)imagePickerControllerDidCancel:(UIImagePickerController*)picker{
        [self dismissModalViewControllerAnimated:YES];[picker release];}//用户直接返回了
      12. 扩展:抓捕地点
        引入新框架Add->ExistingFramework->CoreLocation.framework,#include <CoreLocation/CoreLocation.h>
        数据模型添加double capturedLat,capturedLon经纬度,迁移数据库
        详情视图添加UILabel* capturedLocation位置,[NSString stringWithFormat:@"%.3f,%.3f",capturedLat,capturedLon]
        详情视图添加属性CLLocationManager* locationManager;
        -(void)viewWillAppear{
        self.locationManager=[[CLLocationManager alloc] init];
        self.locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;//十米精度
        self.locationManager.delegate=self;//地址更新时通知代理
        [self.locationManager startUpdatingLocation];}//定位功能非常耗电,在viewWillDisapplear释放
        -(void)viewWillDisappear:(BOOL)animated{
        [self.locationManager stopUpdatingLocation];[self.locationManager=nil];}
        定位地址通知协议CLLocationManagerDelegate
        -(void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation{capturedToggle.enabled=YES;}//可切换被捕
        -(void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error{
        capturedToggle.enabled=NO;}//不能定位地址时禁用切换按钮
        切换被捕状态时保存位置信息
        -(IBAction)capturedToggleChanged:(id)sender{
        if(capturedToggle.selectedSegmentIndex==0){
        CLLocation* curPos=self.locationManager.location;//获得上次通知的地址
        fugitive.capturedLat=[NSNumber numberWithDouble:curPos.coordinate.latitude];
        fugitive.capturedLon=[NSNumber numberWithDouble:curPos.coordinate.longitude];
        }else{fugitive.capturedLat=nil;fugitive.capturedLon=nil;}//更新位置标签capturedLocation
      13. 扩展:地图显示抓捕地点CapturedPhotoViewController下部
        添加地图开发包#iport <MapKit/MapKit.h>,@property (nonatomic,retain) IBOutlet MKMapView* fugitiveMapView;
        -(void)viewWillAppear:(BOOL)animated{//在照片视图显示时加载地图
        if([fugitive.captured boolValue]==YES){//判断是否已被捕
        CLLocationCoordinate2D mapCenter;
        mapCenter.latitude=[fugitive.capturedLat doubleValue];
        mapCenter.longitude=[fugitive.capturedLon doubleValue];//提取被捕位置经纬度
        MKCoordinateSpan mapSpan;
        mapSpan.latitudeDelta=0.005;mapSpan.longitudeDelta=0.005;//地图尺寸比例千分之五
        MKCoordinateRegion mapRegion;
        mapRegion.center=mapCenter;mapRegion.span=mapSpan;//位置和比例组合成范围
        self.fugitiveMapView.region=mapRegion;
        self.fugitiveMapView.mapType=MKMapTypeHybrid;}}//混合卫星和道路信息的地图
        [self.fugitiveMapView addAnnotaion:fugitive];//Fugitive实现了地图注释协议MKAnnotation
        大头针注释地图
        @interface Fugitive:NSManagedObject<MKAnnotation>
        @property (nonatomic,readonly) CLLocationCoordinate2D coordinate;
        -(NSString*)title;-(NSString*)subtitle;//协议支持Fugitive.h
        (CLLocationCoordinate2D)coordinate{
        CLLocationCoordinate2D captureCoord;
        captureCoord.latitude=[self.capturedLat doubleValue];
        captureCoord.longitude=[self.capturedLon doubleValue];
        return captureCoord;}
        -(NSString*)title{return self.name;}
        -(NSString*)subtitle{return self.desc;}//不合成属性@synthesize,手动返回值






  • 相关阅读:
    第15.26节 PyQt(Python+Qt)入门学习:Model/View架构中的便利类QListWidget详解
    第二十一章、 Model/View便利类列表部件QListWidget详解
    PyQt(Python+Qt)学习随笔:QListWidget的信号简介
    iis日志存放位置 及 查看方法
    如何查看和分析IIS日志
    IIS网站设置禁止IP访问设置方法
    修改php默认的FastCGI模式为ISAPI模式的方法
    VPS/云主机CPU占用100%故障排查
    APACHE服务器httpd.exe进程占用cpu100%的解决方法
    httpd.exe占用100%CPU
  • 原文地址:https://www.cnblogs.com/xingqi/p/6aa1f96cb301c7bfaebf7f1c4965fbca.html
Copyright © 2011-2022 走看看