iphone 开发笔记和技巧总结


1 iphone 开发笔记和技巧总结 http://www.cocoachina.com/bbs/read.php?tid=73570&uid=39045 iphone 程序中实现截屏的一种方法 在 iphone 程序中实现截屏的一种方法: //导入头文件 #import QuartzCore/QuartzCore.h // 将 整 个 self.view 大小的图层形式创建一张图片 image UIGraphicsBeginImageContext(self.view.bounds.size); [self.view.layer renderInContext : UIGraphicsGetCurrentContext()]; UIImage*image=UIGraphicsGetImageFromCurrentImageContext (); UIGraphicsEndImageContext(); //然后将该图片保存到图片图 UIImageWriteToSavedPhotosAlbum(image,self,nil,nil); 本帖属于 CocoaChina 会员发表,转帖请写明来源和帖子地址 截取屏幕图片 //创建一个基于位图的图形上下文并指定大小为 CGSizeMake(200,40 0) UIGraphicsBeginImageContext(CGSizeMake(200,400)); //renderInContext 呈现接受者及其子范围到指定的上下文 [self.view.layerrenderInContext:UIGraphicsGetCurrentContext()]; //返回一个基于当前图形上下文的图片 2 UIImage *aImage =UIGraphicsGetImageFromCurrentImageCo ntext(); //移除栈顶的基于当前位图的图形上下文 UIGraphicsEndImageContext(); //以 png 格式返回指定图片的数据 imageData = UIImagePNGRepresentation(aImage); 延时函数和 Timer 的使用 延时函数: [NSThread sleepForTimeInterval:5.0];//暂停 5s. Timer 的使用: NSTimer *connectionTimer; //timer 对象 //实例化 timer self.connectionTimer=[NSTimerscheduledTimerWithTimeInterva l:1.5 target:selfselector:@selector(timerFired:) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop]addTimer:self.connectionTimer forMode:NSDefaultRunLoopMode]; 3 //用 timer 作为延时的一种方法 do{ [[NSRunLoopcurrentRunLoop]runUntilDate:[NSDatedateWithTi meIntervalSinceNow:1.0]]; }while(!done); //timer 调用函数 -(void)timerFired:(NSTimer *)timer{ done =YES; } 启动界面的制作 iPhone 开发实现 splash 画面非常简单,做一个全屏的欢迎页的图片, 把它命名为 Default.png,然后放在 Xcode 工程的 Resource 里面。 在 XXXAppDelegate.m 程序中,插入如下代码: -(BOOL)application:(UIApplication*)application didFinishLaunchingWithOpti*****:(NSDictionary *)launchOpti***** { //–inserta delay of 5 seconds before the splash screendisappears– [NSThread sleepForTimeInterval:5.0]; 4 //Override point for customization after applicationlaunch. //Add the view controller’s view to the window anddisplay. [windowaddSubview:viewController.view]; [windowmakeKeyAndVisible]; return YES; } 这样 splash 页面就停留 5 秒后,消失了。 iphone 之启动界面 在 iphone 的启动应用之前,系统会默认在 Resources 文件夹中的 Default.png,为启动界面。 为了在 iPad 上使用上述的启动画面,你还需要在 info.plist 中加入 key: UISupportedInterfaceOrie ntati*****。 同时,加入值 UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight。 如果觉的启动界面时间比较短,也可以加入下面代码控制一下: 代码如下; -(BOOL)application:(UIApplication *)applicationdidFinishLaunchingWithOpti*****:(NSDictionary *)launchOpti*****{ [NSThread sleepForTimeInterval:3]; returnYES; 5 } iphone 项目的启动界面尺寸设为 320x480,系统自带的,进行加载。 格式和尺寸 图标和启动画面的图片格式:推荐使用 PNG 格式,可以是标准的 24 位色,外加 alpha 通道的 8 位。 iPhone/iPod Touch 的启动画面是全尺寸,iPad 的则要去掉状态栏的 高度 20px。 iPad 的启动画面是分模式的:竖排(portrait)和横排(landscape)。 iPhone4 和 ipod Touch4 有一个新特性:在屏幕尺寸不变的前提下, 分辨率提升一倍(320x480=>640x960)。此特性苹果命名为 Retina。 因此如果 app 要支持 Retina,就要提供分辨率宽高各增一倍的图片, 且为了兼顾没有 Retina 的设备,原来低分辨率的图片仍然要提供 。针 对不同分辨率的相同图片,苹果规定的命名规则是:高分辨率的文件名 比普通分辨率的文件名多“@2x”字样。 iPhone 上实现 Default.png 动画  原理:  添加一张和 Default.png 一样的图片,对这个图片进行动画,从 而实现 Default 动画的渐变消失的效果。 操作:  在 -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOpti*****:(NSDictionary *)launchOpti*****中添加如下代码:// Make this interesting.  UIImageView *splashView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0, 320, 480)]; splashView.image = [UIImage imageNamed:@"Default.png"];  [self.window addSubview:splashView]; [self.window bringSubviewToFront:splashView]; 6  [UIView beginAnimati*****:nil context:nil]; [UIView setAnimationDuration:2.0];  [UIView setAnimationTransition:UIViewAnimationTransitionNone forView: self.window cache:YES]; [UIView setAnimationDelegate:self];  [UIView setAnimationDidStopSelector:@selector(startupAnimationDo ne:finished:context:)]; splashView.alpha = 0.0;  splashView.frame = CGRectMake(-60, -85, 440, 635); [UIView commitAnimati*****];  就 ok 了 使用 NSTimer 与 iphone 的简单动画,实现飘雪效果 使用 NSTimer 与 iphone 的简单动画,实现飘雪效果,这理原理比较 简单,就是定时生成一定的雪花图片,然后使用动画的方式向下漂落(我 在其它论坛,看到使用 path 的方式实现的一个云漂来漂去的效果,实 际也可以用那种方式实现,这实际就是前面说的动画效果的两种应用)。 所以,我们可以在 viewDidLoad 事件中,增加一个图片及定时器并启 动,这里的 pic 请在头文件中定义。 -(void)viewDidLoad{ [super viewDidLoad]; self.pic = [UIImage imageNamed:@"snow.png"];//初始化图片 //启动定时器,实现飘雪效果 [NSTimer scheduledTimerWithTimeInterval:(0.2) target:self 7 selector:@selector(ontime) userInfo:nil repeats:YES]; } 然后再实现定时器定时调用的 ontime 方法: -(void)ontime{ UIImageView *view = [[UIImageView alloc] initWithImage:pic];// 声明一个 UIImageView 对象,用来添加图片 view.alpha = 0.5;//设置该 view 的 alpha 为 0.5,半透明的 int x = round(random()%320);//随机得到该图片的 x 坐标 int y = round(random()%320);//这个是该图片移动的最后坐标 x 轴 的 int s = round(random()%15)+10;//这个是定义雪花图片的大小 int sp = 1/round(random()%100)+1;//这个是速度 view.frame = CGRectMake(x, -50, s, s);//雪花开始的大小和位置 [self.view addSubview:view];//添加该 view [UIView beginAnimati*****:nil context:view];//开始动画 [UIView setAnimationDuration:10*sp];//设定速度 view.frame = CGRectMake(y, 500, s, s);//设定该雪花最后的消失坐 标 [UIView setAnimationDelegate:self]; [UIView commitAnimati*****]; } 使用 NSTimer 实现倒计时 今天在 CocoaChina 上面看到有人在问倒计时怎么做,记得以前在看 8 Iphone31 天的时候做过一个,今天翻出来运行不了了,原因是我的 IphoneSDK 升级到 3.1 了,以前使用的是 2.2.1,在 2.2.1 里面是可以使 用 NSCalendarDate 的,但是在 3.1 里面不能够使用,怎么办,只好用 NSTimer 了 , 最 后 还 是 给 实 现 了 。 代 码 也 比 较 简 单 , 开 始 运 行 viewDidLoad 的时候加载 [NSTimerscheduledTimerWithTimeInterval:1.0 target:selfselector:@selector(timerFireMethod:) userInfo:nilrepeats:YES];// 使用 timer 定时,每秒触发一次 ,然后就是写 selector 了。 -(void)timerFireMethod:(NSTimer*)theTimer { //NSDateFormatter *dateformatter =[[[NSDateFormatter alloc]init]autorelease];//定义 NSDateFormatter 用来显示格式 //[dateformatter setDateFormat:@"yyyy MM dd hh mmss"];//设定格式 NSCalendar *cal = [NSCalendarcurrentCalendar];//定义一个 NSCalendar 对象 NSDateComponents *shibo = [[NSDateComponentsalloc] init];//初始化目 标时间(好像是世博会的日期) [shibo setYear:2010]; [shibo setMonth:5]; 9 [shibo setDay:1]; [shibo setHour:8]; [shibo setMinute:0]; [shibo setSecond:0]; 10 NSDate *todate = [caldateFromComponents:shibo];//把目标时间装载入 date [shibo release]; // NSString *ssss = [dateformatterstringFromDate:dd]; // NSLog([NSString stringWithFormat:@"shiboshi:%@",ssss]); NSDate *today = [NSDate date];//得到当前时间 // NSString *sss = [dateformatterstringFromDate:today]; // NSLog([NSString stringWithFormat:@"xianzaishi:%@",sss]); //用来得到具体的时差 unsigned int unitFlags = NSYearCalendarUnit |NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit |NSMinuteCalendarUnit | NSSecondCalendarUnit; NSDateComponents *d = [cal components:unitFlagsfromDate:today toDate:todate opti*****:0]; lab.text = [NSStringstringWithFormat:@"%d 年%d 月%d 日%d 时%d 分 %d 秒",[d year],[d month], [d day],[d hour], [d minute], [d second]]; } 这样就实现了倒计时的功能. Iphone 幻灯片效果 代码很简单贴出来,以备不时只需: -(void)viewDidLoad { array = [[NSMutableArray alloc] init]; int i = 1; for(i;i<=30;i++) { [array addObject:[UIImageimageNamed:[NSString stringWithFormat:@"%d.jpg",i]]]; } 11 pictures.animationImages = array; pictures.animationDuration = 300;//时间间隔 pictures.animationRepeatCount = 0;//循环播放 [pictures startAnimating];//开始播放 NSTimer*timer = [NSTimerscheduledTimerWithTimeInterval: 1.5target: selfselector:@selector(logo:) userInfo: nilrepeats: YES]; [timer invalidate];//这句代码用来终止 timmer,否则,每过 1.5 秒, 就会执行该方法一次,我们是要在开始的时候执行一次就够了。 iphone 学习笔记 1。隐藏状态栏[[UIApplicationsharedApplication] setStatusBarHidden:YES]; /**************************************************************************** ** 1、取随机数: NSData *datanow = [NSData data]; int i = (int)datanow; srand(i); rand(); //int effectPicNum = rand()%7; **************************************************************************** **/ /**************************************************************************** ** 2、播放音乐: -(void) playMusic { @try{ //取文件路径 NSString *musicFilePath = [[NSBundle mainBundle] pathForResource:@"startLogo" ofType:@"mp3"]; NSURL*musicURL = [[NSURL alloc] initFileURLWithPath:musicFilePath]; musicPlayer= [[AVAudioPlayeralloc] initWithContentsOfURL:musicURL error:nil]; 12 [musicURL release]; //[musicPlayer prepareToPlay]; //[musicPlayer setVolume:1]; //设置音量大小 musicPlayer.numberOfLoops= 0;//设置播放次数,-1 为一直循环,0 为一次 [musicPlayerplay]; } @catch(NSException* e) { } } **************************************************************************** **/ /**************************************************************************** ** 3、每隔 0.8 秒执行 timeCount 方法: NSTimer*countTimer; countTimer= [NSTimerscheduledTimerWithTimeInterval: 0.8target: selfselector: @selector(timeCount:) userInfo: nilrepeats:YES]; [countTimerfire];//执行 timer **************************************************************************** **/ /**************************************************************************** ** 4、延迟 1 秒执行 test 方法: [selfperformSelector:@selector(test) withObject:nilafterDelay:0.1]; **************************************************************************** **/ 6、获取文件路径: //通过 NSHomeDirectory 获得文件路径 NSString *homeDirectory = NSHomeDirectory(); NSString *fileDirectory = [homeDirectory stringByAppendingPathComponent:@"temp/app_data.plist"]; //使用 NSSearchPathForDirectoriesInDomains 检索指定路径 NSArray*path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES); //常量 NSDocumentDirectory 表示正在查找 Documents 目录的路径(使用 NSCachesDirectory 表明 要查找的时 Caches 文件夹),常量 NSUserDomainMask 表明我们希望将搜索限制于我们应用程 序的沙盒,最后一个参数决定了是否“展开”波浪线符号。 //在 Mac 系统中,‘~’表示主路经(Home),如果不展开,路径看起来就是:‘~/Documents’,展开 后即得到完整路径。这个参数一直设置位真即可。 NSString *documentsDirectory = [paths objectAtIndex:0];z NSString *fileDirectory = [documentsDirectory stringByAppendingPathComponent:@"file.txt"]; //使用 Foundation 中的 NSTemporaryDirectory 函数直接返回代表 temp 文件夹的全路径的字符串 对象 13 NSString *tempDirectory = NSTemporaryDirectory(); NSString*file = [tempDirectory stringByAppendingPathComponent:@"file.txt"]; Example: NSArray*path = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *docDir = [path objectAtIndex:0]; NSLog(@"filepath:%@",docDir); NSString*str = @"hello.jpg"; NSString*filepath = [docDir stringByAppendingPathComponent:str]; //NSString *filepath = [docDir stringByAppendingPathComponent:[NSString stringWithUTF8String:"///mest.txt"]]; NSLog(@"filepath:%@",filepath); BOOLsuccess = [[NSFileManagerdefaultManager]createFileAtPath: filepath contents:nilattributes:nil]; NSLog(@"result",success); printf("Create File:%s %s.",[filepath UTF8String], success ?"Success":"Error"); NSString* reValue= [NSString stringWithString:@"\"success\""]; NSLog(reValue); ******************************************************************************/ /********************************************************************************* *************************************************************************** 7 文件、文件夹操作 //如果"/Documents/Theme"路径不存在,则创建。 if(![[NSFileManagerdefaultManager]fileExistsAtPath:themePath]) { [[NSFileManagerdefaultManager] createDirectoryAtPath:themePath attributes:nil]; } //删除已存在的同名文件夹 if([[NSFileManagerdefaultManager] fileExistsAtPath:savePath]) { [[NSFileManagerdefaultManager] removeItemAtPath:savePath error:NULL]; } ********************************************************************************** **************************************************************************/ /********************************************************************************* *************************************************************************** 7 子线程抛给主线程: [selfperformSelectorOnMainThread:@selector(shiftView) withObject:nilwaitUntilDone:YES]; ********************************************************************************** **************************************************************************/ /********************************************************************************* *************************************************************************** 8 获取当前时间 NSDateFormatter*formatter = [[NSDateFormatteralloc] init]; [formatter setDateFormat:@"yyyy-MM-dd hh:mm:ss"]; NSString *locati*****tring=[formatter stringFromDate:[NSDate date]]; 14 //获取当前时间作为 productId NSDateFormatter*formatter = [[NSDateFormatteralloc] init]; [formatter setDateFormat:@"hhmmss"]; NSString *locati*****tring=[formatter stringFromDate:[NSDate date]]; downloadInfo.productId = locati*****tring; [formatter release]; 写入 plist 文件: NSMutableDictionary* dict = [[ NSMutableDictionaryalloc ] initWithContentsOfFile:@"/Sample.plist"]; [ dict setObject:@"Yes"forKey:@"RestartSpringBoard"]; [ dict writeToFile:@"/Sample.plist"atomically:YES]; 读取 plist 文件: NSMutableDictionary* dict = [[ NSMutableDictionaryalloc ] initWithContentsOfFile:@"/Sample.plist"]; NSString* object = [ dict objectForKey:@"RestartSpringBoard" ]; UIView 翻转效果实现 新建一个 view-based 模板工程,在 ViewController 文件中添加下面 的代码,即可实现翻转效果; -(void)viewDidLoad { [super viewDidLoad]; //需要翻转的视图 UIView *parentView = [[UIView alloc] initWithFrame:CGRectMake(0, 150, 320, 200)]; parentView.backgroundColor = [UIColor yellowColor]; parentView.tag = 1000; [self.view addSubview:parentView]; } //需要在 h 头文件声明下面的动作响应函数 //在 xib 文件中添加一个 button,其响应函数为下面的函数 //运行程序后,点击 button 就看到翻转效果 15 -(IBAction)ActionFanzhuan{ //获取当前画图的设备上下文 CGContextRef context = UIGraphicsGetCurrentContext(); //开始准备动画 [UIView beginAnimati*****:nil context:context]; //设置动画曲线,翻译不准,见苹果官方文档 [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; //设置动画持续时间 [UIView setAnimationDuration:1.0]; //因为没给 viewController 类添加成员变量,所以用下面方法得到 viewDidLoad 添加的子视图 UIView *parentView = [self.view viewWithTag:1000]; //设置动画效果 [UIView setAnimationTransition: UIViewAnimationTransitionCurlDown forView:parentView cache:YES]; //从上向下 //[UIView setAnimationTransition: UIViewAnimationTransitionCurlUp forView:parentView cache:YES]; //从下向上 //[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromLeft forView:parentView cache:YES]; //从左向右 //[UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView:parentView cache:YES];//从右向左 //设置动画委托 [UIView setAnimationDelegate:self]; 16 //当动画执行结束,执行 animationFinished 方法 [UIView setAnimationDidStopSelector:@selector(animationFinished:)]; //提交动画 [UIView commitAnimati*****]; } //动画效果执行完毕 -(void) animationFinished: (id) sender{ NSLog(@"animationFinished !"); } 运行程序,点击按钮,就能看到动画效果了 让一个 UIImageView 响应点击事件 UIImageView *imgView =[[UIImageView alloc] initWithFrame:CGRectMake(0, 0,320, 44)]; imgView.userInteractionEnabled=YES; UITapGestureRecognizer *singleTap =[[UITapGestureRecognizer alloc]initWithTarget:selfaction:@selector(onClickImage)]; [imgView addGestureRecognizer:singleTap]; [singleTap release]; -(void)onClickImage{ // here, do whatever you wantto do NSLog(@"imageview is clicked!"); } 17 iphone 调用系统电话、浏览器、地图、邮件等 openURL 的使用方法: view plaincopy toclipboardprint? [[UIApplication sharedApplication] openURL:[NSURL URLWithString:appString]]; 其中系统的 appString 有: view plaincopy toclipboardprint? 1.Map http://maps.google.com/maps?q=Shanghai 2.Email mailto://myname@google.com 3.Tel tel://10086 4.Msg sms://10086 openURL 能帮助你运行 Maps,SMS,Browser,Phone 甚至其他的应用程 序。这是 Iphone 开发中我经常需要用到的一段代码,它仅仅只有一行而 已。 -(IBAction)openMaps { //打开地图 NSString*addressText = @"beijing"; //@"1Infinite Loop, Cupertino, CA 95014"; addressText =[addressTextstringByAddingPercentEscapesUsingEncoding:NSASCIIStrin gEncoding]; NSString*urlText = [NSStringstringWithFormat:@"http://maps.google.com/maps?q=%@",addre ssText]; NSLog(@"urlText=============== %@", urlText); [[UIApplicati*****haredApplication] openURL:[NSURL URLWithString:urlText]]; } -(IBAction)openEmail { //打开 mail // Fire off an email to apple support [[UIApplication sharedApplication]openURL:[NSURL URLWithString:@"mailto://devprograms@apple.com"]]; } -(IBAction)openPhone { 18 //拨打电话 // CallGoogle 411 [[UIApplication sharedApplication] openURL:[NSURLURLWithString:@"tel://8004664411"]]; } -(IBAction)openSms { //打开短信 // Text toGoogle SMS [[UIApplication sharedApplication] openURL:[NSURLURLWithString:@"sms://466453"]]; } -(IBAction)openBrowser { //打开浏览器 // Lanuch any iPhone developers fav site [[UIApplication sharedApplication] openURL:[NSURLURLWithString:@"http://itunesconnect.apple.com"]]; } iphone 程序内调用谷歌地图 使 用 CLLocationManager 类 , MKMapView 。 并 且 实 现 //初始化 CLLocationManager,CLLocationManager 获得当前地理 坐标 locmanager=[[CLLocationManager alloc]init]; [locmanager setDelegate:self]; //设置精确度 [locmanager setDesiredAccuracy:kCLLocationAccuracyBest]; [locmanagerstartUpdatingLocation]; 执行完以后,会自动调用代理方法: 19 在代理方法: -(void)locationManager:(CLLocationManager *)managerdidUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation *)oldLocation{ //初始化矩形大小 CGRect rect=CGRectMake(0,0,320,460); //设置地图大小为矩形大小 map=[[MKMapView alloc] initWithFrame:rect]; CLLocationCoordinate2Dloc=[newLocation coordinate]; lat=loc.latitude; lon=loc.longitude; //coordinate 坐标 CLLocationCoordinate2DtheCoordinate; CLLocationCoordinate2DtheCenter; //theCoordinate.latitude=lat; //theCoordinate.longitude=lon; theCoordinate=loc; [map setDelegate:self]; //设置地图显示的类型,有卫星地图,道路,等 [map setMapType:MKMapTypeStandard]; //[mapsetMapType:MKMapTypeSatellite]; //区域坐标 Region(区域,地域) MKCoordinateRegiontheRegin; 20 //theCenter.latitude=lat; //theCenter.longitude=lon; theCenter=loc; theRegin.center=theCenter; //坐标间距(span:间隔,间距) MKCoordinateSpantheSpan; theSpan.latitudeDelta=0.1; theSpan.longitudeDelta=0.1; //设置地图显示的区域, theRegin.span=theSpan; //[mapsetRegion:theRegin]; [map regionThatFits:theRegin]; map.showsUserLocation=YES; [self.viewaddSubview:map]; } -(MKAnnotationView *)mapView:(MKMapView *)mapViewviewForAnnotation:(id)annotation{ NSLog(@"-------viewForAnnotation-------"); //此类可以显示针一样的图标 MKPinAnnotationView*newAnnotation=[[MKPinAnnotationView alloc] initWithAnnotation:annotationreuseIdentifier:@"annotation1"]; //newAnnotation.animatesDrop=YES; //newAnnotation.animatesDrop=NO; 21 newAnnotation.pinColor=MKPinAnnotationColorPurple; //显示标志提示 newAnnotation.canShowCallout=YES; return newAnnotation; } UIPageControl 实现自定义按钮 有时候 UIPageControl 需要用到白色的背景, 那么会导致上面的点按钮看不见或 不清楚, 我们可以通过继承该类重写函数来更换点按钮的图片现实. 实现思路如下. 新建类继承 UIPageControl : @interface MyPageControl : UIPageControl { UIImage*imagePageStateNormal; UIImage*imagePageStateHighlighted; } -(id)initWithFrame:(CGRect)frame; @property (nonatomic, retain) UIImage*imagePageStateNormal; @property (nonatomic, retain) UIImage*imagePageStateHighlighted; @end 声明了初始化该类的函数 用了两个 UIImage 保存两张图片, 大家知道的, UIPageCotrol 的按钮分为两态, 一个是正常, 一个是高亮 接下来实现该类以及重写父类方法: @interfaceMyPageControl(private) // 声明一个私有方法, 该方法不允许对 象直接使用 22 -(void)updateDots; @end @implementation MyPageControl //实现部分 @synthesize imagePageStateNormal; @synthesize imagePageStateHighlighted; -(id)initWithFrame:(CGRect)frame {// 初始化 self = [superinitWithFrame:frame]; return self; } -(void)setImagePageStateNormal:(UIImage*)image {// 设置正常状态 点按钮的图片 [imagePageStateNormalrelease]; imagePageStateNormal= [image retain]; [self updateDots]; } -(void)setImagePageStateHighlighted:(UIImage *)image {// 设置高亮状 态点按钮图片 [imagePageStateHighlightedrelease]; imagePageStateHighlighted= [image retain]; [self updateDots]; } -(void)endTrackingWithTouch:(UITouch*)touch withEvent:(UIEvent *)event {// 点击事件 [superendTrackingWithTouch:touch withEvent:event]; [self updateDots]; } 23 -(void)updateDots {// 更新显示所有的点按钮 if(imagePageStateNormal || imagePageStateHighlighted) { NSArray*subview = self.subviews; // 获取所有子视图 for(NSInteger i = 0; i < [subview count]; i++) { UIImageView*dot = [subview objectAtIndex:i]; // 以下不解 释, 看了基本明白 dot.image= self.currentPage == i ? imagePageStateNormal : imagePageStateHighlighted; } } } -(void)dealloc {// 释放内存 [imagePageStateNormalrelease], imagePageStateNormal = nil; [imagePageStateHighlightedrelease], imagePageStateHighlighted = nil; [super dealloc]; } @end OK, 在添加处加入以下来实例化该对象代码: MyPageControl *pageControl =[[MyPageControl alloc] initWithFrame:CGRectMake(0,0, 200, 30)]; pageControl.backgroundColor = [UIColorclearColor]; pageControl.numberOfPages = 5; pageControl.currentPage = 0; [pageControlsetImagePageStateNormal:[UIImageimageNamed:@"pag eControlStateNormal.png"]]; 24 [pageControl setImagePageStateHighlighted:[UIImageimageNamed:@"pageControlS tateHighlighted.png"]]; [self.view addSubview:pageControl]; [pageControl release]; http://www.cocoachina.com/bbs/read.php?tid=73570&uid=39045&page=3 UIView 中 bounds 和 frame 的差别? 很明显,bounds 的原点是(0,0)点,而 frame 的原点却是任意的。 frame 如果一个按钮,是在表格里,按钮的 frame 的坐标也是相对的, 并不是相对屏幕,也就是说是相对坐标,不是绝对坐标。 frame 是相对坐标。bounds 是绝对坐标。 Android 的开发过程中,绝对坐标,这样画出来的位置都是相对于屏幕 的而不是相对于控件的 什么是绝对坐标值,相对坐标值? 绝对坐标是:X,Y 就是相对于坐标原点的。 例如(15,20)相对坐标是:@X,Y 就是相对于参考点(可以是自 己设定的一个点)。 例如(15,20)相对于参考点(1,1)的坐标,表示:@14,19 (15,20)相对于参考点(-1,-1)的坐标,表示:@16,21 bounds 是指这个 view 在它自己坐标系的坐标和大小 而 frame 指的是 这个 view 在它 superview 的坐标系的坐标和大小. 区别主要在坐标系这一块。 很明显一个是自己为原点的坐标系,一个是以屏幕为原点的坐标系。 [ 此帖被 haoxue 在2011-11-26 16:12重新编辑 ] 25 图片:frame_bounds_rects.jpg 设置透明度 [myView setAlpha:value]; (0.0 < value < 1.0) 设置背景色 1 [myView setBackgroundColor:[UIColorredCol or]]; (blackColor;darkGrayColor;lightGrayColor;whiteColor;grayColor; redColor; green Color; blueColor; cyanColor;yellowColor;magentaColor; 3 orangeColor;purpleColor;brownColor; clearCo lor; ) 自定义颜色: 1 UIColor*newColor = [[UIColor alloc] initWithRed:(float) green:(float) blue:(floa t) alpha:(float)]; 0.0~1.0 26 宽度和高度 1 768X1024 1024X768 状态栏高 20 像素高 导航栏 工具栏 44 像素高 隐藏状态栏: 1 [[UIApplication shareApplication] setStatusBarHidden: YES animat ed:NO] iphone 界面如何实现下拉列表 代码如下: #import @interface DropDownList : UIView { UITextField* textField; //文本输入框 NSArray* list; //下拉列表数据 BOOL showList; //是否弹出下拉列表 UITableView* listView; //下拉列表 CGRect oldFrame,newFrame; //整个控件(包括下拉前和下拉 后)的矩形 UIColor *lineColor,*listBgColor;//下拉框的边框色、背景色 CGFloat lineWidth; //下拉框边框粗细 UITextBorderStyle borderStyle; //文本框边框 style } @property (nonatomic,retain)UITextField *textField; @property(nonatomic,retain)NSArray* list; @property (nonatomic,retain)UITableView* listView; 27 @property (nonatomic,retain)UIColor *lineColor,*listBgColor; @property (nonatomic,assign)UITextBorderStyle borderStyle; -(void)drawView; -(void)setShowList:(BOOL)b; @end #import "DropDownList.h" @implementationDropDownList @synthesize textField,list,listView,lineColor,listBgColor,borderStyle; -(id)initWithFrame:(CGRect)frame { if(self=[super initWithFrame:frame]){ //默认的下拉列表中的数据 list=[[NSArray alloc]initWithObjects:@"1",@"2",@"3",@"4",nil]; borderStyle=UITextBorderStyleRoundedRect; showList=NO;//默认不显示下拉框 oldFrame=frame; //未下拉时控件初始大小 //当下拉框显示时,计算出控件的大小。 newFrame=CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height*5); lineColor=[UIColor lightGrayColor];//默认列表边框线为灰色 28 listBgColor=[UIColor whiteColor];//默认列表框背景色为白色 lineWidth=1;//默认列表边框粗细为 1 //把背景色设置为透明色,否则会有一个黑色的边 self.backgroundColor=[UIColor clearColor]; [self drawView];//调用方法,绘制控件 } returnself; } -(void)drawView{ //文本框 textField=[[UITextField alloc] initWithFrame:CGRectMake(0, 0, oldFrame.size.width, oldFrame.size.height)]; textField.borderStyle=borderStyle;//设置文本框的边框风格 [self addSubview:textField]; [textField addTarget:self action:@selector(dropdown) forControlEvents:UIControlEventAllTouchEvents]; //下拉列表 listView=[[UITableView alloc]initWithFrame: CGRectMake(lineWidth,oldFrame.size.height+lineWidth, oldFrame.size.width-lineWidth*2, oldFrame.size.height*4-lineWidth*2)]; listView.dataSource=self; 29 listView.delegate=self; listView.backgroundColor=listBgColor; listView.separatorColor=lineColor; listView.hidden=!showList;//一开始 listView 是隐藏的,此后根 据 showList 的值显示或隐藏 [self addSubview:listView]; [listView release]; } -(void)dropdown{ [textField resignFirstResponder]; if(showList) {//如果下拉框已显示,什么都不做 return; }else{//如果下拉框尚未显示,则进行显示 //把 dropdownList 放到前面,防止下拉框被别的控件遮住 [self.superview bringSubviewToFront:self]; [self setShowList:YES];//显示下拉框 } } #pragma mark listViewdataSource method and delegate method -(NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section{ return list.count; } -(UITableViewCell*)tableView:(UITableView *)tableView 30 cellForRowAtIndexPath:(NSIndexPath *)indexPath{ static NSString *cellid=@"listviewid"; UITableViewCell* cell=[tableView dequeueReusableCellWithIdentifier:cellid]; if(cell==nil){ cell=[[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellid]autorelease]; } //文本标签 cell.textLabel.text=(NSString*)[list objectAtIndex:indexPath.row]; cell.textLabel.font=textField.font; cell.selecti*****tyle=UITableViewCellSelecti*****tyleGray; return cell; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ return oldFrame.size.height; } //当选择下拉列表中的一行时,设置文本框中的值,隐藏下拉列表 -(void)tableView:(UITableView *)tableViewdidSelectRowAtIndexPath:(NSIndexPath *)indexPath{ //NSLog(@"select"); textField.text=(NSString*)[list objectAtIndex:indexPath.row]; //NSLog(@"textField.text=%@",textField.text); [self setShowList:NO]; 31 } -(BOOL)showList{//setShowList:No 为隐藏,setShowList:Yes 为显示 return showList; } -(void)setShowList:(BOOL)b{ showList=b; NSLog(@"showlist is set "); if(showList){ self.frame=newFrame; }else { self.frame=oldFrame; } listView.hidden=!b; } /* // Only override drawRect: if you perform custom drawing. // An empty implementation adversely affects performance during animation. -(void)drawRect:(CGRect)rect { // Drawing code. } */ -(void)dealloc { [super dealloc]; } @end 32 iOS Programming – 触摸事件处理 iphone/ipad 无键盘的设计是为屏幕争取更多的显示空间,大屏幕在观 看图片、文字、视频等方面为用户带来了更好的用户体验。而触摸屏幕 是 iOS 设备接受用户输入的主要方式,包括单击、双击、拨动以及多点 触摸等,这些操作都会产生触摸事件。 在 Cocoa 中,代表触摸对象的类是 UITouch。当用户触摸屏幕后,就 会产生相应的事件,所有相关的 UITouch 对象都被包装在事件中,被程 序交由特定的对象来处理。UITouch 对象直接包括触摸的详细信息。 UITouch 类中包含 5 个属性: window:触摸产生时所处的窗口。由于窗口可能发生变化,当前所 在的窗口不一定是最开始的窗口。 view:触摸产生时所处的视图。由于视图可能发生变化,当前视图也不 一定时最初的视图。 tapCount:轻击(Tap)操作和鼠标的单击操作类似,tapCount 表 示短时间内轻击屏幕的次数。因此可以根据 tapCount 判断单击、双击 或更多的轻击。 times*****p:时间戳记录了触摸事件产生或变化时的时间。单位是秒。 phase:触摸事件在屏幕上有一个周期,即触摸开始、触摸点移动、触 摸结束,还有中途取消。而通过 phase 可以查看当前触摸事件在一个 周期中所处的状态。phase 是 UITouchPhase 类型的,这是一个枚举 配型,包含了  UITouchPhaseBegan(触摸开始)  UITouchPhaseMoved(接触点移动)  UITouchPhaseStationary(接触点无移动)  UITouchPhaseEnded(触摸结束)  UITouchPhaseCancelled(触摸取消) UITouch 类中包含如下成员函数: -(CGPoint)locationInView:(UIView *)view:函数返回一个 CGPoint 类型的值,表示触摸在 view 这个视图上的位置,这里返回的位置是针 对 view 的坐标系的。调用时传入的 view 参数为空的话,返回的时触 摸点在整个窗口的位置。 33 -(CGPoint)previousLocationInView:(UIView *)view:该方法记录了 前一个坐标值,函数返回也是一个 CGPoint 类型的值, 表示触摸在 view 这个视图上的位置,这里返回的位置是针对 view 的坐标系的。调 用时传入的 view 参数为空的话,返回的时触摸点在整个窗口的位置。 当手指接触到屏幕,不管是单点触摸还是多点触摸,事件都会开始,直 到用户所有的手指都离开屏幕。期间所有的 UITouch 对象都被包含在 UIEvent 事件对象中,由程序分发给处理者。事件记录了这个周期中所 有触摸对象状态的变化。 只要屏幕被触摸,系统就会报若干个触摸的信息封装到 UIEvent 对象中 发送给程序,由管理程序 UIApplication 对象将事件分发。一般来说, 事件将被发给主窗口,然后传给第一响应者对象(FirstResponder)处理。 关于响应者的概念,通过以下几点说明: 响应者对象(Resp*****e object) 响应者对象就是可以响应事 件并对事件作出处理。在 iOS 中,存在 UIResponder 类,它定义了响 应者对象的所有方法。UIApplication、UIView 等类都继承了 UIResponder 类,UIWindow 和 UIKit 中的控件因为继承了 UIView, 所以也间接继承了 UIResponder 类,这些类的实例都可以当作响应者。 第一响应者(First responder) 当前接受触摸的响应者对象被称为第一响应者,即表示当前该对象正 在与用户交互,它是响应者链的开端。 响应者链(Responder chain) 响应者链表示一系列的响应者对 象。事件被交由第一响应者对象处理,如果第一响应者不处理,事件被 沿着响应者链向上传递,交给下一个响应者(next responder)。一般 来说,第一响应者是个视图对象或者其子类对象,当其被触摸后事件被 交由它处理,如果它不处理,事件就会被传递给它的视图控制器对象(如 果存在),然后是它的父视图(superview)对象(如果存在),以此类 推,直到顶层视图。接下来会沿着顶层视图(top view)到窗口 (UIWindow 对象)再到程序(UIApplication 对象)。如果整个过程都 没有响应这个事件,该事件就被丢弃。一般情况下,在响应者链中只要 由对象处理事件,事件就停止传递。但有时候可以在视图的响应方法中 根据一些条件判断来决定是否需要继续传递事件。 34 管理事件分发 视图对触摸事件是否需要作处回应可以通过设置 视图的 userInteractionEnabled 属性。默认状态为 YES,如果设置为 NO,可以阻止视图接收和分发触摸事件。除此之外,当视图被隐藏 (setHidden:YES)或者透明(alpha 值为 0)也不会收事件。不过 这个属性只对视图有效,如果想要整个程序都步响应事件,可以调用 UIApplication 的 beginIngnoringInteractionEvents 方法来完全停止 事件接收和分发。通过 endIngnoringInteractionEvents 方法来恢复让 程序接收和分发事件。 如果要让视图接收多点触摸,需要设置它的 multipleTouchEnabled 属 性为 YES,默认状态下这个属性值为 NO,即视图默认不接收多点触摸 关于 UIView 的 userInteractionEnabled 属性 如果父视图为 ParentView 包含一个 Button,如果再 ParentView 上添 加子视图 ChildView,且 ChildView 盖住了 Button,那么 Button 就 得到不响应了, 为了让 Button 响应,可以设置 ChildView 的 userInteractionEnabled = NO;最近被这个问题困扰了很久,开始想用事件传递的方法, 重写类继承自 UIView,最后被这简单属性搞定了.... 键盘透明 textField.keyboardAppearance = UIKeyboardAppearanceAlert; 状态栏的网络活动风火轮是否旋转 [UIApplication sharedApplication].networkActivityIndicatorVisible,默认值是 NO。 35 更改 cell 选中的背景 UIView *myview = [[UIView alloc] init]; myview.frame = CGRectMake(0, 0, 320, 47); myview.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"0006.png"]]; cell.selectedBackgroundView = myview; iPhone 键盘改变颜色 只 有 这 2 种 数 字 键 盘 才 有 效 果 : UIKeyboardTypeNumberPad , UIKeyboardTypePhonePad keyboardAppearance = UIKeyboardAppearanceAlert 代码如下: NSArray *ws = [[UIApplication sharedApplication] windows]; for(UIView *w in ws){ NSArray *vs = [w subviews]; for(UIView *v in vs){  if([[NSString stringWithUTF8String:object_getClassName(v)] isEqualToString:@"UIKeyboard"]){  v.backgroundColor = [UIColor redColor];  }  }  } 从一个界面 push 到下一界面左上角返回按钮文字设置 在父 viewController 中如下设置: UIBarButtonItem *backbutton = [[UIBarButtonItem alloc]init]; 36 backbutton.title = @"返回列表"; self.navigationItem.backBarButtonItem = backbutton; [backbutton release]; navigationbar 的 back 键触发其他事件 UIButton *back =[[UIButton alloc] initWithFrame:CGRectMake(200, 25, 63, 30)]; [back addTarget:self act ion:@selector(reloadRowData:) forControlEvents:UIControlEventTouchUpInside]; [back setImage:[UIImage imageNamed:@"返回按钮.png"] forState:UIControlStateNormal]; UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:back]; self.navigationItem.leftBarButtonItem = loginButtonItem [back release]; [backButtonItem release]; 修改 UINavigationController 中 leftBarButtonItem 按钮的 title 新写的App中需要使用UINavigationController对各个页面进行导 航,但由于第一级页面的 title 较长,在进入第二级页面后返回按钮 leftButtonItem 的 title 就会变得很长,对 NavigationBar 空间占用很大, 而且不美观,于是使用代码对 leftButtonItem 的 title 文本进行修改,无 论是设置 self.navigationItem.leftBarButtonItem.title = @"返回";还 是 self.navigationItem.backBarButtonItem.title = @"返回";都没有 效果,title 文本始终不会发生变化。到网上乱搜一通后,得到了以下解 决方法,相对来说比较简单,特记录如下: 在第一级页面的 viewDidLoad 方法中加入以下代码: UIBarButtonItem *temporaryBarButtonItem = [[UIBarB 37 uttonItem alloc] init]; temporaryBarButtonItem.title = @"返回"; self.navigationItem.backBarButtonItem = temporaryBarB uttonItem; [temporaryBarButtonItem release]; 也就是用一个新的按钮在进行导航前将原来的返回按钮替换掉就 可以了。 本文出自 “一叶障目” 博客,请务必保留此出处 http://ddkangfu.blog.51cto.com/311989/459641 //防止屏幕暗掉锁屏 [[UIApplication sharedApplication] setIdleTimerDisabled:YES]; //将图片从左到右翻页效果显示 UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 0, 470)]; [imageView setImage:[UIImage imageNamed:@"Bg.jpg"]]; self.myImageView =imageView; [self.view addSubview:imageView]; [imageView release]; CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimati*****:nil context:context]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.5]; [myImageView setFrame:CGRectMake(0, 0, 310, 470)]; [UIView commitAnimati*****]; 让覆盖在下面层的视图接受触摸事件 searchImage.exclusiveTouch = YES;//第一层 searchImage.userInteractionEnabled = NO; myMapView.exclusiveTouch = NO;//第二层 38 myMapView.userInteractionEnabled = YES; View 的缩放 NSValue *touchPointValue = [[NSValue valueWithCGPoint:CGPointMake(100,100)] retain]; [UIView beginAnimati*****:nil context:touchPointValue]; transform = CGAffineTransformMakeScale(0.1,0.21); firstPieceView.transform = transform; [UIView commitAnimati*****]; 点击 UITextView 输入文字,光标都从最初点开始 能让用户点击 UITextView 输入文字时,光标都从最初点开始 -(void)textViewDidChangeSelection:(UITextView *)textView { NSRange range; range.location = 0; range.length = 0; textView.selectedRange = range; } PS:UITextView 有一个小 BUG,如果其高度小于 50 的话,输入的时候其光标会往上偏移,从而 看不到光标,如果大于 50 就不会出现这个问题。 UITextView 在光标处添加文字 // 获得光标所在的位置 int location =contentTextView.selectedRange.location; // 将 UITextView 中的内容进行调整(主要是在光标所在的位置进行字 符串截取,再拼接你需要插入的文字即可) 39 NSString *content = contentTextView.text; NSString *result = [NSStringstringWithFormat:@"%@[ 姓 名 变 量]%@",[content substringToIndex:location], [content substringFromIndex:location]]; // 将调整后的字符串添加到 UITextView 上面 contentTextView.text = result; 如何设置 UITextView 的光标位置 UITextView * m_textInput; //设置光标到输入文字的末尾 NSUInteger length = m_textInput.text.length; m_textInput.selectedRange = NSMakeRange(length,0); UITextView 方法 用法 UITextView 限制行数的问题之前试了好多方法,最终解决了,解决方法非常简单, 在 UITextViewDelegate 中加下面的方法即可: -(BOOL)textView:(UITextView *)textViewshouldChangeTextInRange:(NSRange)range replacementText:(NSString*)text { if (textView.contentSize.height > 104){ textView.text = [textView.text substringToIndex:[textView.textlength]-1]; returnNO; } return YES; } 40 -(void)textViewDidChangeSelection:(UITextView*)textView 每次输入都知道 [textView becomeFirstResponder] (void)textViewDidChange:(UITextView*)textView 当 textView 的内 容发生改变时,会调用。。再此计算已经输入的字符个数。 -(BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)rangereplacementText:(NS String *)text; { if([@"\n" isEqualToString:text] == YES) { [textViewresignFirstResponder]; returnNO; } returnYES; } -(BOOL)textView:(UITextView*)textView shouldChangeTextInRange:(NSRange)rangereplacementText:(NS String *)text; ctextview 根据光标插入数据 UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; //定位光标 41 NSRange range = [opinion selectedRange]; NSMutableString *top = [[NSMutableString alloc] initWithString:[opinion text]]; NSString *addName = [NSString stringWithFormat:@"%@、 ",cell.textLabel.text]; [top insertString:addName atIndex:range.location]; opinion.text = top; [top release]; iphone 中的 UITouch 手指在屏幕上能达到的精度和鼠标指针有很大的不同。当用户触击屏幕 时,接触 区域实际上是椭圆形的,而且比用户想像的位置更靠下一点。根据 触摸屏幕的手指、手指的尺寸、手指接触屏幕的力量、手指的方向、以 及其它因素的不同, 其“接触部位”的尺寸和形状也有所不同。底层的多点触摸系统会分析所 有的这些信息,为您计算出单一的触点。 UIResponder 是所有响应者对象的基类, 它不仅为事件处理,而且也为常见的响应者行为定义编程接口。 UIApplication、UIView、和所有从 UIView 派生出来的 UIKit 类(包括 UIWindow)都直接或间接地继承自 UIResponder 类。 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { UITouch* touch = [touches anyObject]; NSUInteger numTaps = [touch tapCount]; if (numTaps < 2) { [self.nextResponder touchesBegan:touches withEvent:event]; } else { [self handleDoubleTap:touch]; } } 42 缺省情况下,视图会接收触摸事件。但是,您可以将其 userInteractionEnabled 属性声明设置为 NO,关闭事件传递的功能。 在一定的时间内关闭事件的传递。应用程序可以调用 UIApplication 的 beginIgnoringInteractionEvents 方法,并在随后调用 endIgnoringInteractionEvents 方法来实现这个目的。 缺省情况下,视图只接收多点触摸序列的第一个触摸事件,而忽略 所有其它事件。如果您希望视图处理多点触摸,就必须使它启用这 个功能。在代码或 Interface Builder 的查看器窗口中将视图的 multipleTouchEnabled 属性设置为 YES,就可以实现这个目标。 将事件传递限制在某个单独的视图上。缺省情况下,视图的 exclusiveTouch 属性被设置为 NO。将这个属性设置为 YES 会使相应的 视图具有这样的特性:即当该视图正在跟踪触摸动作时,窗口中的其它 视图无法同时进行跟踪,它们不能接收到那些触摸事件。 多点触摸: -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 当一个或多个手指触碰屏幕时,发送 touchesBegan:withEvent:消息。 当一个或多个手指在屏幕上移动时,发送 touchesMoved:withEvent: 消息。 当一个或多个手指离开屏幕时,发送 touchesEnded:withEvent:消息。 当触摸序列被诸如电话呼入这样的系统事件所取消时,发送 touchesCancelled:withEvent:消息。 上面这些方法都和特定的触摸阶段(比如 UITouchPhaseBegan)相 关联,该信息存在于 UITouch 对象的 phase 属性声明中。 为了处理给定阶段的事件,响应者对象常常从传入的集合参数中取 得一或多个 UITouch 对象,然后考察这些对象的属性或取得它们的位置 43 (如果需要处理所有触摸对象,可以向该 NSSet 对象发送 anyObject 消 息)。UITouch 类中有一个名为 locationInView:的重要方法,如果传入 self 参数值,它会给出触摸动作在响应者坐标系统中的位置(假定该响 应者是一个 UIView 对象,且传入的视图参数不为 nil)。另外,还有一 个与之平行的方法,可以给出触摸动作之前位置 (previousLocationInView:)。UITouch 实例的属性还可以给出发生多少 次触 碰(tapCount)、触摸对象的创建或最后一次变化发生在什么时间 (times*****p)、以及触摸处于什么阶段(phase)。 -(void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { UITouch *touch = [touches anyObject]; if ([touch tapCount] == 2) { CGPoint tapPoint = [theTouch locationInView:self]; // Process a double-tap gesture } } 在 touchesEnded:withEvent:方法中,当触击次数为一时,响应者对 象就向自身发送一个 performSelector:withObject:afterDelay:消息,其中的 选择器标识由响应者对象实现的、用于处理单击手势的方法;第二个参 数是一个 NSValue 或 NSDictionary 对象,用于保存相关的 UITouch 对 象;时延参数则表示单击和双击手势之间的合理时间间隔。 在 touchesBegan:withEvent:方法中,如果触击次数为二,响应者对 象会向自身发送一个 cancelPreviousPerformRequestsWithTarget:消息,取 消当前被挂起和延期执行的调用。如果触碰次数不为二,则在指定的延 时之后,先前步骤中由选择器标识的方法就会被调用,以处理单击手势。 Iphone 开发-NSRunLoop 概述和原理 1.什么是 NSRunLoop? 我们会经常看到这样的代码: -(IBAction)start:(id)sender 44 { pageStillLoading = YES; [NSThread detachNewThreadSelector:@selector(loadPageInBac kground:)toTarget:self withObject:nil]; [progress setHidden:NO]; while (pageStillLoading) { [NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMo de beforeDate:[NSDate distantFuture]]; } [progress setHidden:YES]; } 这段代码很神奇的,因为他会“暂停”代码运行,而且程序运行不会因 为这里有一个 while 循环而受到影响。在[progress setHidden:NO]执 行之后,整个函数像暂停了一样,停在循环里面,等 loadPageInBackground 里面的操作都完成了以后, 才让[progress setHidden:YES]运行。这样做就显得简单,而且逻辑很 清晰。如果不这样做,就需要在 loadPageInBackground 里面表示 load 完成的地方调用[progress setHidden:YES],显得代码不紧凑而且容易 出错。 那么具体什么是 NSRunLoop 呢?其实 NSRunLoop 的本质是一个消 息机制的处理模式。如果你对 vc++编程有一定了解,在 windows 中, 有一系列很重要的函数 SendMessage,PostMessage,GetMessage, 这些都是有关消息传递处理的 API。但是在你进入到 Cocoa 的编程世界 里面,我不知道你是不是走的太快太匆忙而忽视了这个很重要的问题, Cocoa 里面就没有提及到任何关于消息处理的 API, 开发者从来也没有自己去关心过消息的传递过程,好像一切都是那么自 然,像大自然一样自然?在 Cocoa 里面你再也不用去自己定义 45 WM_COMMAD_XXX 这样的宏来标识某个消息, 也不用在 switch-case 里面去对特定的消息做特别的处理。难道是 Cocoa 里面就没有了消息机制?答案是否定的,只是 Apple 在设计消 息处理的时候采用了一个更加高明的模式,那就是 RunLoop。 利用 NSRunLoop 阻塞 NSOperation 线程 在使用 NSOperationQueue 简化多线程开发中介绍了多线程的开发, 我这里主要介绍一下使用 NSRunLoop 阻塞线程。 主要使用在 NStimer 定时启用的任务或者异步获取数据的情况 如 socket 获取网络数据,要阻塞线程,直到获取数据之后在释放线程。 下面是线程中没有使用 NSRunLoop 阻塞线程的代码和执行效果: 线程类: #import @interface MyTask : NSOperation { } @end #import "MyTask.h" @implementation MyTask -(void)main { NSLog(@"开始线程=%@",self); [NSTimer timerWithTimeInterval:2 target:self selector:@selector(hiandeTime:) userInfo:nil repeats:NO]; } -(void)hiandeTime:(id)sender 46 { NSLog(@"执行了 NSTimer"); } -(void)dealloc { NSLog(@"delloc mytask=%@",self); [super dealloc]; } @end 线程添加到队列中: -(void)viewDidLoad { [super viewDidLoad]; NSOperationQueue *queue=[[NSOperationQueue alloc] init]; MyTask *myTask=[[[MyTask alloc] init] autorelease]; [queue addOperation:myTask]; MyTask *myTask1=[[[MyTask alloc] init] autorelease]; [queue addOperation:myTask1]; MyTask *myTask2=[[[MyTask alloc] init] autorelease]; [queue addOperation:myTask2]; [queue release]; } 执行结果是: 2011-07-25 09:44:45.393 OperationDemo[20676:1803] 开始线程 47 = 2011-07-25 09:44:45.393 OperationDemo[20676:5d03] 开始线程 = 2011-07-25 09:44:45.396 OperationDemo[20676:1803] 开始线程 = 2011-07-25 09:44:45.404 OperationDemo[20676:6303] delloc mytask= 2011-07-25 09:44:45.404 OperationDemo[20676:5d03] delloc mytask= 2011-07-25 09:44:45.405 OperationDemo[20676:6303] delloc mytask= 可以看到,根本没有执行 NSTimer 中的方法,线程就释放掉了,我们 要执行 NSTimer 中的方法,就要利用 NSRunLoop 阻塞线程。下面是修改后 的代码: -(void)main { NSLog(@"开始线程=%@",self); NSTimer *timer=[NSTimer timerWithTimeInterval:2 target:self selector:@selector(hiandeTime) userInfo:nil repeats:NO]; [timer fire]; while (!didDisconnect) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 48 } } 执行结果如下: 2011-07-25 10:07:00.543 OperationDemo[21270:1803] 开始线程 = 2011-07-25 10:07:00.543 OperationDemo[21270:5d03] 开始线程 = 2011-07-25 10:07:00.550 OperationDemo[21270:6303] 开始线程 = 2011-07-25 10:07:00.550 OperationDemo[21270:1803] 执 行 了 NSTimer 2011-07-25 10:07:00.551 OperationDemo[21270:5d03] 执 行 了 NSTimer 2011-07-25 10:07:00.552 OperationDemo[21270:6303] 执 行 了 NSTimer 2011-07-25 10:07:00.556 OperationDemo[21270:6503] delloc mytask= 2011-07-25 10:07:00.557 OperationDemo[21270:6303] delloc mytask= 2011-07-25 10:07:00.557 OperationDemo[21270:5d03] delloc mytask= 我们可以使用 NSRunLoop 进行线程阻塞 http://www.cocoachina.com/bbs/read.php?tid=73570&uid=39045&page=6 49 BOOL 在其大多数历史阶段,C 都缺乏一个定义的布尔类型。它通过计算表达 式来确定真值。如果一个表达式计算为 0,则被认为是假;相反,则为 真。 C99 标准添加了一个布尔类型,bool,并且还添加了真值 true 和假值 false。Objective-C 有自己的布尔类型,BOOL,并且还有真值常量 YES 和假值常量 NO。 BOOL 不是一个基本类型。它是无符号的 char 的一个 typedef(别名)。 YES 和 NO 只是为 1 和 0 定义的常量。 由于 Objective-C 继承了 所有的 C 类型,因此我们 可以在自 己的 Objective-C 程序中使用 bool 类型。 然而,Cocoa 框架和大多数已有的 Objective-C 代码使用 BOOL。尽 管可以在 bool 和 BOOL 之间相互转换,除非你的程序用到的库使用了 bool,否则干脆忘掉 bool 会更容易一些。 注 意 尽 管 Objective-C 当 前 的 版 本 是 基 于 C99 标 准 的 , 但 Objective-C 最初只是作为缺乏布尔类型的一个较早版本的 C 的扩展而 开发的。 尽管 C99 的 bool 类型也可以使用,但大多数 Objective-C 社群使用 Objective-C 的 BOOL。 SEL SEL是保存了一个Objective-C 方法名表示的一种类型。SEL是 selector 的缩写。方法名有时候叫做选择器,因为运行时使用它们来选择要执行 的代码,以响应一条消息。 IMP IMP 是一个 typedef,用于“一个指针,它指向接受参数 id、SEL 及可 能的其他参数并且返回 id 的函数”。 50 BOOL 和 bool 的区别 1、类型不同 BOOL 为 int 型 bool 为布尔型 2、长度不同 bool 只有一个字节 BOOL 长度视实际环境来定,一般可认为是 4 个字节 3、取值不同 bool 取值 false 和 true,是 0 和 1 的区别; false 可以代表 0,但 true 有很多种,并非只有 1。 如果数个 bool 对象列在一起,可能会各占一个 bit,这取决于编译器。 BOOL 是微软定义的 typedef int BOOL(在 windef.h 中)。 布尔型变量 bool bool 是布尔型变量,也就是逻辑型变量的定义符,类似于 float,double 等,只不过 float 定义浮点型,double 定义双精度浮点型。 在 objective-c 中提供了相似的类型 BOOL,它具有 YES 值和 NO 值。 布尔型变量的值只有 真 (true) 和假 (false)。 布尔型变量可用于逻辑表达式,也就是“或”“与”“非”之类的逻辑运算 和大于小于之类的关系运算,逻辑表达式运算结果为真或为假。 bool 可用于定义函数类型为布尔型,函数里可以有 return TRUE; return FALSE 之类的语句。 布尔型运算结果常用于条件语句, if (逻辑表达式) { 如果是 true 执行这里; } else 51 { 如果是 false 执行这里; }; BOOL 在 iphone 程序开发中很重要,一般配合 if 语句进行判断,处 理程序中逻辑关系! BOOL,int,float,指针变量 与“零值”比较的 if 语句 分别给出 BOOL,int,float,指针变量 与“零值”比较的 if 语句(假 设变量名为 var) 解答: BOOL 型变量:if(!var) int 型变量: if(var==0) float 型变量: c*****t float EPSINON = 0.00001; if ((x >= - EPSINON)&&(x <= EPSINON) 指针变量: if(var==NULL) 剖析: 考查对 0 值判断的“内功”,BOOL 型变量的 0 判断完全可以写成 if (var==0),而 int 型变量也可以写成 if(!var),指针变量的判断也 可以写成 if(!var), 上述写法虽然程序都能正确运行,但是未能清晰地表达程序的意思。一 般的,如果想让 if 判断一个变量的“真”、“假”,应直接使用 if(var)、 if(!var),表明其为“逻辑”判断; 如果用 if 判断一个数值型变量(short、int、long 等),应该用 if (var==0),表明是与 0 进行“数值”上的比较;而判断指针则适宜用 if (var==NULL),这是一种很好的编程习惯。 浮点型变量并不精确,所以不可将 float 变量用“==”或“!=”与数 字比较,应该设法转化成“>=”或“<=”形式。如果写成 if (x == 0.0), 52 则判为错,得 0 分。 IPhone 之 NSXMLParser 的使用 NSXMLParser 解析 xml 格式的数据用法如下: 首先,NSXMLParser 必须继续 NSXMLParserDelegate 协议 @interface XMLHelper : NSObject 首先设置 XML 数据,并初始化 NSXMLParser -(void)viewDidLoad { NSMutableString *Strxml=[NSMutableStringstringWithString:@"111111113333333333"]; NSData *data=[NSData dataWithBytes:[Strxml UTF8String]length:[Strxml lengt h]]; NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];//设置 XML 数 据 [parser setShouldProcessNamespaces:NO]; [parser setShouldReportNamespacePrefixes:NO]; [parser setShouldResolveExternalEntities:NO]; [parser setDelegate:self]; [parser parse]; [super viewDidLoad]; } //遍例 xml 的节点 53 -(void)parser:(NSXMLParser *)parser didStartElement:(NSString*)elementName namespaceURI:(NSString *)namespaceURIqualifiedName:(NSString *)qName attri butes:(NSDictionary*)attributeDict { NSLog(@"Name:%@",elementName); } //当 xml 节点有值时,则进入此句 -(void)parser:(NSXMLParser *)parser foundCharacters:(NSString*) string { NSLog(@"Value:%@",string); } //当遇到结束标记时,进入此句 -(void)parser:(NSXMLParser *)parser didEndElement:(NSString*)elementName na mespaceURI:(NSString *)namespaceURIqualifiedName:(NSString *)qName { } 在 tableview 索引中显示搜索符号的方法 代码如下,在 UITableViewDataSource 中设置 -(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView { NSMutableArray *arr = [[[NSMutableArray alloc] 54 initWithCapacity:0] autorelease]; [arr addObject:@"{search}"];// 等 价 于 [arr addObject:UITableViewIndexSearch]; return arr; } 效果图: 55 MapKit 学习笔记 1、概述 插入 MapView,设置 Delegate(一般为 Controller),Annotati*****记录 兴趣位置点(AnnotationView 用来显示兴趣位置点),annotation 是可选 的,选中的 annotation 会显示 callout,用来显示信息。 2、设置地图显示类型: mapView.mapType = MKMapTypeStandard; mapView.mapType = MKMapTypeSatellite; mapView.mapType = MKMapTypeHybrid; 3、显示用户位置 设置为可以显示用户位置: mapView.showsUserLocation = YES; 判断用户当前位置是否可见(只读属性): userLocationVisible 得到用户位置坐标:当 userLocationVisible 为 YES 时 CLLocationCoordinate2D coords = mapView.userLocation.location.coordinate; 4、坐标范围 MKCoordinateRegion 用来设置坐标显示范围。 包括两部分:Center(CLLocationCoordinate2D struct,包括 latitude 和 longitude),坐标中心 和 Span(MKCoordinateSpan struct,包括 latitudeDelta 和 longitudeDelta), 缩放级别 MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(center,2000, 2000); 以上代码创建一个以 center 为中心,上下各 1000 米,左右各 1000 米得 区域,但其是一个矩形,不符合 MapView 的横纵比例 MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion]; 以上代码创建出来一个符合 MapView 横纵比例的区域 [mapView setRegion:adjustedRegion animated:YES]; 以上代码为:最终显示该区域 5、Delegate 56 使用 MapView 须符合 MKMapViewDelegate 协议 5.1、地图加载 Delegate 当需要从 Google 服务器取得新地图时 mapViewWillStartLoadingMap: 当成功地取得地图后 mapViewDidFinishLoadingMap: 当取得地图失败后(建议至少要实现此方法) mapViewDidFailLoadingMap:withError: 5.2、范围变化 Delegate 当手势开始(拖拽,放大,缩小,双击) mapView:regionWillChangeAnimated: 当手势结束(拖拽,放大,缩小,双击) mapView:regionDidChangeAnimated: 判断坐标是否在 MapView 显示范围内: CLLocationDegrees leftDegrees = mapView.region.center.longitude –(mapView.region.span.longitudeDelta / 2.0); CLLocationDegrees rightDegrees = mapView.region.center.longitude +(mapView.region.span.longitudeDelta / 2.0); CLLocationDegrees bottomDegrees = mapView.region.center.latitude –(mapView.region.span.latitudeDelta / 2.0); CLLocationDegrees topDegrees = self.region.center.latitude +(mapView.region.span.latitudeDelta / 2.0); if (leftDegrees > rightDegrees) {// Int'l Date Line in View leftDegrees = -180.0 - leftDegrees; if (coords.longitude > 0) // coords to West of Date Line coords.longitude = -180.0 - coords.longitude; } If (leftDegrees <= coords.longitude && coords.longitude <= rightDegrees && bottomDegrees <= coords.latitude && coords.latitude <= topDegrees) { // 坐标在范围内 } 6、Annotation Annotation 包含两部分:Annotation Object 和 Annotation View Annotation Object 必须符合协议 MKAnnotation,包括两个方法:title 和 subtitle,分别用于显示注释的标题和子标题。还有 coordinate 属性,返 回 CLLocationCoordinate2D,表示 Annotation 的位置 然后,需使用 mapView:viewForAnnotation: 方法来返回 MKAnnotationView 或者 MKAnnotationView 的子类用来显示 Annotation 57 (注意:这里显示的不是选中 Annotation 后的弹出框) 你可以子类化 MKAnnotationView,然后再 drawRect:方法里面进行自 己的绘制动作(这个方法很蠢) 你完全可以实例化一个 MKAnnotationView,然后更改它的 image 属性, 这样很简单。 7、添加移除 Annotation 添加一个 Annotation [mapView addAnnotation:annotation]; 添加一个 Annotation 数组 [mapView addAnnotati*****:[NSArray arrayWithObjects:annotation1, annotation2, nil]]; 移除一个 Annotation removeAnnotation: 移除一个 Annotation 数组 removeAnnotati*****: 移除所有 Annotation [mapView removeAnnotati*****:mapView.annotati*****]; 8、选中 Annotation 一次只能有一个 Annotation 被选中,选中后会出现 CallOut(浮动框) 简单的 CallOut 显示 Title 和 SubTitle,但你也可以自定义一个 UIView 作 为 CallOut(与自定义的 TableViewCell 一样) 可通过代码选中 Annotation: selectAnnotation:animated: 或者取消选择: deselectAnnotation:animated: 9、显示 Annotation 通过 mapView:viewForAnnotation: 方法显示 Annotation,每在 MapView 中加入一个 Annotation,就会调用此方法 示例(与 tableView:cellForRowAtIndexPath: 很相似) -(MKAnnotationView *) mapView:(MKMapView *)theMapView viewForAnnotation:(id ) annotation { static NSString *placemarkIdentifier = @"my annotation identifier"; if ([annotation isKindOfClass:[MyAnnotation class]]) { MKAnnotationView *annotationView = [theMapView dequeueReusableAnnotationViewWithIdentifier:placemarkIdentifier]; if (annotationView == nil) { annotationView = [[MKAnnotationView alloc] 58 initWithAnnotation:annotation reuseIdentifier:placemarkIdentifier]; annotationView.image = [UIImage imageNamed:@"blood_orange.png"]; } else annotationView.annotation = annotation; return annotationView; } return nil; } 10、取得真实地址 示例: 初始化 MKReverseGeocoder MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc] initWithCoordinate:coordinates]; geocoder.delegate = self; [geocoder start]; 如果无法处理坐标,则调用 reverseGeocoder:didFailWithError: 方法 -(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error { NSLog(@"Error resolving coordinates: %@",[error localizedDescription]); geocoder.delegate = nil; [geocoder autorelease]; } 如果成功,则调用 reverseGeocoder:didFindPlacemark: 并把信息存储在 MKPlacemark 中 didFindPlacemark:(MKPlacemark *)placemark { NSString *streetAddress = placemark.thoroughfare; NSString *city = placemark.locality; NSString *state = placemark.administrativeArea; NSString *zip = placemark.postalCode; // Do something with information geocoder.delegate = nil; [geocoder autorelease]; } 59 Leaves -- iOS 上一种图书翻页效果的实现 Leaves 是由 Tow Brow 开发的一个简单的图书翻页控件,它巧妙地结合 了镜像层、阴影层(用于半透明页)和渐变层(用于阴影)来实现图书 的翻页效果。其翻页效果如下图所示: 特性 Leaves 支持: 文本、图像、PDF 等任何可被渲染到 Graphics Context 上的对象 通过拖动或点击来翻页 支持 ipad 和 iphone 大小的显示区域 Levels 目前不支持以下特性 60 页面上的交互元素 轻扫动作 类和接口 Leaves 中主要有三个类:LevelsView、LevelsViewController、LevelsCache: LevelsCache:是一个辅助类,用于缓存显示页。它将显示的内容缓存为 图片并保存。 LevelsView:是翻页视图,翻页的主要效果便在些实现。它定义了一系 列的层对象,并通过操作这些层对象来实现翻页中各种效果。 LevelsViewController: LevelsView 的控制器 类似于 UITableView, LevelsView 也有一个相关的数据源类 (LeaveViewDataSource)与委托类(LeavesViewDelegate),它们分别有两个 方法,如下所示 复制代码 @protocol LeavesViewDataSource -(NSUInteger) numberOfPagesInLeavesView:(LeavesView*)leavesView; -(void) renderPageAtIndex:(NSUInteger)index inContext:(CGContextRef)ctx; @end @protocol LeavesViewDelegate @optional -(void) leavesView:(LeavesView *)leavesView willTurnToPageAtIndex:(NSUInteger)pageIndex; -(void) leavesView:(LeavesView *)leavesView didTurnToPageAtIndex:(NSUInteger)pageIndex; @end 层树结构 LevelsView 中的层树结构如下图所示: 每一个层(Layer)都有其特殊的用途,或作为内容的显示层,或作为阴影 层,具体说明如下: topPage 层:显示当前页的内容。 topPageOverlay 层:在翻页过程中,该层覆盖于 topPage 层上,且颜色 偏暗,从而使 topPage 未翻转的部分变暗,有阴影的感觉。 topPageShadow 层:在翻页过程中,该层用于表达 topPage 被翻转部分 61 所形成的阴影。 topPageReverse 层:翻页过程中,topPage 被翻转部分的反面的容器层。 topPageReverseImage 层:反面的内容页。在竖屏下,用于显示 topPage 被翻转部分的内容,这些内容被映射到该层,给人感觉书是透明的。在 横屏下,显示的是下一页的内容。 topPageReverseOverlay 层:该层用于覆盖 topPageReverse 层,效果与 topPageOverlay 类似。 topPageReverseShading 层:该层在 topPageReverse 层右侧形成一个阴影。 bottomPage 层:topPage 页的下一页所在的层。 bottomPageShadow 层:该层为在翻页过程中在 bottomPage 左侧形成的 一个阴影层。 leftPage 层:该层为横屏模式下左侧页所在的层。 leftPageOverlay 层:该层覆盖于为 leftPage 层,效果与 topPageOverlay 类似。 由上可以看出,层树中的层主要分为三类: 内容显示层:topPage、topPageReverseImage、bottomPage、leftPage 阴影层:topPageShadow、topPageReverseShading、bottomPageShadow 覆盖层:topPageOverlay、topPageReverseOverlay、leftPageOverlay 图片缓存 Tow Brow 在处理不同的内容(文本、图像、PDF)时显示时,所采取的方 法是一样的。他将内容缓存为图像,并显示在屏幕上。基本方法是将内 容写进 CGContextRef 中,然后根据 CGContextRef 中的信息创建图像, 具体方法如下: 复制代码 -(CGImageRef) imageForPageIndex:(NSUInteger)pageIndex { CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef context = CGBitmapContextCreate(NULL, pageSize.width, pageSize.height, 8, /* bits per component*/ pageSize.width * 4, /* bytes per row */ colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); 62 CGContextClipToRect(context, CGRectMake(0, 0, pageSize.width, pageSize.height)); [dataSource renderPageAtIndex:pageIndex inContext:context]; CGImageRef image = CGBitmapContextCreateImage(context); CGContextRelease(context); [UIImage imageWithCGImage:image]; CGImageRelease(image); return image; } 当然程序没有缓存所有页的内容,而是根据横竖屏的不同缓存适当数量 的内容。每次翻页时会重新整理缓存中的内容。 翻页动画实现 在 Leaves 中,翻页的基本原理其实很简单:翻页过程中,根据手指的划 动来不断的调整层树结构中每个层的 frame,翻页结束后,重新调整内 容显示层所显示的内容。 为此,LevelsView 中设置了一个 leafEdge 变量,该变量是手指在屏幕上 划动时 Touch Point 在屏幕 x 轴上的百分比位置,这个操作在 touchesMoved:withEvent 中完成: 复制代码 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { ...... UITouch *touch = [event.allTouches anyObject]; CGPoint touchPoint = [touch locationInView:self]; [CATransaction begin]; [CATransaction setValue:[NSNumber numberWithFloat:0.07] forKey:kCATransactionAnimationDuration]; self.leafEdge = touchPoint.x / self.bounds.size.width; [CATransaction commit]; } 而在 leafEdge 的 set 方法中,我们根据 leafEdge 的值来重新设定各个 Layer 的 frame 属性 复制代码 -(void) setLayerFrames { CGRect rightPageBoundsRect = self.layer.bounds; CGRect leftHalf, rightHalf; CGRectDivide(rightPageBoundsRect, &leftHalf, &rightHalf, 63 CGRectGetWidth(rightPageBoundsRect) / 2.0f, CGRectMinXEdge); if (self.mode == LeavesViewModeFacingPages) { rightPageBoundsRect = rightHalf; } topPage.frame = CGRectMake(rightPageBoundsRect.origin.x, rightPageBoundsRect.origin.y, leafEdge * rightPageBoundsRect.size.width, rightPageBoundsRect.size.height); topPageReverse.frame = CGRectMake(rightPageBoundsRect.origin.x + (2*leafEdge-1) * rightPageBoundsRect.size.width, rightPageBoundsRect.origin.y, (1-leafEdge) * rightPageBoundsRect.size.width, rightPageBoundsRect.size.height); ...... } 最后便是当手指离开屏幕时,如何处理翻页结果(将当前页翻过去还是没 有翻过去)。这个操作在 这个操作在 touchesEnded:withEvent 中完成 复制代码 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { ...... UITouch *touch = [event.allTouches anyObject]; CGPoint touchPoint = [touch locationInView:self]; BOOL dragged = distance(touchPoint, touchBeganPoint) > [self dragThreshold]; [CATransaction begin]; float duration; if ((dragged && self.leafEdge < 0.5) || (!dragged && [self touchedNextPage])) { [self willTurnToPageAtIndex:currentPageIndex + numberOfVisiblePages]; self.leafEdge = 0; duration = leafEdge; ...... } else { [self willTurnToPageAtIndex:currentPageIndex]; self.leafEdge = 1.0; duration = 1 - leafEdge; ....... 64 } [CATransaction setValue:[NSNumber numberWithFloat:duration] forKey:kCATransactionAnimationDuration]; [CATransaction commit]; } 如果需要在翻页后执行某些操作(如在屏幕上显示当前页数等),则可以 在继承自 LevelsViewController 的控制器中实现 leavesView:didTurnToPageAtIndex 方法。 在此需要注意的就是 topPageReverseImage 在竖屏时做了如下的变换 复制代码 topPageReverseImage.contentsGravity = kCAGravityRight; topPageReverseImage.transform = CATransform3DMakeScale(-1, 1, 1); 从而使 topPageReverseImage 显示的内容让人感觉是透过纸张,看到 topPage 的内容。 横屏与竖屏 Leaves 还有一个特点就是其支持横屏时,能同时看到两页的内容(该效 果是由 Ole Begemann 改进的)。该改进最关键的地方就是增加了 leftPage 层,同时在横屏显示时将屏幕一分为二,在左侧显示 leftPage。同进在 翻页的过程中,topPageReverseImage 显示的是 topPage 页下一页的内容。 在翻转屏幕时,会根据方向重新调整内容的显示。 65 刷新 view 时不全屏加载的方法 如果你的 iPhne 应用里涉及到刷新功能,但不需要全屏加载去覆盖老 的 view,而只是刷新部分屏幕(比如,320×400 的面积),可以先在 view 中添加 一个 320×400 的 view。再将 navigationController.view 加入到这个 320×400 的 view 中,再用 这个 navigationController 去刷新的 viewController 就可以了。 代码例子 TestPush.zip iPhone table 实现动态加载图片的教程 iPhone 在加载列表时,如果每个等待把所有列表中的数据都加载完在显示相关内容,如果列表 66 中有一些比较大的图片,加载的时间比较长,那么给用户的效果就很差了,下面详细是一种实 现动态加载图片的办法: -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"tag"]; if (cell==nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"tag"] autorelease]; } //表格设计 NSDictionary* one = [array objectAtIndex:indexPath.row]; cell.textLabel.text = [one objectForKey:@"title"]; cell.detailTextLabel.text = [one objectForKey:@"content"]; [NSThread detachNewThreadSelector:@selector(updateImageForCellAtIndexPath:) toTarget:self withObject:indexPath]; return cell; } -(void)updateImageForCellAtIndexPath:(NSIndexPath *)indexPath { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; UIImage *image = [self getImageForCellAtIndexPath:indexPath]; UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; [cell.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; [image release]; [pool release]; } -(UIImage *)getImageForCellAtIndexPath:(NSIndexPath *)indexPath { id path = [[array objectAtIndex:indexPath.row] objectForKey:@"image"]; 67 NSURL*url = [NSURL URLWithString:path]; NSData *data = [NSData dataWithContentsOfURL:url]; UIImage *image = [[UIImage alloc] initWithData:data cache:NO]; return image; } 关于 TableView 中图片的延时加载 经常我们会用 tableView 显示很多条目, 有时候需要显示图片, 但是一次 从服务器上取来所有图片对用户来浪费流量, 对服务器也是负担.最好 是按需加载,即当该用户要浏览该条目时再去加载它的图片。 重写如下方法 -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { UIImage *image = [self getImageForCellAtIndexPath:indexPath]; // 从网上取得图片 [cell.imageView setImage:image]; 68 } 这虽然解决了延时加载的问题, 但当网速很慢, 或者图片很大时(假设, 虽然一般 cell 中的图很小),你会发现程序可能会失去对用户的响应. 原因是 UIImage *image = [self getImageForCellAtIndexPath:indexPath]; 这个方法可能要花费大量的时间,主线程要处理这个 method. 所以失去了对用户的响应. 所以要将该方法提出来: -(void)updateImageForCellAtIndexPath:(NSIndexPath *)indexPath { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; UIImage *image = [self getImageForCellAtIndexPath:indexPath]; UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; [cell.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO]; [pool release]; } 然后再新开一个线程去做这件事情 -(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { [NSThread detachNewThreadSelector:@selector(updateImageForCellAtIndexPath:) toTarget:self withObject:indexPath]; } 同理当我们需要长时间的计算时,也要新开一个线程 去做这个计算以避 免程序处于假死状态 以上代码只是示例, 还可以改进的更多, 比如从网上 down 下来一次后 就将图片缓存起来,再次显示的时候就不用去下载。 69 Three20 中 TTNavigator 用法总结 简单映射: Three20 中的 TNavigator 对于软件导航很有用,只需要维护一张 map 映射表就行了。就像 url 表示一个网页一样,Three20 也采用了相同的方式,用 url 关联页面。大家可以参看 TTNavigatorDemo 中的源码: TTURLMap* map = navigator.URLMap; c // Any URL that doesn't match will fall back on this one, and open in the web browser [map from:@"*" toViewController:[TTWebController class]]; // The tab bar controller is shared, meaning there will only ever be one created. Loading // This URL will make the existing tab bar controller appear if it was not visible. [map from:@"tt://tabBar" toSharedViewController:[TabBarController class]]; // Menu controllers are also shared - we only create one to show in each tab, so opening // these URLs will switch to the tab containing the menu [map from:@"tt://menu/(initWithMenu:)" toSharedViewController:[MenuController class]]; 上面的代码就是给页面注册 url, 如 tt:tabBar 就表示 TabBarController,只要调用 TTOpenURL(@"tt://tabBar");这句代码就可以初始化 TabBarController,并显示出来。相当于执行了 TabBarController *test=[[TabBarController alloc] init]; [self.view addSubview:test.view]; 如果调用 TTOpenURL(@"tt://menu/1");会发生什么? 它会调用 MenuController 中的 -(id)initWithMenu:(MenuPage)page { if (self = [super init]) { 70 self.page = page; } return self; } 为什么会调用这个方法呢? 因为我们在上面 map 的时候是用的 tt://menu/(initWithMenu:) 括号 里是方法名,可以想像成如果有括号,那么它就表示一变量,那么它就是一对多的映射, 与数 学上的映射一个道理。,tt://menu/1 tt://menu/2 tt://menu/3 ..... tt://menu/XXX 都表示这个对应,所 以 TTOpenURL(@"tt://menu/2");的时候也会调用上面的方法。 而这个 1,2,3 .... XXX 就表未参数传入到上面这个方法。为什么会样呢,因为这是 Three20 的 规则。还有注意,你的 MenuController 必须要实现 -(id)initWithMenu:(MenuPage)page 这个方法,不然就不能达到效果。 在 map 映射的时候,如果加括号有方法名的时候,这个方 法返回的必须是 Controller. (这是我的理解,不知道正确与否,知道的大侠通知我一下) 多参数映射: 上面的情况是只有一个参数转入,如果想传多个参数如何办呢?我知道有两种方法: 1. 将映射改为: [map from:@"tt://menu/(initWithMenu:)/(withParam:)" toSharedViewController:[MenuController class]]; 这样就可以传入两个参数,相应的方法就应改为: -(id)initWithMenu:(MenuPage)page withParam:(NSString*)param { if (self = [super init]) { self.page = page; } return self; } 2。将映射改为: [map from:@"tt://menu?menu=(initWithMenu:)" toSharedViewController:[MenuController class]]; 这种方式也可以传入多个参数,如: TTOpenURL(@"tt://menu?menu=1&ref=hello&name=world&phone=123");这样就传入了三个参 数, 那么它的初始化方法就应写为: -(id)initWithMenu:(MenuPage)page query:(NSDictionary*)query { NSString *ref = [query objectForKey:@"ref"]; NSString *name = [query objectForKey:@"name"]; NSString *phone = [query objectForKey:@"phone"]; if (self = [super init]) { self.page = page; } return self; } 注意:如果 -(id)initWithMenu:(MenuPage)page 这个方法与上面多参数方法同时存在的话, 那么首先是调用上面这个单参数方法,并没有智能 的根据参数的不同而选择初始化方法,避免错误调用方法就是在映射的时候将方法名命名为不 同的名字。 Hash URL 在 demo 中有一个 Hash URL 的例子,它可以指定方法的调用。 如果将 MenuController 里的代码修改一下: self.navigationItem.rightBarButtonItem = 71 [[[UIBarButtonItem alloc] initWithTitle:@"Order" style:UIBarButtonItemStyleBordered target:@"tt://order?waitress=Betty&ref=toolssssstest#param" action:@selector(openURLFromButton:)] autorelease]; 那么点 order 的时候就会调用 ContentController 里的 -(void)orderAction:(NSString*)action { TTDPRINT(@"ACTION:%@", action); } 因为 map 映射的是: [map from:@"tt://order?waitress=(initWithWaitress:)" toModalViewController:[ContentController class]]; [map from:@"tt://order?waitresss=()#(orderAction:)" toViewController:[ContentController class]]; 好了,就些就是我学习的一点点小结,可能有误 ,望大家指正。 参考: http://three20.pypt.lt/url-based-navigation-and-state-persistence http://three20.info/article/2010-10-06-URL-Based-Navigation http://www.slideshare.net/iphonedevbr/three20 原文链接:http://blog.csdn.net/favormm/article/details/6760533 常用 16 种视图切换动画小结 前 4 种是 UIView,后面都是 Core Animation, 下面 8 种是传说中的私有 API 整合到一个例子里,代码较清晰,适合新手阅读,效果如下图: 72 源码下载: StudyiOS.zip iPhone 开发 地图线路 因为接触到了这么一个项目,所以进行了这个功能的深入了解,比较忙,所以把关键代码贴在 这里,如果有问题,请留言。或者是其他的平台,也想具备这个功能,请留言。周内不回复。 头文件如下: 73 效果图如下:可能有偏移,这里不进行解决。 你知道的,为什么要加标点。 用到的几个方法代码如下: 获取路径数据: 74 核心代码,解析数据为经纬度对值: 75 画 出线路: 76 地图居中显示: 使用 google 地图 api 3.0协议解析两个经纬度,得到行进路线。 77 比较重要的一个方法: 工作日内不回复。 或者你用下面的这个 addoverlay 的方法即可解决。 或者如下博客所述。 http://apps.hi.baidu.com/share/detail/51968697 核心代码: 这个是基本的绘制线路的方法。最后生成一张图片。 地图居中显示 #pragma mark mapView delegate functions -(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated { route_view.hidden = YES; } -(void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { [self update_route_view]; route_view.hidden = NO; [route_view setNeedsDisplay]; } Cover flow 基本原理及 Tapku 实现方法 本帖属于 CocoaChina 会员发表,转帖请写明来源和帖子地址  Cover flow 是苹果首创的将多首歌曲的封面以3D 界面的形式显示出来的方式。如下图 所示: 78 从图中可以看到,显示在中间的图片为目标图片,两侧的图片在 y 轴都旋转了一定的角度, 并且每两张图片之间都保持了一定的距离。在交互(如点击两侧的图片)的时候,滑动到 中间的图片会逐渐放大,旋转的角度由原来的旋转角度 a 变为0,且位置上移动中间,变成 新的目标图片;同时原处于中间位置的图片则缩小、旋转一定的角度、位置偏移到一侧。 所以在整个过程中,主要有两个属性发生了变化:角度与位置(缩放只是视觉上的,并没有 进行缩放操作)。 在每次点击一张图片时,如果这张图片在目标图片的左边,则所有的图片都会向右移动, 同时做相应的旋转;相反,点击目标图片右侧的图片时,所有图片都会向左移动并做相应 的旋转。 从如上描述的效果,可以看出在 Cover Flow 中最主要的的操作有两个:3D 仿射变换与动 画。仿射变换实质上是一种线性变换,通常主要用到的仿射变换有平移(Translation)、旋转 (Rotation)、缩放(Scale)。 对于这两种操作,iOS 都提供了非常简便的接口来实现。接下来我们便以 tapku 的实现方 法为例,来说明实现 Cover Flow 的基本过程。 一、图片的布局 从效果图可以看出,图片是按一条直接排列,图片与图片之间有一定的间距,目标图片是 79 正向显示,两侧的图片则按一定的角度进行了旋转,与目标图片形成一定的角度。同时我 们还能看到每个图片都有一个倒影,并且这个倒影是渐变的,由上而下逐渐透明度逐渐减 小。 1、 Cover Flow 单元的定义 在 tapku 中,每一个图片附属于一个视图(TKCoverflowCoverView),这个视图相当于 UITableViewCell,它包含了三个要素:图片(imageView),倒影图片(reflected),渐变层 (gradientLayer)。渐变层覆盖于倒影图片上,且大小位置一致。 TKCoverflowCoverView 的声明及布局代码如下所示: 复制代码@interface TKCoverflowCoverView : UIView {  float baseline;  UIImageView *imageView;  UIImageView *reflected;  CAGradientLayer *gradientLayer;  }  @end  -(id)initWithFrame:(CGRect)frame {  self = [super initWithFrame:frame];  if (self) {  self.opaque = NO;  self.backgroundColor = [UIColor clearColor];  self.layer.anchorPoint = CGPointMake(0.5, 0.5);  imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.width)];  [self addSubview:imageView];  reflected = [[UIImageView alloc] initWithFrame:CGRectMake(0, self.frame.size.width, self.frame.size.width, self.frame.size.width)];  reflected.transform = CGAffineTransformScale(reflected.transform, 1, -1);  [self addSubview:reflected]; 80  gradientLayer = [CAGradientLayer layer];  gradientLayer.colors = [NSArray arrayWithObjects:(id)[UIColor colorWithWhite:0 alpha:0.5].CGColor,(id)[UIColor colorWithWhite:0 alpha:1].CGColor,nil];  gradientLayer.startPoint = CGPointMake(0, 0);  gradientLayer.endPoint = CGPointMake(0, 0.4);  gradientLayer.frame = CGRectMake(0, self.frame.size.width, self.frame.size.width, self.frame.size.width);  [self.layer addSublayer:gradientLayer];  }  return self;  }  注意:此次将视图的锚点(anchorPoint 属性) 设置为(0.5, 0.5),即视图的中心点,目的是 让视图以中心点为基点进行旋转。 在进行仿射变换时,视图作为一个整体进行 变换。 2、图片的布局 tapku 中 , 图 片 的 布 局 与 交 互 是 在 TKCoverflowView 类 中 完 成 的 。 类 TKCoverflowView 继承自 UIScrollView,相 当于是 TableView。 该类中定义是两个仿射变量: 复 制 代 码 CATransform3D leftTransform, rightTransform 81  这两个变量分别设置了两侧图片的仿射变换,具体的设置方法为 复制代码-(void) setupTransforms{  leftTransform = CATransform3DMakeRotation(coverAngle, 0, 1, 0);  leftTransform = CATransform3DConcat(leftTransform,CATransform3DMakeTranslation(-spaceFromCurrent, 0, -300));  rightTransform = CATransform3DMakeRotation(-coverAngle, 0, 1, 0);  rightTransform = CATransform3DConcat(rightTransform,CATransform3DMakeTranslation(spaceFromCurrent, 0, -300));  }  其中 coverAngle 为旋转的角 度。对每个仿射变量同时设置 了旋转也平移变换。 Cover Flow 单元是存储在一 个数组中: 复 制 代 码 NSMutableArray *coverViews;  初始化时设置数组的大小,并存入空对象。在后期获取某个索引位置的单元时, 如果该单元为空,则生成一个新的 TKCoverflowCoverView 并放入相应位置。 复制代码 if([coverViews objectAtIndex:cnt] == [NSNull null]){  TKCoverflowCoverView *cover = [dataSource coverflowView:self 82 coverAtIndex:cnt];  [coverViews replaceObjectAtIndex:cnt withObject:cover];  ......  }  每个 Cover Flow 单元的位置计算如下 复制代码 CGRect r = cover.frame;  r.origin.y = currentSize.height / 2 -(coverSize.height/2) - (coverSize.height/16);  r.origin.x = (currentSize.width/2 -(coverSize.width/ 2)) + (coverSpacing) * cnt;  cover.frame = r;  其 中 currentSize,coverSize,coverSpacin g 都是固定值。从中可以看出所有单元 的 y 值都是一样的,而 x 值则与其在数 组中的索引值相关,索引越大,x 值也 越大。而这就涉及我们之后的一个问 题。一会再讲。 假定目标图片的索引为currentIndex, 则目标图片两侧的仿射属性设置如下: 复制代码 if(cnt > currentIndex){  cover.layer.transform = rightTransform;  } 83  else  cover.layer.transform = leftTransform;  如上即为 Cover Flow 的基本布局,可以与 UITableView 比较一下。 二、交互 Cover Flow 的基本交互是点击两侧的图片,则被点击的图片成为新的目标图片 并移动中屏幕中间,而其它图片一起移动,在这个过程中所需要做的就两件事: 旋转与平移。 方法很简单:在动画块中重新设置 Cover Flow 单元的 transform 属性,这样就 可以缓动实现这个动画的过程。实际上只有新旧目标图片及中间的图片需要做这 种变换,其余图片的 transform 属性都是不变的。 复制代码 float speed = 0.3;  [UIView beginAnimati*****:string context:nil];  [UIView setAnimationDuration:speed];  [UIView setAnimationCurve:UIViewAnimationCurveEaseOut];  [UIView setAnimationBeginsFromCurrentState:YES];  [UIView setAnimationDelegate:self];  [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];  for(UIView *v in views){  int i = [coverViews indexOfObject:v];  if(i < index) v.layer.transform = leftTransform;  else if(i > index) v.layer.transform = rightTransform;  else v.layer.transform = CATransform3DIdentity;  }  [UIView commitAnimati*****]; 84  但这在做的只是旋转了 Cover Flow 的内容,并没有对 Cover Flow 进行水平平移, Cover Flow 水平位置已由其 origin.x 值固定。那么水平上的平移是如何实现的呢,我 们看下面的代码: 复制代码-(void) snapToAlbum:(BOOL)animated{  UIView *v = [coverViews objectAtIndex:currentIndex];  if((NSObject*)v!=[NSNull null]){  [self setContentOffset:CGPointMake(v.center.x -(currentSize.width/2), 0) animated:animated];  }else{  [self setContentOffset:CGPointMake(coverSpacing*currentIndex, 0) animated:animated];  }  } 其所做的就是以目标图片为中心,整体平移 TKCoverflowView 视图。 三、总结 由上可以看出,Cover Flow 特效的原理很简单:对新旧目标图片及中间的图片以动画的形式 做仿射变换。至于仿射变换如何处理,有不同的方法。tapku 所实现的方法可以说相对简单灵 活。 Android, Flash 都有类似的 Cover Flow 特效实现方法,有兴趣的童鞋可以参考一下。 c UIWebView 之获取所点位置图片 URL 85 UIWebView 有 自 己 的 UIResgure , 如 果 我 们 手 动 加 入 自 己 的 GestureRecognize 将不能识别,如 UILongPressGestureRecongnizer. 在浏 览网页的时候,如果看到喜欢的图片,想把它保存下来如何办呢? 我 们可以自己写一个程序来实现,用 uiwcebview 开发一个自己的浏览器。 关面说到uiwebview不能识别long press gesture,幸好有一个可以识别, 那就是 double click.因此我们注册它,代码如下: UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; doubleTap.numberOfTouchesRequired = 2; [self.theWebView addGestureRecognizer:doubleTap]; 然后就是实现 doubleTap: -(void) doubleTap :(UITapGestureRecognizer*) sender { // // int scrollPositionY = [[self.theWebView stringByEvaluatingJavaScriptFromString:@"window.pageYOffset"] intValue]; int scrollPositionX = [[self.theWebView stringByEvaluatingJavaScriptFromString:@"window.pageXOffset"] intValue]; 86 int displayWidth = [[self.theWebView stringByEvaluatingJavaScriptFromString:@"window.outerWidth"] intValue]; CGFloat scale = theWebView.frame.size.width / displayWidth; CGPoint pt = [sender locationInView:self.theWebView]; pt.x *= scale; pt.y *= scale; pt.x += scrollPositionX; pt.y += scrollPositionY; NSString *js = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).tagName", pt.x, pt.y]; NSString * tagName = [self.theWebView stringByEvaluatingJavaScriptFromString:js]; if ([tagName isEqualToString:@"img"]) { NSString *imgURL = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", pt.x, pt.y]; NSString *urlToSave = [self.theWebView stringByEvaluatingJavaScriptFromString:imgURL]; NSLog(@"image url=%@", urlToSave); } } 这样我们就可以得到图片的 url,然后下载保存就行了。 利用 ASIHTTPRequest 发送数据到(新浪微博)以 及新浪 API Oauth 认证 利用 ASIHTTPRequest 发送数据到 Sina Weibo Oauth_Sina weibo Oauth.zip 新浪 API 认证,只要改 Key.h 就行了,把里 面的 APPKEY 和 APPSECRET 改成你在新浪申请的就应用 APPKey 然后导入真机开始认证(必须有 WIFI),运行 App,会进入新浪网站要 求你输入你的微博帐号和密码进行认证,认证完成后,把 OAuthC*****umerKey 与 kOAuthC*****umerSecret 记下来 87 附件 2:testPost_SinaWeibo.zip 我写的一个测试 Demo,SDK3.0 测试 Ok 只要把 WeiBoData.h 头文件里面的宏定义 kOAuthC*****umerKey 和 kOAuthC*****umerSecret 改成以上你所记录下来的你自己应用的 kOAuthC*****umerKey 和 kOAuthC*****umerSecret 然后修改 WeiBoData.m 的-(void)getUserInformation 函数,如果你未登 入过帐号,这里先填写你的,帐号和密码 -(void)getUserInformation{ NSUserDefaults*userInformation = [NSUserDefaultsstandardUserDefaults]; username= [userInformation valueForKey:@"userName"]; password= [userInformation valueForKey:@"userPwd"]; if([username length] < 1 && [password length] <1) { //别看了,就这里。。 username= @""; password= @""; } } PS:感谢 Qd 哥,大老晚的帮忙测试解决了一点 问题。(发送图片,路 径那里,[request setData:imageData forKey:@"pic"];)@"pic"我一直 用的@"picture"与@"Photo"再测试。。。。就没想到@"Pic"..我都汗了。。 [url=job.php?action=download&aid=17969] Oauth_Sina weibo 88 Oauth.zip[/url] [url=job.php?action=download&aid=17970] testPost_SinaWeibo.zip[/url] http://www.cocoachina.com/bbs/read.php?tid-38804.html 利用 DTGridView 实现横向滚动的 tableview 我们都知道 tableview 的实现原理,就是创建当前可见个数的 tablecell,滚动过程中只是更改不 可见的 tablecell 到可见的位置并且更新数据。这样可以避免滚动很多屏不用创建相应的视图, 这样就不会造成内存泄漏。 下面是实现的效果图: 下面是实现的代码: 89 #pragma mark DTGridViewDataSource Methods -(NSInteger)numberOfRowsInGridView:(DTGridView *)gv { return 1; } -(NSInteger)numberOfColumnsInGridView:(DTGridView *)gv forRowWithIndex:(NSIn teger)index { return 20; } -(CGFloat)gridView:(DTGridView *)gv heightForRow:(NSInteger)rowIndex { return gv.frame.size.height; } -(CGFloat)gridView:(DTGridView *)gv widthForCellAtRow:(NSInteger)rowIndex colu mn:(NSInteger)columnIndex { return gv.frame.size.width; } -(DTGridViewCell *)gridView:(DTGridView *)gv viewForRow:(NSInteger)rowIndex col umn: (NSInteger)columnIndex { return gv.frame.size.width; } -(DTGridViewCell *)gridView:(DTGridView *)gv viewForRow:(NSInteger)rowIndex col umn:(NSInteger)columnIndex { MyTableCell *cell = (MyTableCell *)[gv dequeueReusableCellWithIdentifier:@"cell"]; if (!cell) { cell = [[[NSBundle mainBundle] loadNibNamed:@"MyTableCell" owner:self opti**** *:nil] objectAtIndex:0]; cell.identifier = @"cell"; } [cell *****howCell]; return cell; 90 } 图像及动画处理二:百叶窗效果 图片切割这后就可以做百叶窗效果了让每片叶子动起来有两种动画方式 scale 和 rotation 91 注:如果处理后的小图片能保存有它们在大图片中的 rect 时,小图片利用起来就特别方便 源码下载: Leaves Leaves http://www.cocoachina.com/bbs/read.php?tid=73570&uid=39045&page=10 图像及动画处理三:WaitingBar 一个很简单的等待页面的等待条的制作,方法如下: -(id)initWithFrame:(CGRect)aFrame color:(UIColor*)aColor timeInterval:(float)aInterval; discussion: arguments- aFrame:视图框架,包括所有小球,其高为小球直径的 2 倍,宽与高的 比值的 2 倍为小球的数量 aColor:小球颜色 aInterval:相邻小球跳动的时间间隔 return value:视图,包括所有小球 以上为公共参数,当然也可以根据需要,自行在方法体中进行更细致和 专门的修改.效果如下图: 92 WaitingBar 图像及动画处理四:旋转等待条(仿苹果) 手写了仿苹果的旋转等待条,并可通过参数设置属性,方法如下: -(id)initWithRadius:(float)aRadius color:(UIColor*)aColor timeInterval:(float)aInterval; discussion- arguments- aRadius: 包含动画的正方形的半个边长,这个正方形的中心在 0 点(0,0).也可以认为是可视 区域的半径 aColor:小长条的颜色 aInterval:相邻小长条跳动的时间间隔 return value:UIView 类型,中心在 0 点(0,0) 若有必要,可在方法体中进行进一步的修改 从效果上来看,与苹果等待条很像,但可放大缩小且不失真,效果如图: iOS5 打开系统 setting 页面 iOS5 的 SDK 现在可以直接打开 setting 页面了,以往的 SDK 则不可以, 当时我还花了大量时间去实现,结果不了了之。 93 如果你想打开 Location Services 的 setting 页面,代码如下: [[UIApplication sharedApplication] openURL:[NSURL URLWit hString:@"prefs:root=LOCATION_SERVICES"]]; 如果想打开 Twitter 的设置: [[UIApplication sharedApplication] openURL:[NSURL URLWit hString:@"prefs:root=TWITTER"]]; 如果想打开蓝牙的设置: [[UIApplication sharedApplication] openURL:[NSURL URLWit hString:@"prefs:root=General&path=Bluetooth"]]; 当然你还可以打开应用的设置: [[UIApplication sharedApplication] openURL:[NSURL URLWit hString:@"prefs:root=Apps&path=Your+App+Display+Name "]]; Your+App+Display+Name 是什么,你应懂的。 不过我试这个的时候没 有打开应用的 setting,反而打开的是系统 setting 页,不知道为何。 94 使用 UIActivityIndicatorView UIActivityIndicatorView 实例提供轻型视图,这些视图显示一个标准的旋 转进度轮。通过将指示器的 animating 属性更新为 YES 来启动它。若要 停止,将该属性设置为 NO。Cocoa Touch 会负责完成其余工作,在视图 不使用时隐藏视图。 iPhone 提供了几种不同样式的 UIActivityIndicatorView 类。 UIActivityIndicator- ViewStyleWhite 和 UIActivityIndicatorViewStyleGray 是最简洁的。黑色背景下最适合白色版本的外观,白色背景最适合灰色 外观(如图 4-7 所示)。它非常瘦小,而且采用夏普风格。选择白色还是 灰色时要格外注意。全白显示在白色背景下将不能显示任何内容。而 UIActivityIndicatorViewStyleWhiteLarge 只能用于深色背景。它提供最 大、最清晰的指示器。 UIActivityIndicatorView 的两种形式 用法一:只显示不停旋转的进度滚轮指示器。 //显示进度滚轮指示器 -(void)showWaiting { progressInd=[[UIActivityIndicatorViewalloc]initWithActivityIndicator Style: UIActivityIndicatorViewStyleWhiteLarge]; progressInd.center=CGPointMake(self.view.center.x,240); [self.navigationController.view addSubview:progressInd]; [progressIndstartAnimating]; } //消除滚动轮指示器 -(void)hideWaiting 95 { [progressIndstopAnimating]; } 用法二:带有半透明背景的进度轮指示器。 //显示进度滚轮指示器 -(void)showWaiting:(UIView*)parent { int width = 32, height = 32; CGRectframe=CGRectMake(100,200,110,70);//[parent frame]; //[[UIScreenmainScreen] applicationFrame]; int x = frame.size.width; int y = frame.size.height; frame = CGRectMake((x - width) / 2,(y - height) / 2, width, height); UIActivityIndicatorView* progressInd =[[UIActivityIndicatorView alloc]initWithFrame:frame]; [progressIndstartAnimating]; progressInd.activityIndicatorViewStyle=UIActivityIndicatorViewStyl eWhiteLarge; frame = CGRectMake((x -70)/2,(y - height) / 2 + height, 80, 20); UILabel*waitingLable =[[UILabel alloc] initWithFrame:frame]; waitingLable.text =@"Loading..."; waitingLable.textColor =[UIColor whiteColor]; waitingLable.font =[UIFont systemFontOfSize:15]; 96 waitingLable.backgroundColor= [UIColor clearColor]; frame = CGRectMake(100, 200, 110, 70);//[parentframe]; UIView *theView = [[UIView alloc] initWithFrame:frame]; theView.backgroundColor =[UIColor blackColor]; theView.alpha = 0.7; [theView addSubview:progressInd]; [theView addSubview:waitingLable]; [progressInd release]; [waitingLable release]; [theView setTag:9999]; [parent addSubview:theView]; [theView release]; } //消除滚动轮指示器 -(void)hideWaiting { [[self.viewviewWithTag:9999]removeFromSuperview]; } iphone 网络 post 连接的两种处理方式(同步和异步) 第一种: 直接返回方式。 -(void)UpadaPost:(NSString *)strcontext URL:(NSString *)urlstr{ 97 NSLog(urlstr); NSLog(strcontext); assert(strcontext != NULL); assert(urlstr != NULL); NSData *postData = [strcontext dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]]; NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; [request setURL:[NSURL URLWithString:urlstr]]; [request setHTTPMethod:@"POST"]; [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:postData]; NSURLResp*****e *respone; NSError *error; NSData *myReturn =[NSURLConnection sendSynchronousRequest:request returningResp*****e:&respone error:error]; NSLog(@"%@", [[NSString alloc] initWithData:myReturn encoding:NSUTF8StringEncoding]); 98 } 第二种,采用事件代理方式(重要) 使用 TouchXML 时,常用到下面的代码 -(void)UpadaPost:(NSString *)strcontext URL:(NSString *)urlstr{ NSLog(urlstr); NSLog(strcontext); assert(strcontext != NULL); assert(urlstr != NULL); NSData *postData = [strcontext dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES]; NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]]; NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease]; [request setURL:[NSURL URLWithString:urlstr]]; [request setHTTPMethod:@"POST"]; [request setValue:postLength forHTTPHeaderField:@"Content-Length"]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:postData]; NSURLConnection *conn=[[NSURLConnection alloc] initWithRequest:request delegate:self]; 99 if (conn) { NSLog(@"Connection success"); [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; [conn retain]; } else { // inform the user that the download could not be made } } --------------------------------------------------------------------------------------------------------------------------- application/x-www-form-urlencoded 、 multipart/form-data 、 text/plain 为什么上传文件的表单里要加个属性 enctype 上传文件的表单中
要加属性 enctype="multipart/form-data",很 多人只是死记硬背知道上传表单要这么写,知其然而不知其所以然。那 到底为什么要添加这个属性呢?它是什么意思呢?它又有什么其他可 选值呢?其实 form 表单在你不写 enctype 属性时,也默认为其添加了 enctype 属性值,默认值是 enctype="application/x- www-form-urlencoded". 这个属性管理的是表单的 MIME 编码,共有三个值可选: ①application/x-www-form-urlencoded (默认值) 100 ②multipart/form-data ③text/plain 其中①application/x-www-form-urlencoded 是默认值,大家可能在 AJAX 里见过这个: xmlHttp.setRequestHeader("Content-Type","application/x-www-form- urlencoded"); 这两个要做的是同一件事情,就是设置表单传输的编码。 在 AJAX 里不写有可能会报错,但是在 HTML 的 form 表单里是可以不 写 enctype="application/x-www-form-urlencoded"的,因为默认 HTML 表 单就是这种传输编码类型。而 ②multipart-form-data 是用来指定传输数 据的特殊类型的,主要就是我们上传的非文本的内容,比如图片或者 mp3 等等。 ③text/plain 是纯文本传输的意思,在发送邮件时要设置这 种编码类型,否则会出现接收时编码混乱的问题,网络上经常拿 text/plain 和 text/html 做比较,其实这两个很好区分,前者用来传输纯 文本文件,后者则是传递 html 代码的编码类型,在发送头文件时才用得 上。①和③都不能用于上传文件,只有 multipart/form-data 才能完整的 传递文件数据。 上面提到的 MIME,它的英文全称是"Multipurpose Internet Mail Extensions" 多功能 Internet 邮件扩充服务,它是一种多用途网际邮件扩 充协议,在 1992 年最早应用于电子邮件系统,但后来也应用到浏览器。 服务器会将它们发送的多媒体数据的类型告诉浏览器,而通知手段就是 说明该多媒体数据的 MIME 类型,从而让浏览器知道接收到的信息哪些 是 MP3 文件,哪些是 Shockwave 文件等等。服务器将 MIME 标志符放 入传送的数据中来告诉浏览器使用哪种插件读取相关文件。 简单说,MIME 类型就是设定某种扩展名的文件用一种应用程序来 打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指 定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些 媒体文件打开方式。 浏览器接收到文件后,会进入插件系统进行查找,查找出哪种插件 可以识别读取接收到的文件。如果浏览器不清楚调用哪种插件系统,它 可能会告诉用户缺少某插件,或者直接选择某现有插件来试图读取接收 到的文件,后者可能会导致系统的崩溃。传输的信息中缺少 MIME 标识 101 可能导致的情况很难估计,因为某些计算机系统可能不会出现什么故 障,但某些计算机可能就会因此而崩溃。 检查一个服务器是否正确设置了 MIME 类型的步骤是: 1. 在 Netscape 浏览器中打开服务器网页 2. 进入"View"菜单,选择"Page Info" 3. 在弹出的窗口中点击上层框架中的"EMBED" 4. 在下层框架中查看 MIME 的类型是否为"application/x-director"或 "application/x-shockwave- flash",如果是上述信息的话表明服务器已经正 确设置了 MIME 类型;而如果 MIME 类型列出的是文本内容、八位一 组的数据或是其它形式均表明服务器的 MIME 类型没有设置正确。 如果服务器没有正确标明其发送的数据的类型,服务器管理员应该 正确添加相关信息,具体操作方法非常简单快捷。 每个 MIME 类型由两部分组成,前面是数据的大类别,例如声音 audio、图象 image 等,后面定义具体的种类。 常见的 MIME 类型 超文本标记语言文本 .html,.html text/html 普通文本 .txt text/plain RTF 文本 .rtf application/rtf GIF 图形 .gif image/gif JPEG 图形 .jpeg,.jpg image/jpeg au 声音文件 .au audio/basic MIDI 音乐文件 mid,.midi audio/midi,audio/x-midi 102 RealAudio 音乐文件 .ra, .ram audio/x-pn-realaudio MPEG 文件 .mpg,.mpeg video/mpeg AVI 文件 .avi video/x-msvideo GZIP 文件 .gz application/x-gzip TAR 文件 .tar application/x-tar Internet 中有一个专门组织 IANA 来确认标准的 MIME 类型, 但 Internet 发展的太快,很多应用程序等不及 IANA 来确认他们使用的 MIME 类型为标准类型。因此他们使用在类别中以 x-开头的方法标识这 个类别还没有成为标准,例如:x-gzip,x-tar 等。事实上这些类型运用 的很广泛,已经成为了事实标准。只要客户机和服务器共同承认这个 MIME 类型,即使它是不标准的类型也没有关系,客户程序就能根据 MIME 类型,采用具体的处理手段来处理数据。而 Web 服务器和浏览器 (包括操作系统)中,缺省都设置了标准的和常见的 MIME 类型,只有 对于不常见的 MIME 类型,才需要同时设置服务器和客户浏览器,以 进行识别。 ---------------------------------------------------------------- 表单中 enctype="multipart/form-data"的意思,是设置表单的 MIME 编码。 默认情况, 这个编码格式是 application/x-www-form-urlencoded,不能用于文件上 传; 只有使用了 multipart/form-data,才能完整的传递文件数据,进行下面的 操作. enctype="multipart/form-data"是上传二进制数据; form 里面的 input 的值 以 2 进制的方式传过去。 form 里面的 input 的值以 2 进制的方式传过去, 所以 request 就得不到值了。也就是说加了这段代码,用 request 就会传递 不成功,取表单值加入数据库时,用到下面的: SmartUpload su = new SmartUpload();//新建一个 SmartUpload 对象 103 su.getRequest().getParameterValues();取数组值 su.getRequest().getParameter( );取单个参数单个值 图像及动画处理五:进度条 -(id)initWithFrame:(CGRect)aFrame frameColor:(UIColor*)aFrameColor barColor:(UIColor*)aBarColor; arguments- aFrame:边框 aFrameColor:边框颜色 aBarColor:进度条颜色 return value-UIView 格式 -(void)setProgress:(float)progress; progress:范围为[0,1] 其它细节,可在方法体内自行修改,显示效果如下图: 104 美化 UILabel 中的字体 UILabdel.zip 图像及动画处理六:选取器(dataPicker 仿苹果) 本文实现了苹果的选取器,与苹果自带的选取器相比有以下特点: 单行,横向放置,大小可配置,内容可配置且方法简单,同时可容纳文 字和图片 105 (1) tasks: -(id)initWithFrame:(CGRect)frame array:(NSArray*)list row:(int)aRow; -(int)index; (2)discussi*****: 1)-(id)initWithFrame:(CGRect)frame array:(NSArray*)list row:(int)aRow; arguments: frame: the frame of the component view list: the content listed on the component view, in format of NSString and UIImage only row: the number of row displaying on the component, limited to be 1,3,5 and 7 only return value: a subclass of UIView 2)-(int)index; return value: to indicate which section is chosen. 106 (3)attenti*****: the background image is in the format "png", so it may looks ugly when scaling it or setting its frame some times. when that happens, it is suggested to rescale it or change the image in the file "bg.png" 效果如图: http://www.cocoachina.com/iphonedev/sdk/2011/1110/3483.ht ml WDataPicker [url=job.php?action=download&aid=26420][/url] iOS5 新特性:强大的 Core Image iOS5 给我们带来了很多很好很强大的功能和 API。Core Image 就是其 中之一,它使我们很容易就能处理图片的各种效果,色彩啊,曝光啊, 饱和度啊,变形啊神马的。 可惜苹果一直没能完善官方文档,也没有推出示例代码,所以国内很多同 学可能还没有开始使用。 但国外的大神们已经证明这是个相当强悍的框架,不仅功能强大,而且 可以直接使用 GPU,效率奇高,甚至可以实时的对视频进行渲染。 下面让我们来看看,如何具体使用它: 107 首先你需要导入 CoreImage.framework 框架;进行 Mac(不是 iOS) 开发的同学请导入 QuartzCore.framework 框架,包含在其中了。 然后我们先来看看 3 个主要的类: CIContext:它与 Core Graphics 和 OpenGL context 类似,所有 Core Image 的处理流程都通过它来进行; CIImage:它用来存放图片数据,可以通过 UIImage,图片文件或像素 数据创建; CIFilter:通过它来定义过滤器的详细属性。 CIContext 有两种初始化方法,分别对应 GPU 和 CPU // 创建基于 GPU 的 CIContext 对象 context = [CIContext contextWithOpti*****: nil]; // 创建基于 CPU 的 CIContext 对象 //context = [CIContext contextWithOpti*****: [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:kCIContextUseSoftwareRenderer]]; 一般采用第一种基于 GPU 的,因为效率要比 CPU 高很多,但是要注意 的是基于 GPU 的 CIContext 对象无法跨应用访问。 比如你打开 UIImagePickerController 要选张照片进行美化,如果你直 接在 UIImagePickerControllerDelegate 的委托方法里调用 CIContext 对象进行处理,那么系统会自动将其降为基于 CPU 的,速 度会变慢,所以正确的方法应该是在委托方法里先把照片保存下来,回 到主类里再来处理。(代码里你将会看到) CIImage 的初始化方法有很多,常用的也是 2 种: // 通过图片路径创建 CIImage 108 NSString *filePath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"]; NSURL*fileNameAndPath = [NSURL fileURLWithPath:filePath]; beginImage = [CIImage imageWithContentsOfURL:fileNameAndPath]; // 通过 UIImage 对象创建 CIImage UIImage *gotImage = ...; beginImage = [CIImage imageWithCGImage:gotImage.CGImage]; CIFilter 初始化: // 创建过滤器 filter = [CIFilter filterWithName:@"CISepiaTone"]; [filter setValue:beginImage forKey:kCIInputImageKey]; [filter setValue:[NSNumber numberWithFloat:slideValue] forKey:@"inputIntensity"]; 第一行:指定使用哪一个过滤器,通过[CIFilter filterNamesInCategory: kCICategoryBuiltIn]能得到所有过滤器的列表 第二行:指定需要处理的图片 第三行:指定过滤参数,每个过滤器的参数都不一样,可以在官方文档 里搜索“Core Image Filter Reference”查看 得到过滤后的图片并输出: CIImage *outputImage = [filter outputImage]; CGImageRef cgimg = [context createCGImage:outputImage fromRect:[outputImage extent]]; 109 UIImage *newImg = [UIImage imageWithCGImage:cgimg]; [imgV setImage:newImg]; CGImageRelease(cgimg); 第一行:通过[filter outputImage]可以得到过滤器输出的图片 第二行:通过 CIContext 的方法 createCGImage: fromRect:得到 CGImage 第三行:转化为 UIImage,这样我们就可以跟据需要显示在界面上了 至此一个过滤周期就完成了,简单来说分以下几个步骤: 1 初始化 CIContext,CIImage 2 初始化 CIFilter 并设置参数 3 得到输出的图片 4 将图片转化成能显示的 UIImage 类型 如果想一张图片有多种过滤效果就需要重复 2,3 两步,并且要将上一 个过滤器输出的图片作为下一个过滤器的参数 简单吧!几行代码就可以得到丰富的效果哦. 目前为止最为接近 iBook 的翻页效果 Book 的翻页效果一直是大家追求的特效,可惜 ios5 前,苹果都没有开放出来。在 ios5 中,苹 果开放了 PageViewController,于是这种效果得到了官方支持。 110 今天要给大家介绍的源码是 ES 实现的翻页效果,是目前为止最接近 iBook 的效果了, 是实时 的哟。目前源码是 alpha 版,开发人员还在继续完善,相信将来可能超越 iBook 哟,大家敬请关 注。 iOS 的 keyChain 2012-2-16 12:29| 发布者: benben| 查看: 1644| 评论: 0 摘要: 说明:每一个 keyChain 的组成如图,整体是一个字典结构.1.kSecClass key 定义属于那一 种类型的 keyChain2.不同的类型包含不同的 Attributes,这些 attributes 定义了这个 item 的具 体信息3.每个 item 可以包含一个密码项来存储对 ... 说明: 每一个 keyChain 的组成如图,整体是一个字典结构. 1.kSecClass key 定义属于那一种类型的 keyChain 2.不同的类型包含不同的 Attributes,这些 attributes 定义了这个 item 的具体信息 3.每个 item 可以包含一个密码项来存储对应的密码 使用: 引入 Security 包,引入文件 #import 添加 -(IBAction)add:(id)sender { if (nameField.text.length > 0 && passwordField.text.length > 0){ // 一个 mutable 字典结构存储 item 信息 NSMutableDictionary* dic = [NSMutableDictionary dictionary]; // 确定所属的类 class 111 [dic setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; // 设置其他属性 attributes [dic setObject:nameField.text forKey:(id)kSecAttrAccount]; // 添加密码 secValue 注意是 object 是 NSData [dic setObject:[passwordField.text dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData]; // SecItemAdd OSStatus s = SecItemAdd((CFDictionaryRef)dic, NULL); NSLog(@"add :%ld",s); } } 查找 // 查找全部 -(IBAction)sel:(id)sender { NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, kSecMatchLimitAll,kSecMatchLimit, kCFBooleanTrue,kSecReturnAttributes,nil]; CFTypeRef result = nil; OSStatus s = SecItemCopyMatching((CFDictionaryRef)query, &result); NSLog(@"se;ect all :%ld",s); NSLog(@"%@",result); } // 按名称查找 -(IBAction)sname:(id)sender { if (nameField.text.length >0){ // 查找条件:1.class 2.attributes 3.search option NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, nameField.text,kSecAttrAccount, kCFBooleanTrue,kSecReturnAttributes,nil]; CFTypeRef result = nil; // 先找到一个 item OSStatus s = SecItemCopyMatching((CFDictionaryRef)query, &result); 112 NSLog(@"select name :%ld",s); // errSecItemNotFound 就是找不到 NSLog(@"%@",result); if (s == noErr) { // 继续查找 item 的 secValue NSMutableDictionary* dic = [NSMutableDictionary dictionaryWithDictionary:result]; // 存储格式 [dic setObject:(id)kCFBooleanTrue forKey:kSecReturnData]; // 确定 class [dic setObject:[query objectForKey:kSecClass] forKey:kSecClass]; NSData* data = http://www.cnblogs.com/v2m_/archive/2012/01/18/nil; // 查找 secValue if (SecItemCopyMatching((CFDictionaryRef)dic, (CFTypeRef*)&data) == noErr) { if (data.length) NSLog(@"%@",[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]); } } } } 修改 -(IBAction)update:(id)sender { if (nameField.text.length >0 && passwordField.text.length > 0){ // 先查找看看有没有 NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, nameField.text,kSecAttrAccount, kCFBooleanTrue,kSecReturnAttributes,nil]; CFTypeRef result = nil; if (SecItemCopyMatching((CFDictionaryRef)query, &result) == noErr) { // 更新后的数据,基础是搜到的 result NSMutableDictionary* update = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)result]; 113 // 修改要跟新的项 注意先加后删的 class 项 [update setObject:[query objectForKey:kSecClass] forKey:kSecClass]; [update setObject:[passwordField.text dataUsingEncoding:NSUTF8StringEncoding] forKey:kSecValueData]; [update removeObjectForKey:kSecClass]; #if TARGET_IPHONE_SIMULATOR // 模拟器的都有个默认的组“test”,删了,不然会出错 [update removeObjectForKey:(id)kSecAttrAccessGroup]; #endif // 得到要修改的 item,根据 result,但要添加 class NSMutableDictionary* updateItem = [NSMutableDictionary dictionaryWithDictionary:result]; [updateItem setObject:[query objectForKey:(id)kSecClass] forKey:(id)kSecClass]; // SecItemUpdate OSStatus status = SecItemUpdate((CFDictionaryRef)updateItem, (CFDictionaryRef)update); NSLog(@"update:%ld",status); 删除 -(IBAction)del:(id)sender { if (nameField.text.length >0){ // 删除的条件 NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:kSecClassGenericPassword,kSecClass, nameField.text,kSecAttrAccount,nil]; // SecItemDelete OSStatus status = SecItemDelete((CFDictionaryRef)query); NSLog(@"delete:%ld",status); //// errSecItemNotFound 就是没有 } } 注意: 1.区别(标识)一个 item 要用 kSecAttrAccount 和 kSecAttrService 114 UIScrollView 的 setContentOffset 方法 在 UIScrollView 中,setContentOffset 方法的功能是跳转到你指定内 容的坐标, [self.scroview setContentOffset:CGPointMake(0, 50)animated:YES]; 这样就行了` 但是,今天突然发现了一个问题: 当设置了 scroview.pagingEnabled = YES;的时候 在你执行 setContentOffset 方法过后,再执行其他操作时,指定内容的 坐标将被还原,pagingEnabled 属性会对它进行重置。 怎样让程序第一次加载的时候默认选中 TableView 的 第一行? 使 tableview 在界面启动后定位在 x 行 在 viewDidLoad 中加入以下代码 NSIndexPath *idxPath = [NSIndexPath indexPathForRow:x inSection:0]; [self.tableView scrollToRowAtIndexPath:idxPath atScrollPosition:UITableViewScrollPositionMiddle animated:NO]; 你先试试,有好多方法的! 获得通讯录中联系人的所有属性 获得通讯录中联系人的所有属性 ,看代码: 115 ABAddressBookRef addressBook = ABAddressBookCreate(); CFArrayRef results = ABAddressBookCopyArrayOfAllPeople(addressBook); for(int i = 0; i < CFArrayGetCount(results); i++) { ABRecordRef person = CFArrayGetValueAtIndex(results, i); //读取 firstname NSString *personName = (NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty); if(personName != nil) textView.text = [textView.text stringByAppendingFormat:@"\n 姓名:%@\n",personName]; //读取 lastname NSString *lastname = (NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty); if(lastname != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",lastname]; //读取 middlename NSString *middlename = (NSString*)ABRecordCopyValue(person, kABPersonMiddleNameProperty); if(middlename != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",middlename]; //读取 prefix 前缀 NSString *prefix = (NSString*)ABRecordCopyValue(person, kABPersonPrefixProperty); if(prefix != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",prefix]; 116 //读取 suffix 后缀 NSString *suffix = (NSString*)ABRecordCopyValue(person, kABPers*****uffixProperty); if(suffix != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",suffix]; //读取 nickname 呢称 NSString *nickname = (NSString*)ABRecordCopyValue(person, kABPersonNicknameProperty); if(nickname != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",nickname]; //读取 firstname 拼音音标 NSString *firstnamePhonetic = (NSString*)ABRecordCopyValue(person, kABPersonFirstNamePhoneticProperty); if(firstnamePhonetic != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",firstnamePhonetic]; //读取 lastname 拼音音标 NSString *lastnamePhonetic = (NSString*)ABRecordCopyValue(person, kABPersonLastNamePhoneticProperty); if(lastnamePhonetic != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",lastnamePhonetic]; //读取 middlename 拼音音标 NSString *middlenamePhonetic = (NSString*)ABRecordCopyValue(person, kABPersonMiddleNamePhoneticProperty); if(middlenamePhonetic != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",middlenamePhonetic]; //读取 organization 公司 NSString *organization = (NSString*)ABRecordCopyValue(person, 117 kABPersonOrganizationProperty); if(organization != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",organization]; //读取 jobtitle 工作 NSString *jobtitle = (NSString*)ABRecordCopyValue(person, kABPersonJobTitleProperty); if(jobtitle != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",jobtitle]; //读取 department 部门 NSString *department = (NSString*)ABRecordCopyValue(person, kABPersonDepartmentProperty); if(department != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",department]; //读取 birthday 生日 NSDate *birthday = (NSDate*)ABRecordCopyValue(person, kABPersonBirthdayProperty); if(birthday != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",birthday]; //读取 note 备忘录 NSString *note = (NSString*)ABRecordCopyValue(person, kABPersonNoteProperty); if(note != nil) textView.text = [textView.text stringByAppendingFormat:@"%@\n",note]; //第一次添加该条记录的时间 NSString *firstknow = (NSString*)ABRecordCopyValue(person, kABPersonCreationDateProperty); NSLog(@"第一次添加该条记录的时间%@\n",firstknow); //最后一次修改該条记录的时间 NSString *lastknow = (NSString*)ABRecordCopyValue(person, 118 kABPersonModificationDateProperty); NSLog(@"最后一次修改該条记录的时间%@\n",lastknow); //获取 email 多值 ABMultiValueRef email = ABRecordCopyValue(person, kABPersonEmailProperty); int emailcount = ABMultiValueGetCount(email); for (int x = 0; x < emailcount; x++) { //获取 email Label NSString* emailLabel = (NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValue CopyLabelAtIndex(email, x)); //获取 email 值 NSString* emailContent = (NSString*)ABMultiValueCopyValueAtIndex(email, x); textView.text = [textView.text stringByAppendingFormat:@"%@:%@\n",emailLabel,emailC ontent]; } //读取地址多值 ABMultiValueRef address = ABRecordCopyValue(person, kABPersonAddressProperty); int count = ABMultiValueGetCount(address); for(int j = 0; j < count; j++) { //获取地址 Label NSString* addressLabel = (NSString*)ABMultiValueCopyLabelAtIndex(address, j); textView.text = [textView.text stringByAppendingFormat:@"%@\n",addressLabel]; //获取該 label 下的地址 6 属性 NSDictionary* personaddress =(NSDictionary*) ABMultiValueCopyValueAtIndex(address, j); NSString* country = [personaddress valueForKey:(NSString *)kABPersonAddressCountryKey]; 119 if(country != nil) textView.text = [textView.text stringByAppendingFormat:@" 国家:%@\n",country]; NSString* city = [personaddress valueForKey:(NSString *)kABPersonAddressCityKey]; if(city != nil) textView.text = [textView.text stringByAppendingFormat:@" 城市:%@\n",city]; NSString* state = [personaddress valueForKey:(NSString *)kABPersonAddressStateKey]; if(state != nil) textView.text = [textView.text stringByAppendingFormat:@" 省:%@\n",state]; NSString* street = [personaddress valueForKey:(NSString *)kABPersonAddressStreetKey]; if(street != nil) textView.text = [textView.text stringByAppendingFormat:@" 街道:%@\n",street]; NSString* zip = [personaddress valueForKey:(NSString *)kABPersonAddressZIPKey]; if(zip != nil) textView.text = [textView.text stringByAppendingFormat:@" 邮编:%@\n",zip]; NSString* coutntrycode = [personaddress valueForKey:(NSString *)kABPersonAddressCountryCodeKey]; if(coutntrycode != nil) textView.text = [textView.text stringByAppendingFormat:@" 国家编号:%@\n",coutntrycode]; } //获取 dates 多值 ABMultiValueRef dates = ABRecordCopyValue(person, kABPersonDateProperty); int datescount = ABMultiValueGetCount(dates); for (int y = 0; y < datescount; y++) { 120 //获取 dates Label NSString* datesLabel = (NSString*)ABAddressBookCopyLocalizedLabel(ABMultiValue CopyLabelAtIndex(dates, y)); //获取 dates 值 NSString* datesContent = (NSString*)ABMultiValueCopyValueAtIndex(dates, y); textView.text = [textView.text stringByAppendingFormat:@"%@:%@\n",datesLabel,datesC ontent]; } //获取 kind 值 CFNumberRef recordType = ABRecordCopyValue(person, kABPersonKindProperty); if (recordType == kABPersonKindOrganization) { // it's a company NSLog(@"it's a company\n"); } else { // it's a person, resource, or room NSLog(@"it's a person, resource, or room\n"); } //获取 IM 多值 ABMultiValueRef instantMessage = ABRecordCopyValue(person, kABPersonInstantMessageProperty); for (int l = 1; l < ABMultiValueGetCount(instantMessage); l++) { //获取 IM Label NSString* instantMessageLabel = (NSString*)ABMultiValueCopyLabelAtIndex(instantMessage, l); textView.text = [textView.text stringByAppendingFormat:@"%@\n",instantMessageLabel]; //获取該 label 下的 2 属性 121 NSDictionary* instantMessageContent =(NSDictionary*) ABMultiValueCopyValueAtIndex(instantMessage, l); NSString* username = [instantMessageContent valueForKey:(NSString *)kABPersonInstantMessageUsernameKey]; if(username != nil) textView.text = [textView.text stringByAppendingFormat:@"username:%@\n",username]; NSString* service= [instantMessageContent valueForKey:(NSString *)kABPersonInstantMessageServiceKey]; if(service != nil) textView.text = [textView.text stringByAppendingFormat:@"service:%@\n",service]; } //读取电话多值 ABMultiValueRef phone= ABRecordCopyValue(person, kABPersonPhoneProperty); for (int k = 0; k @optional //Called when a button is clicked. The view will be automaticallydismissed after this call returns -(void)acti*****heet:(UIActi*****heet *)acti*****heetclickedButtonAtIndex:(NSInteger)buttonIndex; //Called when we cancel a view (eg. the user clicks the Home button).This is not called when the user clicks the cancel button. // Ifnot defined in the delegate, we simulate a click in the cancelbutton -(void)acti*****heetCancel:(UIActi*****heet *)acti*****heet; -(void)willPresentActi*****heet:(UIActi*****heet *)acti*****heet; // before animation and showing view -(void)didPresentActi*****heet:(UIActi*****heet *)acti*****heet; // after animation 144 -(void)acti*****heet:(UIActi*****heet *)acti*****heetwillDismissWithButtonIndex:(NSInteger)buttonInd ex; // beforeanimation and hiding view -(void)acti*****heet:(UIActi*****heet *)acti*****heetdidDismissWithButtonIndex:(NSInteger)buttonInd ex; // after animation @end 7:Please wait ;向用户显示进度。 等待是计算机用户体验的一个部分,iphone 也需要在某些情况下告知 用户你所需要的数据正在加载过程中,请用户耐心等待,并需要让用户 看到 iphone 当前确实在运行而不是已经死机。在 iphone 有 2 中有两 种方式来达到该效果 UIActivityIndicatorView 和 UIActi*****heet 8:UIProgressBar 一个显示进度的进度条控件,他可以让用户看到程序工作的进度,指示 任务完成的程度。 9:使用网络指示器: UIApplication *app =[UIApplication sharedApplication]; app.networkActivityIndicatorVisible =!app.networkActivityIndicatorVisible; http://www.cocoachina.com/bbs/read.php?tid=73570&uid=390 45&page=16 152 楼: 发表于: 2012-01-04 14:34 发自: Web Page 全看 小 中 大 本帖属于 CocoaChina 会员发表,转帖请写明来源和帖子地址 145 一些 iOS 高效开源类库 因为 iOS SDK 相对比较底层,所以开发者就得受累多做一些体力活。不过幸运的是,有很多第三方 的类库可以用来简化很多不必要的工作。整理了一下在本人学习过程中用到的一些比较有用 Object ive-C 开源类库,既是做一个总结,同时也希望通过这些分享,能提高各位的开发效率。 KissXml——xml 解析库 相关教程:http://www.iteye.com/topic/625849 http://sencho.blog.163.com/blog/static/83056228201151743110540/ 很方便的一个 xml 解析器,支持 Xpath 查询。 skpsmtpmessage——Quick SMTP 邮件发送 svn checkout http://skpsmtpmessage.googlecode.com/svn/trunk/ skpsmtpmessage-rea d-only github: git clone https://github.com/kailoa/iphone-smtp.git 相关教程:http://disanji.net/2011/01/28/skpsmtpmessage-open-source-framework/ skpsmtpmessage 是由 Skorpiostech, Inc.为我们带来的一个 SMTP 协议的开源实现,使用 Obj ective-c 实现,iOS 系统的项目可以直接调用。 jsonframework——JSON 支持 相关教程:http://blog.csdn.net/xiaoguan2008/article/details/6732683 它是一个开源框架,基于 BSD 协议发布。由于 json-framework 是开放源代码的,当你需要使用它 时你只需将 json 的源代码加入到你的工程中。 ASIHttpRequest——HTTP Network 库 ASIHttpRequest 库极大的简化了网络通 信,提供更先进的工具,例如文件上传工具,重定向处理 工具、验证工具、等等。 MBProgressHUD——进展指示符库 苹果的应用程序一般都会用一种优雅的,半透明的进度显示效果,不过这个 API 是不公开的,因此 你要是用了,很可能被清除出 AppStore。而 MBProgressHUD 提供了一个替代方案,而且在用户 角度上,实现的效果根本看不出和官方程序有什么差别。同时还提供了其他附加功能,比如虚拟进 展 指示符,以及完成提示信息。整合到项目里也很容易,这里不细谈了。 146 zxing——二维码扫描库 支持条形码/二维码扫描的图形处理库,这是一个 java 库,在 android 上的功能比较完整。同时该 库也支持 ios,但只能支持二位条形码的扫描。 kal——iPhone 日历控件 一个类似于 ios 系统默认日历开源日历库,支持添加事件,自定义日历样式等功能。 Facebook iOS SDK——Facebook API 类库 大体来讲就是 iPhone 上的 Facebook login,完全支持 Facebook Graph API 和 the older RES T api。 shareKit——分享库 相关 demo:http://www.cocoachina.com/bbs/read.php?tid-71760.html 分享到开心,豆瓣,腾讯,新浪微博的 api 所用到的强大的分享库。 SDWebImage——简化网络图片处理 用 SDWebImage 调用网站上的图片,跟本地调用内置在应用包里的图片一样简单。操作也很简单。 GData client——iPhone 上所有 Google 相关服务的类库 名字就说明一切了。跟 Google 相关的,值得一提的是,这个项目很开放。有很多示例程序供下载。 CorePlot——2D 图形绘图仪 CorePlot 有很多解决方案将你的数据可视。同时也会提供各种迷人的图形效果,比如棒状图、饼状 图、线状图等等,在他们网站上也提供了大量的范例图形,很多股票价格应用,游戏分数,个人财 务管理都在用。 Three20——类似于 Facebook 的优秀的 UI 库 Three20类库是 Facebook 自己做的,大而全是他最大的特色。把他整合到已有的项目中可能得费 点周折,不过如果一开始你就用上了 Three20,尤其是牵扯到很多 web 相关的项目的时候,你就能 深刻体会到神马叫给力了。 FMDatabase——SQLite 的 Objective-C 封装 是 SQLite 的 CAPI 對初學者來說實在太麻煩太瑣碎,難度太高。FMDB 說穿了其實只是把 CAPI 包裝成簡單易用的 Objective-C 类。對于 SQLite 初學者來說,大大減低了上手的難度。有了 FMD B,寫程式時只要專心在 SQLite 的語法上,而不用去理那堆有看沒有懂的 CAPI,實在是件快樂的 事情。 147 读取 iOS 代理设置的代码 公司网络很多都是有代理设置的,如果设备通过 wifi 上网,就要过公司 网络代码。 于是想到一个问题:如何读取 iOS 设备的代理设置? 用过 ASIHTTPRequest 这个开源网络库,它可以读取代理设置,于是 我在源码中发现读取代理设置的方法,我已把代码提取出来: NSDictionary *proxySettings = NSMakeCollectable([(NSDiction ary *)CFNetworkCopySystemProxySettings() autorelease]); NSArray *proxies = NSMakeCollectable([(NSArray *)CFNetwor kCopyProxiesForURL((CFURLRef)[NSURL URLWithString:@"http: //www.google.com"], (CFDictionaryRef)proxySettings) autorele ase]); NSDictionary *settings = [proxies objectAtIndex:0]; NSLog(@"host=%@", [settings objectForKey:(NSString *)kCFPr oxyHostNameKey]); NSLog(@"port=%@", [settings objectForKey:(NSString *)kCFPr oxyPortNumberKey]); NSLog(@"type=%@", [settings objectForKey:(NSString *)kCFPr oxyTypeKey]); 需要 CFNetwork.framework 本帖属于 CocoaChina 会员发表,转帖请写明来源和帖子地址 新浪微博 iOS 版 SDK 框架学习笔记 本文为论坛会员 3h2om 分享,对新浪微博 iOS 版 SDK-“宝玉 XP”框架 进行研究所写的学习笔记,非常详细和精彩。 在学习的过程中,对新浪微博 iOS 版 SDK-“宝玉 XP”框架进行了学习(下 148 载地址:https://github.com/JimLiu/WeiboSDK),在没有获得相应 的说明文档前提下,要理解其中的内幕对于初涉 OPENAPI 的新人来说 不算是件易事,为了满足一窥究竟的一惯心理,我在对其源代码进行一 番抽丝剥茧式的跟踪后,基本上搞懂了框架内各类之间的调用关系,初 略地理解了各类的大概用途,也对 OAuth 认证机会有了进一步的认识。 充分理解该框架后将对于开发基于 HTTP 协议的类似项目有一定的参考 作用。现将我的这种“理解”简要地进行整理,愿能对学习并想了解该 SDK 的人有所帮助。 一、组成和关系 该框架除了由大量的诸如数据连接、数据模型等基础类支撑外,其主要 的功能由 RootViewControllerComposeViewController、 OAuthcontroller、OAuthEngine URLConnection、WeiboClient 6 个类完成,RootViewController 是整个框架的视图控制器,它作为应 用程序委托中的 UINavigationController 类型的输出口,控制该系统 的主视图以呈现给用户。ComposeViewController 类是作为 RootViewController 类的组成部分存在的,用以控制写微博时所呈现 出的发送视图。OAuthcontrller 用以控制完成 OAuth 认证机制所需要 的视图。类 OAuthEngine、URLConnection、WeiboClient 为服务 类,为各视图控制类提供服务,类 OAuthEngine 为完成 OAuth 方式 认证提供了支持,通过该方法完成授权和认证过程,URLConncetion 和 WeiboClient 建立网络连接,实现新浪提供的 OPEN API 功能,设 置并完成 HTTP 请求以发送和接受数据。 149 二、各类简单说明 1、RootViewController 类 该类是整个系统的视图控制类,是系统与外面交互的入口,也是系统的运行的驱动点,它关联 了 OAuthEngine 等服务类,在该类通过调用其他各服务类提供的功能,完成从用户的登录授权 认证到把微博客。在 viewDidLoad 方法中,完成了对用于保存微博列表的 NSMutableArray 类的 status 的初如化。接着在 viewDidAppear 方法中,用服务方提供的三个 URL 和应用程序在新浪 方获取的 Key 和 Secret 完成其成员 OAuthEngine 类型的_engine 的初始化工作,为 OAuth 认证 提供了准备。在此之类,就调用自身 loadTimeline 方法,来完成包括 OAuth 认证、请求数据等 一系列动作,从此,系统运行的万里长征正式踏上征程。 2、ComposeViewController 类 该类所控制的视图是 RootViewController 类所控制的视图的组成一部分,当用户点击主视图上 150 面导航栏中的发送按钮,该类所控制的视图将呈现出来,主要用于发送微博。Draft 类描述发送 微博时的附件信息,newTweet 方法的主要作用是初始化 draft,为发送新的微博上传相关附件提 供对应的对象,send 方法用于调用的 OPENGAPI 完成发送这一动作,insert 方法在发送微博时 插入附件时被调用。 3、OAuthController 类该类主要用于调用 OAuthEngine 类的服务来完成 OAuth 认证机制中的认 证工作的三步认证,它由 RootViewController 类中的 loodTimeline 方法调用。该类中的_webView 成员是用来显示用户授权界面的 UIVebView 控件,因此就实现了 UIWebViewDelegate 委托,用 委托中相应的方法协调完成认证过程。该控件的 URLRequest 属性被设置为三步认证中的第二 个 URL,用于获取用户授权的 Request Token。 4、OAuthEngine 类该类是 OAuth 认证实现的核心类,为其他类提供认证服务。调用 requestRequestToken 将获取到经过授权的获取用户授权的 Request Token,调用 requestAccessToken 将用授权的 Request Token 换取 Access Token。 5、URLConnection 和 WeiboClient 类 WeiboClient 是 URLConnection 的子类,WeiboClient 实现 了 OPENAPI 方法,设置并完成 HTTP 请求以发送和接受数据,并用指定的 action 来处理通 过的 HTTP 请求得到数据。 二、进入用户授权界面的步骤 系统运行后,经过 RootViewController 类的 viewDidApper 事件方法,调用其 lodadTimeline 方法完成 OAuth 认证机制的第一步(获取未授权的 Request Token),之后进入到 OAuthController 151 类的 loadView 方法,该方法中通过语句:“*request = _engine.authorizeURLRequest; [_webView loadRequest: request];”完成认证机制中第二步,接着进入到 webViewDidFinshg 事件方法,进入到授权界面。具体细节比较复杂,见下面的(进入授权界面的时序图),由于没 有专门的 UML 工具,加之涉及到的对象较多,时序图没有列出所有的对象和细节。在进入 RootViewController 的 viewDidAppear 事件方法中,判断该类中的_engine 是否已经存在,如果 没有就对其初始化,接着调用“[self performSelector:@selector(loadTimeline) withObject:nil afterDelay:0.0]; ”进入到 loadTimeline 方法中。loadTimeline 方法首先用本类中的实例成员_engine 作为参数,着手构建 OAuthController 对象,下一步就判断刚刚构建的动作是否真的构建了对象, 如果对象存在,就立即转入到刚刚构建 OAuthController 类对象所对应的视图,即进入到授权界 面,以供用户进行授权。如果不存在 OAuthController 对象,就说明已经完成了认证,不用进入 到授权界面,直接调用 loadData 加载与授权用户相关的微博信息后,进入到 RootViewController 对应视图即可。其中创建 OAuthController 对象是关键,在其中进行了判断,如果已经授权了或 者 cache 中还保存着相应的 cooke 的话,就退出,否则就用_engine 为参数,调用 OAuthController 的初始化方法,初始化后又判断_engine.OAuthSetup 的值,如果为 NO 则表示还没有进行过认 证(若为 YES 则表示已经完成了认证步中的第一步),于是就调用¬¬¬¬_engine requestRequestToken 来完成认证的第一步操作。OAuthEngine 类中 requestRequestToken 方法的 调用过程:该方法是一中间方法,起到过渡作用,它只是调用 requestURL: token:*****uccess: onFai:方法,后一个方法用指定的 URL 和两个方法 SEL 作为参数,其中两个 SEL 分别用于当该 HTTP请求成功或失败返回时对应的处理方法。它分别指定为setRequestToken和outhTicketFailed 方法。 OAuthEngine 类中的 requestURL:token:*****uccess:onFail 方法又用给定的 URL 和 token 构建了 OAMutableURLRequest 对象,然后构建 OADataFetcher 对象,并把它来提取基于 OAMutableURLRequest 网络连接的数据(调用*****ucess:和 onFail 方法)。如果成功,就调用 上面传过来的 OAuthEngine 类中 setRequestToken 方法处理认证第一步的返回数据。 setRequestToken 只是用得到的数据填充用 OAuthEngine 类中的_requestToken。 至此,已经完成了构建 OAuthController 对象,并工作完成了 OAuth 认证中的第一步了。接着, 程序一路回退,回退至 loadTimeline 方法中: UIViewController *controller = [OAuthController controllerToEnterCredentialsWithEngine: _engine delegate:self]//通过以上的过程,该句已经执行完毕 if(controller)//第一次进入时总需要认证,总会构建 controller,所以为为真值 [self presentModalViewContrllor: controller animated:YES];// else [self loadData];由于 presentModalViewContrllor 是异步方法,调用后,loadTimeline 就当即结束了。 经过几番系统 的“原子操作后”,进入到 OAuthController 类中的 loadView 事件方法中,在该事 件方法中,将完成 OAuth 认证机制中的第二步过程。该方法对即将出现的授权界面中的一些 UI 进行了初始化设置后,调用: NSURLRequest *request = _engine.authorizeURLRequest; [_webView loadRequest:request]; 在 OAuthEngine 类的 authorizeURLRequest 方法中,首先判断_requestToke.key 是否为空(由于 我在第一步的认证过程上,已经设置好了),若不为空,则用 authorizeURL 和_requestToken 等 为参数,构建 OAMutableURLRequest 对象,并基于此设置好相关的 HTTP 请求,并返回供 _webView 加载,loadView 结束后再进入_webViewDidFinishLoad 事件方法。 至此,授权界面已经出现,以供用户对其授权,界面如下: 152 此过程的详细调用情况见下图: 153 进入授权界面的时序图 154 三、用户授权后并进入到微博主界面的调用关系 155 当用户在授权界面上填写好帐号和密码后,点击“授权”后,触发 OAuthController 类的 webViewStartLoadWithRequest 事件和 webViewDidFinishLoad 方法,在 webViewDidFinishLoad 中调用 gotPin 方法得到 Access Token 完成 OAuth 认证机制的最后一步。之后 RootViewController 类中的 viewDidAppear 事件方法被触发,在该方法中,调用 loadData 方法,完成数据的加载工 作,然后就显示了微博的主列表界面。 具体细节比较复杂,见下面的(进入授权界面的时序图),由于没有专门的 UML 工具,加之涉 及到的对象较多,时序图没有列出所有的对象和细节。该时序图仅描述用户授权过程(即 OAuth 认证的最后步),没有描述认证后其中加载数据的详细过程,详细过程见方法调用图。 156 157 158 几个重要方法: RootViewController 类中 loadTimeline 方法:该方法是本框架中的一个主要中转方法,此方法调 用 OAuthController 类的 controllerToEnterCredentialsWithEng ine 完成认证中的前两步操作,调用 loadData 方法完成认证的第三步和加载数据过程。 159 OAuthEngine 类中的 requestRequestToken 方法用来完成认证第步的请求,setRequestToken 方法 用来处理接收数据,并设置好_requestToken;requestAccessToken 方法用来完成认证第三步, setAccessToken 方法用来处理上步接收的数据,并设置_accessToken 从而完成整个认证操作。OAuthController 类中的 locateAuthPinInW ebView 方法用来从返回的 HTTP 请求中获取 PIN 码,即获取用授权的 Request Token,完成认证 的第二步,用此来作为第三步的参数。 RootViewController 类中的 timelineDidReceiveForComment 方法用来处理接收从 HTTP 请求返回 中的数据,在此方法中实现微博的数据的反序列化工作。 四、几点发现 1、OAuthController 类中的 webViewDiFinishLoad 事件方法中通过调用:_delegate OAuthController:self authenticatiedWit ntroller:authenticatedWithUserName:_engine.username 方法间接地又调用了一次 loadTimeline 和 loadData 方法生成 WeiboCleint 对象并进行认证和加载数据操作,但由于 WeiboClient 对象是自动销毁后,程序立即进入到了 RootViewController 类的 viewDidApper 事件方法,在这个方法中又调用 loadTimeline,以至于上 面的操作是多余的,等于在进行了两次认证(第二步和第三步)和加载数据操作。 2.关于 OAuthController 类中的 webView:shouldStartLoadWit hRequest 事件方法(视图类的相关事件方法也一样)连续被调用多次问题。这是一个很有趣的 问题,至今我没有发现什么原因。比如说要转到(presentModalViewController:)一个视图(该视 图实现了 UIWebViewDelegate 委托),该视图控制器中实现了 viewDidLoad 和 loadView 事件方 法,如果在这些方法中没有调用其父类的对应方法,则被转到的视图控制器中的这两个方法会 连接地被调用,我一次试验是连续地被调用了11次?但如果加上 super viewDidLoad 的话只 正常地被调用1次。至于是什么原因,我至今未懂。 Xcode4.2 本地化 总结 1 xcode4.2,如果是简体中文,把国际化的文件放到 zh-Hans.lproj 中就显示正常了。如果放到 zh.lproj 中就不可以 160 2 字符串 1)在项目的“supporting files”目录中右键“new file”然后在弹出窗口左侧选择 IOS 的 resour ce 项,在右侧就可以看到“String File”的图标。创建这个文件,新建的文件名要写成“Localiza ble.strings” 必须是 2)点击刚才创建的这个文件,选择的菜单中的“view”-》“utilities”-》“file inspect” 右侧会 看到一些属性的信息 3)找到 Localization 这项,现在应该是空的,点“+”进行国际化的添加。因为我只制作了中文 和英文,所以我加了“English”和“Chinese”,这里要注意的是“Chinese”要选择“zh_Hans”,这 个是简体中文。 4)添加好后就可以看到你项目目录下会生成对应的目录,zh-Hans.lproj 和 en.lproj 目录里 面就是 Localizable.strings 的文件 5)在项目中可以看到原先创建的 Localizable.strings 文件的左侧会多出一个三角图标,点击 后会扩展出2个文件,一个中文,一个英文的。点击每个文件进行编辑就可以了。 6)文件中的格式是“Key”=“value”; 等号 分号都必须是英文状态。 7)在程序中需要使用国际化字符串的时候,调用 NSLocalizedString(@"Key", nil)就可以进行 字符串的显示。其中第一个字符串就是文件中的 key,第二个字符串可以使用 nil 代替也可以写 一些注释。 3应用程序名称 1)创建一个空文件,取名为 InfoPlist.strings 一般程序可以会自动生产 这个文件。 2)对 InfoPlist.strings 进行。 单击 InfoPlist.strings 。选择 “view”-》“utilities”-》“file i nspect”。 在 Localization 选项下 点击+加号 添加 chinese (zh-Hans) 类型的 为简体中文 。 english 应该会自动添加上 。 然后在 InfoPlish.strings 下会多两个 english chinese 版本的文件。 3)在这 english chinese 版本的文件。 编辑不同的 InfoPlist.strings 文件,设置显示名字 CFBundleDisplayName = "名字"; 4)编辑 Info.plist,添加一个新的属性 Application has localized display name, 设置其类 型为 boolean,并将其 value 设置为选中状态 先总结这些 161 4 nib 文件 和 图片 首先说明一下 图片是不能直接本地化 的。 先把 nib 文件本地化后 在把相应的图片本地化 过程类似。 本地化 nib 文件 。 1) 单击 nib 文件 然后选择“view”-》“utilities”-》“file inspect” 右侧 会看到一些属性的信息。 或者快捷键 command + option+ 1。 在 Localization 选项下 点击+加号 添加 chinese (zh-Hans) 类型的 为简体中文 。 en glish 应该会自动添加上 。 本地化图片。 必须先本地化好 nib 文件 后 才能本地化相关的图片。 2) 单击图片 。 然后选择“view”-》“utilities”-》“file inspect” 右侧会看到一些属性的信息。 或者快捷键 co mmand + option+ 1. 在 Localization 选项下 点击+加号 添加 chinese (zh-Hans) 类型的 为简体中文 。 en glish 应该会自动添加上 。 如何让你的 iPhone 程序支持多语言环境(本地化) 我们知道,Cocoa 程序是完全支持多语言的,包括 iPhone 中的程序。这里简单介绍一下制作多语 言 iPhone 程序的方法,同时也是 iPhone 中显示中文的最好办法。 XCode 中支持多语言 在项目中点右键,选择 Add->New File 在列表中选择 Strings File 可以叫做 Localizable.strings,也可以取别的名字,比如 MyApp.strings 选中 MyApp.string,按 command+i,点击左下方的 Make File Localizable,你会看到 General 中的 Localizations 里面已经有了 English。 点击下面的 Add Localization,添加一个 zh_CN(简体中文)和一个 zh_TW 或者 zh_HK(繁体 中文)。注意 zh_Hans(简体中文)和 zh_Hant(繁体中文)在 Mac 中可以正确识别,但是在 iPhone 中不能正确识别。 如果你想支持别的语言,可以添加: 日语:Japanese 德语:German 162 西班牙语:Spanish 法语:French .strings 文件的内容可以是标准的 plist 格式,也可以是旧的列表格式: mykey myvalue …. 字符串如果要换行的话,直接按回车换行,不要写成\n 这种形式。 或者直接使用旧式的列表格式: "mykey" = "myvalue"; … 注意每行后面加分号。 如果你使用的是 Localizable.strings,那么你在程序中可以这样获取字符串: NSLocalizedString(@"mykey", nil) 如果你使用的是自定义名字的.strings,比如 MyApp.strings,那么你在程序中可以这样获取字符串: NSLocalizedStringFromTable (@"mykey",@"MyApp", nil) 这样即可获取到"myvalue"这个字符串,可以是任何语言。 如果你使用的是官方的 iPhone SDK,那么项目中包含这个.strings 就可以直接使用了,如果你使用 的是 toolchain,那么需要修改一下 Makefile: 增加 LANG_FILES=$(wildcard *.lproj) LANG_FILES_ABS=$(addprefix $(SRCROOT)/,$(LANG_FILES)) RESOURCES=Resources 找到 $(APP_ABS): $(INFOPLIST_ABS) 在最后一行增加: cp -R $(LANG_FILES_ABS) $(APP_ABS)/$(RESOURCES) 这样即可让你的 iPhone 程序支持多语言环境了。 当然如果你不怕麻烦,也可以每次都手工把这 些.lproj 目录复制到编译好的 Bundle 里,也是一样的。 163 Interface Builder 建立 UIView 无法 全屏的解决方法 Interface Builder 默认新建的 XIB 的 UIView 是 320*460 分辨率,所以进入全屏时,底部会出 现一个 20 像素的空白条。就像下图这种效果 164 解决方法很简单,把分辨率改成 320*480 即可,比如 self.view.frame=CGRectMake(0,0,320,480); iphone 开发中图像处理四个要点 对于 iOS 开发者而言,图像处理是一个非常重要的方面。iPhone 图像通 常存储在以下 4 个地方: 相册(PhotoAlums):用户可以使用 UIImagePickerController 类提 供的交互对话框从该相册中获取图像。 应用程序包:将图像与可执行程序、Info.plist 文件和其他资源一 同存储,用户可以通过本地文件路径由 imageNamed:方法来读取这些基 于包的图像。 沙盒:借助沙盒,可以将文件存储到 Documents、Library 和 tmp 文件夹中。 因特网(Internet):应用程序可通过 URL 资源从网上下载图像。 图像文件的位置决定着读取该文件的具体方式。相册中的图片及其 路径无法直接从应用程序访问,只有终端用户能够浏览和选择图像,使 所选图像对应用程序可用。图像也不能由 URL 直接初始化。图像源不同 读取方式也不同: 1. 从应用程序包加载图像 UIImage 类提供了一种加载应用程序包中存储的任意图像的简单方 法,即通过文件名及其扩展名调用 imageNamed:方法。 myImage = [UIImage imageNamed:@icon.png]; 为避免本地图像缓存及其有效利用内存空间的问题,还可用 imageWithContentsOfFile:替换,这个方法会返回从某一具体路径中加 载的图像,这个路径需以参数形式提供。当然,若要从应用程序包中获 取图像路径,可以查询 NSBundle 类为给定资源查找路径。示例代码: NSString *path = [[NSBundle mainBundle] pathForResource:@icon ofType:@png]; myImage = [UIImage imageWithContentsOfFile:path]; 165 2. 从沙盒加载图像 默认情况下,每个沙盒包含 3 个文件夹:Documents、Library 和 tmp。图像等由应用程序生成的数据通常位于 Documents 文件夹内。在 iPhone 开发中可以通过调用实用工具主目录函数可靠地定位顶级沙盒 文件夹。通过 NSHomeDirectory()返回结果,我们可以向下导航一级到 Documents 文件夹,完全可以保证正确的位置。示例代码: NSString *documentsFolder() return [NSHomeDirectory() stringByAppendingPathComponent:@Documents]; // 加载图像 path = [documentsFolder() stringByAppendingPathComponent:@image.png]; return [UIImage imageWithContentsOfFile:path]; 3. 从 URL 资源加载图像 UIImage 类可以从 NSData 实例加载图像,但它不能直接从 URL 字符 串或 NSURL 对象加载图像。因此,只能为 UIImage 提供已经从 URL 下载 的数据(即要创建由 URL 内容初始化的 NSData 实例)。 NSURL *url = [NSURL URLWithString:@http://www.cnblogs.com/lovecode/images/demo.jp g]; UIImage *img = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]; // 类似地我们可以直接创建个类方法 // 由具体的一个 URL 字符串,返回通过该资源构建的 UIImage + (UIImage *) imageFromURLString: (NSString *) urlstring return [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:urlstring]]]; 4. 从相册加载数据 UIImagePickerController 类帮助我们从 iPhone 相册中选择图像。 它提供一个独立的视图控制器,以模态形式呈现视图。该控制器发回的 委托消息能够反映用户选择的图像。 UIImagePickerControllerSourceTypePhotoLibrary 所有同步到 iPhone 的图像以及包括用户拍摄的图片在内的任何相册。 UIImagePickerControllerSourceTypeSavedPhotosAlbum 仅含相 册。 166 UIImagePickerControllerSourceTypeCamera 允许用户使用 iPhone 内置的摄像头拍照。 图像拾取器的委托必须遵守两个协议: UINavigationControllerDelegate 和 UIImagePickerControllerDelegate。在接口中一定要为设置为拾取器 委托的对象声明这两个协议。 网上常用免费 WebServices 集合 天气预报 Web 服务,数据来源于中国气象局 公用事业 http://www.webxml.com.cn/WebServices/WeatherWebService.asmx 中国股票行情分时走势预览缩略图 http://www.webxml.com.cn/webservices/ChinaStockSmallImageWS.asmx 中国股票行情数据 WEB 服务(支持深圳和上海股市的基金、债券和股票) http://www.webxml.com.cn/WebServices/ChinaStockWebService.asmx 国内飞机航班时刻表 WEB 服务 公用事业 http://www.webxml.com.cn/webservices/DomesticAirline.asmx 中国电视节目预告(电视节目表)WEB 服务 公用事业 http://www.webxml.com.cn/webservices/ChinaTVprogramWebService.asmx 火车时刻表 (第六次提速最新列车时刻表) 公用事业 http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx 中文 <-> 英文双向翻译 WEB 服务 获得标准数据 http://www.webxml.com.cn/WebServices/TranslatorWebService.asmx 验证码图片 WEB 服务 支持中文、字母、数字 图像和多媒体 http://www.webxml.com.cn/WebServices/ValidateCodeWebService.asmx 中国邮政编码 <-> 地址信息双向查询/搜索 WEB 服务 获得标准数据 http://www.webxml.com.cn/WebServices/ChinaZipSearchWebService.asmx IP 地址来源搜索 WEB 服务(是目前最完整的 IP 地址数据) 获得标准数据 http://www.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx 国内手机号码归属地查询 http://webservice.webxml.com.cn/WebServices/MobileCodeWS.asmx 外汇-人民币即时报价 167 http://webservice.webxml.com.cn/WebServices/ForexRmbRateWebService.asmx 腾讯 QQ 在线状态 WEB 服务 http://webservice.webxml.com.cn/webservices/qqOnlineWebService.asmx 中文简体字<->繁体字转换 WEB 服务 http://webservice.webxml.com.cn/WebServices/TraditionalSimplifiedWebService.asmx IP 地址搜索 WEB 服务包含中国和国外已知的 IP 地址数据,是目前最完整的 IP 地址数据,记 录数量现已超过 37 万条并还在不断更新和增加中 http://webservice.webxml.com.cn/WebServices/IpAddressSearchWebService.asmx 一些 iOS 高效开源类库 因为 iOS SDK 相对比较底层,所以开发者就得受累多做一些体力活。不过幸运的是,有很多第三方 的类库可以用来简化很多不必要的工作。整理了一下在本人学习过程中用到的一些比较有用 Objective-C 开源类库,既是做一个总结,同时也希望通过这些分享,能提高各位的开发效率。 KissXml——xml 解析库 相关教程:http://www.iteye.com/topic/625849 http://sencho.blog.163.com/blog/static/83056228201151743110540/ 很方便的一个 xml 解析器,支持 Xpath 查询。 skpsmtpmessage——Quick SMTP 邮件发送 svn checkout http://skpsmtpmessage.googlecode.com/svn/trunk/ skpsmtpmessage-read-only github: git clone https://github.com/kailoa/iphone-smtp.git 相关教程:http://disanji.net/2011/01/28/skpsmtpmessage-open-source-framework/ skpsmtpmessage 是由 Skorpiostech, Inc.为我们带来的一个 SMTP 协议的开源实现,使用 Objective-c 实现,iOS 系统的项目可以直接调用。 jsonframework——JSON 支持 相关教程:http://blog.csdn.net/xiaoguan2008/article/details/6732683 它是一个开源框架,基于 BSD 协议发布。由于 json-framework 是开放源代码的,当你需要使用它 时你只需将 json 的源代码加入到你的工程中。 ASIHttpRequest——HTTP Network 库 168 ASIHttpRequest 库极大的简化了网络通 信,提供更先进的工具,例如文件上传工具,重定向处理 工具、验证工具、等等。 MBProgressHUD——进展指示符库 苹果的应用程序一般都会用一种优雅的,半透明的进度显示效果,不过这个 API 是不公开的,因此 你要是用了,很可能被清除出 AppStore。而 MBProgressHUD 提供了一个替代方案,而且在用户 角度上,实现的效果根本看不出和官方程序有什么差别。同时还提供了其他附加功能,比如虚拟进 展 指示符,以及完成提示信息。整合到项目里也很容易,这里不细谈了。 zxing——二维码扫描库 支持条形码/二维码扫描的图形处理库,这是一个 java 库,在 android 上的功能比较完整。同时该 库也支持 ios,但只能支持二位条形码的扫描。 kal——iPhone 日历控件 一个类似于 ios 系统默认日历开源日历库,支持添加事件,自定义日历样式等功能。 Facebook iOS SDK——Facebook API 类库 大体来讲就是 iPhone 上的 Facebook login,完全支持 Facebook Graph API 和 the older REST api。 shareKit——分享库 相关 demo:http://www.cocoachina.com/bbs/read.php?tid-71760.html 分享到开心,豆瓣,腾讯,新浪微博的 api 所用到的强大的分享库。 SDWebImage——简化网络图片处理 用 SDWebImage 调用网站上的图片,跟本地调用内置在应用包里的图片一样简单。操作也很简单。 GData client——iPhone 上所有 Google 相关服务的类库 名字就说明一切了。跟 Google 相关的,值得一提的是,这个项目很开放。有很多示例程序供下载。 CorePlot——2D 图形绘图仪 CorePlot 有很多解决方案将你的数据可视。同时也会提供各种迷人的图形效果,比如棒状图、饼状 图、线状图等等,在他们网站上也提供了大量的范例图形,很多股票价格应用,游戏分数,个人财 务管理都在用。 Three20——类似于 Facebook 的优秀的 UI 库 Three20 类库是 Facebook 自己做的,大而全是他最大的特色。把他整合到已有的项目中可能得费 点周折,不过如果一开始你就用上了 Three20,尤其是牵扯到很多 web 相关的项目的时候,你就能 深刻体会到神马叫给力了。 FMDatabase——SQLite 的 Objective-C 封装 是 SQLite 的 CAPI 對初學者來說實在太麻煩太瑣碎,難度太高。FMDB 說穿了其實只是把 CAPI 包裝成簡單易用的 Objective-C 类。對于 SQLite 初學者來說,大大減低了上手的難度。有了 FMDB, 寫程式時只要專心在 SQLite 的語法上,而不用去理那堆有看沒有懂的 CAPI,實在是件快樂的事情。 169 iPhone 开发之 -[UIView beginAnimati*****:context:]与[UIView animateWithDuration:animati*****:]值得 注意区别 看过官方文档的都知道,官方推荐在 iOS4 以后使用[UIView animateWithDuration:animati*****:],而不是原来的[UIView beginAnimati*****:context:],来完成动画,虽然二者功能几乎完全相 同,但使用前者在一些情况下会方便不少,这些内容可以参考官方文档 View Programming Guide For iOS 的 Animation 一节. 二者有一个值得新手注意的区别就是[UIView animateWithDuration:animati*****:]默认会禁止触摸,手势等的响应, 这可以通过设置 option 选项来解决(直接引用 StackOverFlow 的一段 了): UIViewAnimationOpti***** opti***** = UIViewAnimationCurveLinear | UIViewAnimationOptionAllowUserInteraction; [UIView animateWithDuration:0.2 delay:0.0 opti*****:opti***** animati*****:^ { highlightView.alpha = 1.0; } completion:nil]; [UIView animateWithDuration:duration delay:0.0 opti*****:UIViewAnimationCurveEaseInOut //设置动画类型 animati*****:^{ //开始动画 [self updateArrowBtnTitle:YES]; 170 rotateView.transform = CGAffineTransformMakeRotation((stickToDegrees/180)*M_PI); } completion:^(BOOL finished){ // 动画结束时的处理 }]; [UIView animateWithDuration:] 方法仅支持 ios4.0 及以上版本。如 果要兼容以前的版本的话,还是需要使用 [UIView beginAnimation:] 方法 [UIView beginAnimati*****:nil context:nil]; // fade out helpImageBtn.alpha = 0.0f; // set animation did stop selector [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animationDidStop:finish ed:context:)]; [UIView commitAnimati*****]; -(void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context { if (self.retainedHelpImageBtn.superview) //先判断父视图再 执行视图移除 [self.retainedHelpImageBtn removeFromSuperview]; } 判断 textField 为空时让按钮不可用的代码 textField 为空时让按钮不可用,既防止误操作又显得应用很注重细节。 -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range 171 replacementString:(NSString *)string { NSMutableString *newValue = [[self.TextField.text mutableCopy] autorelease]; [newValue replaceCharactersInRange:range withString:string]; if ([newValue length]== 0) { self.navigationItem.rightBarButtonItem.enabled = NO; } else { self.navigationItem.rightBarButtonItem.enabled = YES; } return YES; } -(BOOL)textFieldShouldClear:(UITextField *)textField{ self.navigationItem.rightBarButtonItem.enabled = NO; return YES; } 获取手机号码,和 IMEI 获取本地 iphone 手机号码 [[NSUserDefaults standardUserDefaults] valueForKey:@"SBFormattedPhoneNumber"]; 获取手机的 imei #import "Message/NetworkController.h" NetworkController *ntc=[[NetworkController sharedInstance] 172 autorelease]; NSString *imeistring = [ntc IMEI]; imeistring 就是获取的 imei。IMEI(International Mobile Equipment Identity)是国际移动设备身份码的缩写, 国际移动装备辨识码,是由 15 位数字组成的"电子串号",它与每台手 机一一对应,而且该码是全世界唯一的。 控制 Default.png 图片的显示时间 -(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions //等待 1 秒进入首页 self.timer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerFired:) userInfo:nil repeats:NO]; [[NSRunLoop currentRunLoop] addTimer:self.connectionTimer forMode:NSDefaultRunLoopMode]; do{ [[NSRunLoop currentRunLoop]runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; //控制 default 图片显示的时间 }while (!done); -(void)timerFired:(NSTimer *)timer{ done=YES; } http://www.cocoachina.com/bbs/read.php?tid=73570&uid=39045&page=20 iOS5 的新功能之解析 JSON 173 iOS5 新加了很多新功能,解析 JSON 也是其中的一个。 下面是我最近写的一个小 DMEO。关于 JSON 的,现放出与大家共享。 以下代码参考 Vandad Nahavandipoor 的 《iOS 5 Programming Cookbook》。 这个是保存的方法。 -(IBAction)touchWriteButton:(id)sender { NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; [dictionary setValue:@"Anthony" forKey:@"First Name"]; [dictionary setValue:@"Robbins" forKey:@"Last Name"]; [dictionary setValue:[NSNumber numberWithUnsignedInteger:51] forKey:@"Age"]; NSArray *arrayOfAnthonysChildren = [[NSArray alloc] initWithObjects: @"Anthony's Son 1", @"Anthony's Daughter 1", @"Anthony's Son 2", @"Anthony's Son 3", @"Anthony's Daughter 2", nil]; [dictionary setValue:arrayOfAnthonysChildren forKey:@"children"]; NSError *error = nil; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error]; if (error) { 174 NSLog(@"dic->%@",error); } [dictionary release]; BOOL succeed = [jsonData writeToFile:JSON_PATH atomically:YES]; if (succeed) { NSLog(@"Save succeed"); }else { NSLog(@"Save fail"); } } 这个是读取的方法。 -(IBAction)touchReadButton:(id)sender { NSData *jsonData = [[NSData alloc] initWithContentsOfFile:JSON_PATH]; /* Now try to deserialize the JSON object into a dictionary */ NSError *error = nil; id jsonObject = [NSJSONSerialization 175 JSONObjectWithData:jsonData options:NSJSONReadingAllowFragments error:&error]; if (jsonObject != nil && error == nil){ NSLog(@"Successfully deserialized..."); if ([jsonObject isKindOfClass:[NSDictionary class]]){ NSDictionary *deserializedDictionary = (NSDictionary *)jsonObject; NSLog(@"Dersialized JSON Dictionary = %@", deserializedDictionary); } else if ([jsonObject isKindOfClass:[NSArray class]]){ NSArray *deserializedArray = (NSArray *)jsonObject; NSLog(@"Dersialized JSON Array = %@", deserializedArray); } else { NSLog(@"An error happened while deserializing the JSON data."); } } [jsonData release]; } 此功能仅限于 IOS5 才能使用。他的解析效率是目前市面上最高的 实现弹出软键盘后不遮挡文本框,自动调整屏幕高度方法 176 第一步:在头文件加入协议,并定义成员变量 int keyBoardMargin_; //记录上一次移动的间距,用户离开文本时恢复视图高度 第二步:在 xib 文件设置文本框的 delegate 与 file'owner 连接,或者在 m 文件用代码实现代理的 连接(文本控件.delegate=self) int keyBoardMargin_; //记录上一次移动的间距,用户离开文本时恢复视图高度 第三步:m 文件中加入以下方法 #pragma mark - 处理文本位置方法 -(void)moveView:(UITextField *)textField leaveView:(BOOL)leave { float screenHeight = 480; //屏幕尺寸,如果屏幕允许旋转,可根据旋转动态调整 float keyboardHeight = 216; //键盘尺寸,如果屏幕允许旋转,可根据旋转动态调整 float statusBarHeight,NavBarHeight,tableCellHeight,textFieldOriginY,textFieldFromButtomHeigt h; int margin; statusBarHeight = [[UIApplication sharedApplication] statusBarFrame].size.height; //屏 幕状态栏高度 NavBarHeight = self.navigationController.navigationBar.frame.size.height; //获取导航栏 高度 UITableViewCell *tableViewCell=(UITableViewCell *)textField.superview; tableCellHeight = tableViewCell.frame.size.height; //获取单元格高度 CGRect fieldFrame=[self.view convertRect:textField.frame fromView:tableViewCell]; textFieldOriginY = fieldFrame.origin.y; //获取文本框相对本视图的 y 轴位置。 NSLog(@"textFieldOriginY=%f",textFieldOriginY); NSLog(@"tableCellHeight=%f",tableCellHeight); NSLog(@"NavBarHeight=%f",NavBarHeight); NSLog(@"statusBarHeight=%f",statusBarHeight); //计算文本框到屏幕底部的高度(屏幕高度-顶部状态栏高度-导航栏高度-文本框的的相对 y 轴 位置-单元格高度) 177 textFieldFromButtomHeigth = screenHeight - statusBarHeight - NavBarHeight - textFieldOriginY - tableCellHeight; if(!leave) { if(textFieldFromButtomHeigth < keyboardHeight) {//如果文本框到屏幕底部的高度 < 键盘高度 margin = keyboardHeight - textFieldFromButtomHeigth; // 则计算差距 keyBoardMargin_ = margin; //keyBoardMargin_ 为成员变量,记录上一次移动的 间距,用户离开文本时恢复视图高度 } else { margin= 0; keyBoardMargin_ = 0; } } NSLog(@"keyBoardMargin_=%d",keyBoardMargin_); c*****t float movementDuration = 0.3f; // 动画时间 int movement = (leave ? keyBoardMargin_ :-margin); //进入时根据差距移动视图,离开时 恢复之前的高度 [UIView beginAnimati*****: @"textFieldAnim" context: nil]; //添加动画 [UIView setAnimationBeginsFromCurrentState: YES]; [UIView setAnimationDuration: movementDuration]; self.view.frame = CGRectOffset(self.view.frame, 0, movement); [UIView commitAnimati*****]; } 第四步:m 文件中加入以下协议方法 -(void)textFieldDidBeginEditing:(UITextField *)textField { [self moveView:textField leaveView:NO]; } -(void)textFieldDidEndEditing:(UITextField *)textField; { [self moveView:textField leaveView:YES]; 178 } 注:margin = keyboardHeight - textFieldFromButtomHeigth; // 则计算差距 这里应该写 margin = keyboardHeigh; //也就是 view 向上推一个键盘的高度 如果按照你写的计算差距,如果文本框刚好在键盘的高度内,会导致页面推到上面。 我的*****:213681048 附件: UITextView.zip (99 K) 下载次数:6 百度地图自定义弹出气泡的实现代码 最近项目中要加入地图搜索功能,目前选择的是百度地图。 官方指南:http://dev.baidu.com/wiki/imap/index.php?title=iOS 平 台/开发指南 但是百度地图默认的弹出气泡只能显示两行文字,所以需要自定义实 现。 网上搜索没找到现成代码,只好自己动手实现,现将代码分享,希望帮 到需要的朋友。 其间参考了论坛中几个很有用的帖子,在此一并感谢。 注:必须在 Xcode4 下编译项目,项目中用的是真机的 sdk,只能在设 备上运行。如果想在模拟器中运行,请自行去官网下载对应库文件。 需要申请百度地图 API Key,填在 AppDelegate.m 中相应位 置,例如 [_mapManager start:@"此处填写自己的 API Key" generalDelegate:nil]; BMKBubbleDemo.zip
还剩177页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享pdf获得金币 ] 0 人已下载

下载pdf

pdf贡献者

xin417

贡献于2012-12-06

下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf