IOS开发 经常使用知识点

1 获取系统语言设置
 
      NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
 
      NSArray *languages = [userDefault objectForKey:@ "AppleLanguages" ];
 
      NSString *preferredLang = [languages objectAtIndex: 0 ];
 
2
 
缓存路径下文件大小
 
 
- (unsigned  long  long  int ) cacheFolderSize
 
{
 
     NSFileManager  *_manager = [NSFileManager defaultManager];
 
     NSArray *_cachePaths =  NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
                                                 NSUserDomainMask, YES);
 
     NSString  *_cacheDirectory = [_cachePaths objectAtIndex:];
 
     NSArray  *_cacheFileList;
 
     NSEnumerator *_cacheEnumerator;
 
     NSString *_cacheFilePath;
 
     unsigned  long  long  int  _cacheFolderSize = ;
 
     _cacheFileList = [ _manager subpathsAtPath:_cacheDirectory];
 
    _cacheEnumerator = [_cacheFileList objectEnumerator];
 
     while  (_cacheFilePath = [_cacheEnumerator nextObject])
 
    {
 
          NSDictionary *_cacheFileAttributes = [_managerfileAttributesAtPath: 
 
          [_cacheDirectory   stringByAppendingPathComponent:_cacheFilePath]
 
          traverseLink:YES];
 
       _cacheFolderSize += [_cacheFileAttributes fileSize];
 
     }
 
// 单位是字节
 
     return  _cacheFolderSize;
 
}
 
3Popover push 时 Frame没法改变解决办法
 
在popover中的ViewController中实现:
 
- ( void )viewWillAppear:(BOOL)animated
{
 
    CGSize size = CGSizeMake( 320 480 );  // size of view in popover 
 
    self.contentSizeForViewInPopover = size;
 
    [ super  viewWillAppear:animated];
 
}
 
4tableview滑动致使NSTimer和委托回调中止解决办法
 
/ /请求回调
 
NSURLRequest  * 请求  =  ...
 
scheduleInRunLoop :[ NSRunLoop  currentRunLoop ]
                                             forMode :NSRunLoopCommonModes ]
[ 链接开始] / /定时器回调
 
NSTimer * updateTimer = [NSTimer scheduledTimerWithTimeInterval: 0 .01f目标:自我选择:选择(updatePencent)的UserInfo:无重复:是];
 
* NSRunLoop主要= [NSRunLoop currentRunLoop]
[主要addTimer:updateTimer forMode:NSRunLoopCommonModes];
 
5 手势识别类
 
UIGestureRecognizer
 
 
6SFHFKeychainUtils 存储信息
 
苹果SDK自带的就有密码保护,使用方法很简单,以下:
 
1 、引入Security.frameWork框架。
 
2 、引入头文件:SFHKeychainUtils.h.
 
3 、存密码:
 
[SFHFKeychainUtils storeUsername:@ "dd"  andPassword:@ "aa" forServiceName:SERVICE_NAMEupdateExisting: 1  error:nil];
 
[SFHFKeychainUtils deleteItemForUsername:@ "dd"  andServiceName:SERVICE_NAME error:nil];
 
4 、取密码:
 
NSString *passWord =  [SFHFKeychainUtils getPasswordForUsername:@ "dd" andServiceName:SERVICE_NAMEerror:nil];
 
7missing required architecture i386 in file 解决办法
 
在TargetInfo里面修改 Framework Search Pasths 删除里面内容就能够了。
 
 
8view 放大缩小动画效果
 
//建立缩小了的视图
myWeiBoImageVC = [[UIViewController alloc] init];
myWeiBoImageVC.view.clipsToBounds = YES;
myWeiBoImageVC.view.alpha =  0.0 ;
myWeiBoImageVC.view.frame = CGRectMake( 64 0 1024 - 64 768 - 20 );
[self.view addSubview:myWeiBoImageVC.view];
     
CGAffineTransform newTransform =
CGAffineTransformScale(myWeiBoImageVC.view.transform,  0.1 0.1 );
[myWeiBoImageVC.view setTransform:newTransform];
myWeiBoImageVC.view.center = CGPointMake( 670 100 );
  
[self performSelector: @selector (imageViewControllerBigAnimation)];
 
//放大刚刚建立缩小后的视图
- ( void )imageViewControllerBigAnimation{
    
     [UIView beginAnimations:@ "imageViewBig"  context:nil];
     [UIView setAnimationDuration: 0.5 ];  
     CGAffineTransform newTransform =            CGAffineTransformConcat(myWeiBoImageVC.view.transform,  CGAffineTransformInvert(myWeiBoImageVC.view.transform));
     [myWeiBoImageVC.view setTransform:newTransform];
     myWeiBoImageVC.view.alpha =  1.0 ;
     myWeiBoImageVC.view.center = CGPointMake( 416 510 );
     [UIView commitAnimations];
    
}
 
//缩小视图 隐藏
 
- ( void )imageViewControllerSmallAnimation{
 
     [UIView beginAnimations:@ "imageViewSmall"  context:nil];
     [UIView setAnimationDuration: 0.5 ];
     CGAffineTransform newTransform =  CGAffineTransformScale(myWeiBoImageVC.view.transform,  0.1 0.1 );
     [myWeiBoImageVC.view setTransform:newTransform];
     myWeiBoImageVC.view.center = CGPointMake( 670 100 );
     [UIView commitAnimations];
    
}
 
9UIScrollView 控制View缩放
 
allImageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake( 0 0 768 1024 )];
allImageScrollView.minimumZoomScale =  0.3 ;
allImageScrollView.maximumZoomScale =  1.0 ;
allImageScrollView.backgroundColor = [UIColor clearColor];
allImageScrollView.delegate = self;
[self.view addSubview:allImageScrollView];
 
mPicStatusesViewController = [[PicStatusesViewController alloc] init];
[allImageScrollView addSubview:mPicStatusesViewController.view];
 
//UIScrollView Delegete 实现
 
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
 
{
     return  mPicStatusesViewController.view;  //返回ScrollView上添加的须要缩放的视图
}
 
- ( void )scrollViewDidZoom:(UIScrollView *)scrollView
 
{
     //缩放操做中被调用
}
 
- ( void )scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:( float )scale
 
{
     //缩放结束后被调用
   }
 
10 、iOS3. 2  播放视频
 
NSString *urlString = [NSString stringWithString:@ "视频url" ];
 
NSURL *movieUrl = [[NSURL alloc] initWithString:urlString];
     
MPMoviePlayerController *myMoviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieUrl];
myMoviePlayer.view.frame = CGRectMake( 250 250 350 350 );
[self.view addSubview:myMoviePlayer.view];   
myMoviePlayer.shouldAutoplay = YES;
myMoviePlayer.scalingMode= MPMovieScalingModeAspectFit; 
[myMoviePlayer play];
 
 
11 、谷歌地图翻起动画效果
 
     CATransition *animation = [CATransition animation];
     [animation setDelegate:self];
     [animation setDuration: 0.35 ];
     [animation setTimingFunction:UIViewAnimationCurveEaseInOut];
     if  (!curled){
 
         animation.type = @ "pageCurl" ;
         animation.fillMode = kCAFillModeForwards;
         animation.endProgress =  0.40 ;
     else  {
         animation.type = @ "pageUnCurl" ;
         animation.fillMode = kCAFillModeBackwards;
         animation.startProgress =  0.30 ;
     }
     [animation setRemovedOnCompletion:NO];
     [self.view exchangeSubviewAtIndex: 0  withSubviewAtIndex: 1 ];
     
     [self.view.layer addAnimation:animation forKey:@ "pageCurlAnimation" ];
 
12 、给View添加阴影 和边框
 
UIImageView *imgvPhoto  = [UIImageView alloc] init];
 
//添加边框
    CALayer *layer = [_imgvPhoto layer];
     layer.borderColor = [[UIColor whiteColor] CGColor];
     layer.borderWidth =  5 .0f;
//添加四个边阴影
     _imgvPhoto.layer.shadowColor = [UIColor blackColor].CGColor;
     _imgvPhoto.layer.shadowOffset = CGSizeMake( 0 0 );
     _imgvPhoto.layer.shadowOpacity =  0.5 ;
     _imgvPhoto.layer.shadowRadius =  10.0 ;
//添加两个边阴影
     _imgvPhoto.layer.shadowColor = [UIColor blackColor].CGColor;
     _imgvPhoto.layer.shadowOffset = CGSizeMake( 4 4 );
     _imgvPhoto.layer.shadowOpacity =  0.5 ;
     _imgvPhoto.layer.shadowRadius =  2.0 ;
 
13 、使用NSTimer与UIView动画实现飘雪效果
 
viewDidLoad事件中,增长一个图片及定时器并启动,这里的pic请在头文件中定义。
 
-( void )viewDidLoad{
  [ super  viewDidLoad];
  self.pic = [UIImage imageNamed:@ "snow.png" ]; //初始化图片
  //启动定时器,实现飘雪效果
  [NSTimer scheduledTimerWithTimeInterval:( 0.2 ) target:self 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() 20 ); //随机获得该图片的x坐标
  int  y = round(random() 20 ); //这个是该图片移动的最后坐标x轴的
  int  s = round(random())+ 10 ; //这个是定义雪花图片的大小
  int  sp =  1 /round(random() 0 )+ 1 ; //这个是速度
  view.frame = CGRectMake(x, - 50 , s, s); //雪花开始的大小和位置
  [self.view addSubview:view]; //添加该view
  [UIView beginAnimations:nil context:view]; //开始动画
  [UIView setAnimationDuration: 10 *sp]; //设定速度
  view.frame = CGRectMake(y,  500 , s, s); //设定该雪花最后的消失坐标
  [UIView setAnimationDelegate:self];
  [UIView commitAnimations];
}
 
14 、配置Xcode 看程序崩溃信息
 
1 、在xcode中的左侧目录中找到Executables 打开
 
2 、双击和工程名同样的文件。
 
3 、在打开的文件中的Arguments选项,在下面的框中加入Name: NSZombieEnabled 设置value为YES。
 
15 、程序中发送邮件和检测设备邮箱是否被配置
 
-( void )addEmail{
 
Class mailClass = (NSClassFromString(@ "MFMailComposeViewController" ));
 
if  (mailClass != nil){
 
     if  ([mailClass canSendMail]){
 
         [self displayComposerSheet];
 
     } else {
 
         [self launchMailAppOnDevice];
 
     }
 
} else {
 
     [self launchMailAppOnDevice];
 
     }
 
}
 
-( void )displayComposerSheet
 
{
 
MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
 
controller.navigationBar.tag =  1002 ;
 
[self.navigationController.navigationBar setNeedsDisplay];
 
controller.mailComposeDelegate = self;
 
[controller setSubject:@ "意见反馈" ];
 
[controller setToRecipients:[[NSArray alloc] initWithObjects:@ "555@cifco.net.cn" ,nil]];
 
NSString *emailBody = nil;
 
[controller setMessageBody:emailBody isHTML:YES];
 
[self presentModalViewController:controller animated:YES];
 
[controller release];
 
}
 
#pragma mark mailComposeDelegate ----
 
- ( void )mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error
 
{
 
if  (result == MFMailComposeResultSent)
 
{
 
[self dismissModalViewControllerAnimated:YES];
 
}
 
if  (result == MFMailComposeResultSaved)
 
{
 
[self dismissModalViewControllerAnimated:YES];
 
}
 
if  (result == MFMailComposeResultFailed)
 
{
 
Emailalert = [[UIAlertView alloc] initWithTitle:@ ""  message:@ "发送失败"  delegate:selfcancelButtonTitle:@ "知道了"  otherButtonTitles:nil];
 
[Emailalert show];
 
}
 
if  (result == MFMailComposeResultCancelled)
 
{
 
[self dismissModalViewControllerAnimated:YES];
 
}
 
}
 
- ( void )alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
 
{
 
if (alertView == Emailalert)
 
{
 
if  (buttonIndex == )
 
{
 
[self dismissModalViewControllerAnimated:YES];
 
}
 
} else
 
{
 
if  (buttonIndex == )
 
{
 
//[self dismissModalViewControllerAnimated:YES];
 
} else
 
{
 
NSString *recipients = @ "mailto:theonelgq@gmail.com?cc=theone_liuguoqing@163.com&subject=text" ;
 
NSString *body = @ "&body=text!" ;
 
NSString *email = [NSString stringWithFormat:@ "%@%@" , recipients, body];
 
email = [email stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:email]];
 
}
 
}
 
}
 
#pragma mark -
 
#pragma mark Workaround
 
-( void )launchMailAppOnDevice
 
{
 
isEmailalert = [[UIAlertView alloc] initWithTitle:@ "警告"  message:@ "请配置您的邮箱"  delegate:selfcancelButtonTitle:@ "取消"  otherButtonTitles:@ "好的" ,nil];
 
[isEmailalert show];
 
}
 
16 、程序启动画面大小
 
  iOS设备如今有三种不一样的分辨率:iPhone 320x480、iPhone  4  640x960、iPad 768x1024。之前程序的启动画面(图片)只要准备一个 Default.png 就能够了,可是如今变得复杂多了。下面就是 CocoaChina 会员作得总结
 
   若是一个程序,既支持iPhone又支持iPad,那么它须要包含下面几个图片:
 
Default-Portrait.png iPad专用竖向启动画面 768x1024或者768x1004
 
Default-Landscape.png iPad专用横向启动画面 1024x768或者1024x748
 
Default-PortraitUpsideDown.png iPad专用竖向启动画面(Home按钮在屏幕上面),可省略 768x1024或者768x1004
 
Default-LandscapeLeft.png iPad专用横向启动画面,可省略 1024x768或者1024x748
 
Default-LandscapeRight.png iPad专用横向启动画面,可省略 1024x768或者1024x748
 
Default.png iPhone默认启动图片,若是没有提供上面几个iPad专用启动图片,则在iPad上运行时也使用Default.png(不推荐) 320x480或者320x460
 
Default @2x .png iPhone4启动图片640x960或者640x920
 
   为了在iPad上使用上述的启动画面,你还须要在info.plist中加入key: UISupportedInterfaceOrientations。同时,加入值UIInterfaceOrientationPortrait, UIInterfacOrientationPortraitUpsideDown, UIInterfaceOrientationLandscapeLeft, UIInterfaceOrientationLandscapeRight
 
17 、ASIHTTPRequest实现断点下载
 
- (IBAction)URLFetchWithProgress:(id)sender
 
{
 
[startButton setTitle:@ "Stop"  forState:UIControlStateNormal];
 
[startButton addTarget:self action: @selector (stopURLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
 
NSString*tempFile = [[[[NSBundle mainBundle] bundlePath]stringByDeletingLastPathComponent]stringByAppendingPathComponent:@ "MemexTrails_1.0b1.zip.download" ];
 
if  ([[NSFileManager defaultManager] fileExistsAtPath:tempFile]) {
 
[[NSFileManager defaultManager] removeItemAtPath:tempFile error:nil];
 
}
 
[self resumeURLFetchWithProgress:self];
 
}
 
- (IBAction)stopURLFetchWithProgress:(id)sender
 
{
 
networkQueue = [[ASINetworkQueue alloc] init];
 
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0  target:selfselector: @selector (updateBandwidthUsageIndicator) userInfo:nil repeats:YES];
 
timer = nil;
 
[startButton setTitle:@ "Stop"  forState:UIControlStateNormal];
 
[startButton addTarget:self action: @selector (URLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
 
[networkQueue cancelAllOperations];
 
[resumeButton setEnabled:YES];
 
}
 
- (IBAction)resumeURLFetchWithProgress:(id)sender
 
{
 
[resumeButton setEnabled:NO];
 
[startButton setTitle:@ "Start"  forState:UIControlStateNormal];
 
  [startButton addTarget:self action: @selector (stopURLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
 
[networkQueue cancelAllOperations];
 
[networkQueue setShowAccurateProgress:YES];
 
[networkQueue setDownloadProgressDelegate:progressIndicator];
 
[networkQueue setDelegate:self];
 
[networkQueue setRequestDidFinishSelector: @selector (URLFetchWithProgressComplete:)];
 
ASIHTTPRequest*request=[[[ASIHTTPRequest alloc] initWithURL:[NSURLURLWithString:@ "http://9991.net/blog/mp3/2.mp3" ]] autorelease];
 
[request setDownloadDestinationPath:[[[[NSBundle mainBundle] bundlePath]
 
stringByDeletingLastPathComponent] stringByAppendingPathComponent:@ "MemexTrails_1.0b1.mp3" ]];
 
[request setTemporaryFileDownloadPath:[[[[NSBundle mainBundle] bundlePath]stringByDeletingLastPathComponent]stringByAppendingPathComponent:@ "MemexTrails_1.0b1.zip.down" ]];
 
[request setAllowResumeForFileDownloads:YES];
 
[networkQueue addOperation:request];
 
[networkQueue go];
 
}
 
- ( void )URLFetchWithProgressComplete:(ASIHTTPRequest *)request
 
{
 
if  ([request error]) {
 
fileLocation.text=[NSString stringWithFormat:@ "An error occurred:%@" ,[[[requesterror] userInfo] objectForKey:@ "Title" ]];
 
else  {
 
fileLocation.text=[NSString stringWithFormat:@ "File downloaded to %@" ,[requestdownloadDestinationPath]];
 
}
 
[startButton setTitle:@ "Start"  forState:UIControlStateNormal];
 
[startButton addTarget:self action: @selector (URLFetchWithProgress:)forControlEvents:UIControlEventTouchUpInside];
 
}
 
- (IBAction)throttleBandwidth:(id)sender
 
{
 
if  ([(UIButton *)sender state] ==YES) {
 
[ASIHTTPRequest setMaxBandwidthPerSecond:ASIWWANBandwidthThrottleAmount];
 
else  {
 
[ASIHTTPRequest setMaxBandwidthPerSecond:];
 
}
 
}
 
18 、Safari 启动本地app
 
在plist文件中加入URL types 结构以下图,在Safari中地址栏输入 设置的字符串,好比设置的是
 
QQ,地址栏输入 QQ: // 就能够起点本地应用。
 
  
 
 
19 、拖到视频进度与滑动手势冲突解决办法
 
#pragma mark -
#pragma mark UIGestureRecognizerDelegate
 
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
     UIView *touchView = touch.view;
     
     if  ([touchView isKindOfClass:[UISlider  class ]])
     {
         return  NO;
     }
     else
     {
         return  YES;
     }
}
 
20 、建立并保存Cookie的方法
 
 
         NSString *cookieString = [NSString stringWithString:[headers objectForKey:@ "Cookie" ]];
         
         NSMutableDictionary *cookieProperties = [[NSMutableDictionary alloc] init];
         [cookieProperties setValue:cookieString forKey:NSHTTPCookieValue];
         [cookieProperties setValue:@ "QQCookie"  forKey:NSHTTPCookieName];
         [cookieProperties setValue:@ ".QQ.com"  forKey:NSHTTPCookieDomain];
         [cookieProperties setValue:[NSDate dateWithTimeIntervalSinceNow: 60 * 60 ] forKey:NSHTTPCookieExpires];
         [cookieProperties setValue:@ "/"  forKey:NSHTTPCookiePath];
         NSHTTPCookie *newcookie = [[NSHTTPCookie alloc] initWithProperties:cookieProperties];
         
         [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:newcookie];
 
 
21 、popover横竖屏位置改变解决办法
 
1 、 delegate中 处理
 
- ( void )popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
     userImageShow = NO;
     
     if  ([popoverController isEqual:myPopover])
     {
         [myPopover release];
         myPopover = nil;
     }
}
 
2 、屏幕旋转时从新弹出Popover
 
if  (myPopover) 
 
{
 
      if  ((self.interfaceOrientation ==
        UIInterfaceOrientationLandscapeLeft) || (self.interfaceOrientation ==
        UIInterfaceOrientationLandscapeRight))
      {
             [myPopover presentPopoverFromRect:CGRectMake( 10 , 180 1 1 )
                                                 inView:self.view
                               permittedArrowDirections:UIPopoverArrowDirectionRight
                                               animated:YES];
      }
      else
      {
            [myPopover presentPopoverFromRect:CGRectMake( 20 , 180 1 1 )
                                                 inView:self.view
                               permittedArrowDirections:UIPopoverArrowDirectionRight
                                               animated:YES];
       }
 
}
 
22 、plist各类key值含义
 
原文:http: //www.minroad.com/?p=434
 
 
 
UIRequiresPersistentWiFi 在程序中弹出wifi选择的key(系统设置中须要将wifi提示打开)
UIAppFonts 内嵌字体(http: //www.minroad.com/?p=412 有详细介绍)
UIApplicationExitsOnSuspend 程序是否在后台运行,本身在进入后台的时候exit( 0 )是很傻的办法
UIBackgroundModes 后台运行时的服务,具体看iOS4的后台介绍
UIDeviceFamily array类型( 1 为iPhone和iPod touch设备, 2 为iPad)
UIFileSharingEnabled 开启itunes共享document文件夹
UILaunchImageFile 至关于Default.png(改名而已)
UIPrerenderedIcon icon上是否有高光
UIRequiredDeviceCapabilities 设备须要的功能(具体点击这里查看)
UIStatusBarHidden 状态栏隐藏(和程序内的区别是在于显示Default.png已经生效)
UIStatusBarStyle 状态栏类型
UIViewEdgeAntialiasing 是否开启抗锯齿
CFBundleDisplayName app显示名
CFBundleIconFile、CFBundleIconFiles 图标
CFBundleName 与CFBundleDisplayName的区别在于这个是短名, 16 字符以内
CFBundleVersion 版本
CFBundleURLTypes 自定义url,用于利用url弹回程序
CFBundleLocalizations 本地资源的本地化语言,用于itunes页面左下角显示本地话语种
CFBundleDevelopmentRegion 也是本地化相关,若是用户所在地没有相应的语言资源,则用这个key的value来做为默认
最后附上官方文档,全部的key都有,看英文原版才是正路:)点我进入
 
24 、xcode工程内添加多个Target
 
转自:http: //blog.sina.com.cn/s/blog_682dc7810100pv8t.html
 
  
 
啥叫多Targets, 有啥用!
 
  
 
    相信不少人都注意到XCode中,
有个Target的概念.
     这在不少地方都有所体现,
好比打开一个工程后, 左侧的列表中有Targets一项, 而在工程界面的顶部菜单中,
project里面也有多个涉及到Target的项目,
那么这个Target究竟是什么呢? 
     Apple的人是这样说的:
     
 
引用
 
Targets that define the products to build. A
target organizes the files and instructions needed to build a
product into a sequence of build actions that can be taken.
 
 
 
     简单的理解的话,
 
能够认为一个target对应一个新的product(基于同一份代码的状况下). 但都一份代码了, 弄个新product作啥呢?
 
折腾这个有意思么?
 
     其实这不是单纯的瞎折腾,
 
虽然代码是同一份, 但编译设置(好比编译条件), 以及包含的资源文件却能够有很大的差异. 因而即便同一份代码,
 
产出的product也可能大不相同.
 
     咱们来举几个典型的应用多Targets的状况吧,
 
好比完整版和lite版; 好比同一个游戏的 20 关,  30 关,  50 关版; 再或者好比同一个游戏换些资源和名字就当新游戏卖的(喂喂,
 
你在教些什么...)
 
 
Targets之间, 什么相同, 什么不一样!
 
 
     既然是利用同一份代码产出不一样的product,
 
那么到底不一样Target之间存在着什么样的差别呢?
 
     要解释这个问题,
 
咱们就要来看看一个Target指定了哪些内容.
 
 
     从XCode左侧的列表中,
 
咱们能够看到一个Target包含了Copy Bundle Resources, Compile Sources, Link
 
Binary With Libraries. 其中
 
         Copy
 
Bundle Resources 是指生成的product的.app内将包含哪些资源文件
 
         Compile
 
Sources 是指将有哪些源代码被编译
 
         Link
 
Binary With Libraries 是指编译过程当中会引用哪些库文件
 
 
     经过Copy
 
Bundle Resources中内容的不一样设置, 咱们可让不一样的product包含不一样的资源, 包括程序的主图标等,
 
而不是把XCode的工程中列出的资源一股脑的包含进去.
 
     而这还不是一个target所指定的所有内容.
 
每一个target可使用一个独立,
 
不一样的Info.plist文件.  
 
     咱们都知道,
 
这个Info.plist文件内定义了一个iPhone项目的不少关键性内容, 好比程序名称,
 
最终生成product的全局惟一id等等.
 
      
 
     并且不一样的target还能够定义完整的差别化的编译设置,
 
从简单的调整优化选项, 到增长条件编译所使用的编译条件, 以致于所使用的base SDK均可以差别化指定.
 
 
建立第二个Target!
 
     为何是第二个?
 
由于第一个就是建立好工程后的默认Target呀! (废话这么多, 拖走...)
 
 
     建立target有多种方法,
 
咱们能够从现有的target上复制出一份, 而后略加改动, 也能够彻底新建一个target出来. 但其实说穿了,
 
两个方法大同小异
 
     首先咱们来看看利用复制的方法建立target
 
 
      利用复制建立target
 
     咱们在XCode左侧的列表中,
 
展开 Targets 项, 在现有的target上, 右键选择  "Duplicate" , 或者选中现有target后,
 
在顶部菜单的Edit内选择 "Duplicate" 也能够.
 
     此时咱们就获得了一个新的target,
 
而在Resource里面也会获得一个 xxxx copy.plist. 这个新的target与原有的target是彻底一致的,
 
余下的就是一些差别化的修改, 这个咱们后面再说
 
 
      建立全新的target
 
     相似复制的方法,
 
咱们能够在左侧的列表中不少地方按下右键菜单, 均可以看到Add中会有 "New Target..." 一项,
 
而在工程顶部菜单的Project内, 也能够看到这个 "New Target..." 的身影.
 
     点击后,
 
首先会让你选择target的类型, 既然我一直所指的都是程序自己, 那么天然选择Application了(至于其余的嘛,
 
有兴趣的本身研究吧, 好比咱们能够把程序中的部分提取成一个Static Library).
 
     Next后,
 
会让你输入一个新的Target的名字, 而不像复制的方法中, 默认生成 xxxxx copy这样的target名.
 
     可是这样生成出的Target几乎是空的.
 
Copy Bundle Resources, Compile Sources, Link Binary With
 
Libraries里面都没有任何内容. 编译设置也是彻底原始的状态.
 
     能够经过拖拽内容到这些target的设置中,
 
以及调整编译选项来完成Target的配置.
 
 
 
Target中部份内容的修改方法!
 
     其实这段的部份内容,
 
在非多Targets的工程中也可能会用获得.
 
     因为修改基本都是在工程/编译设置中完成,
 
所以没有特殊状况, 就再也不声明了, 打开target对应的工程/编译设置的方法能够采用在该target上右键, 选择get
 
info来作到.
 
 
     生成的product名称的修改:
 
Packing段内的Product Name一项
 
 
     Info.plist文件名:
 
Packing段内的Info.plist File一项, 好比复制出来的target以为那个xxxxx
 
copy.plist太傻就能够在这里改
 
 
    
 
件编译: 增长一个User-Defined Setting(Target  "xxxx"
 
Info的build页的左下角那个齿轮中能够看到这个内容), 在Other C Flag里面填入,
 
好比要定义一个叫作LITE_VERSION的define值, 咱们能够写上  "-DLITE_VERSION" 
 
"-DLITE_VERSION=1" . 那么在程序中就能够用
 
     # if
 
defined(LITE_VERSION)
 
     # else
 
     #endif
 
这样的条件编译来部分差别化代码了
 
 
     也许有些朋友记得我在代码区贴过的检测破解版的代码,
 
其中有一种检测方法就是看info.plist是文本仍是二进制的, 那么咱们可否建议一个模拟破解的target,
 
直接生成文本的info.plist以便测试呢?
 
     固然能够,
 
在packing段内, 有一项叫 "Info.plist Output Encoding" , 默认值是Binary,
 
咱们只要选成xml, 那么生成出的product.app内的info.plist就直接是文本样式的了.
 
 
 
    
 
外, 向Copy Bundle Resources, Compile Sources, Link Binary With
 
Libraries内添加/删除文件, 能够在要改动的文件上, 选择get info, 而且切换到Target页,
 
勾选要引用这个文件的target便可. 好比icon.png能够指定给默认target, 而icon_lite.png指定给lite
 
verion的target
 
 
 
大体就是如此吧, 懒得抓图了. 各位将就吧. 想到什么须要补充的, 我会加入
 
另外
 
一个英文教程:http: //www.codza.com/free-iphone-app-version-from-the-same-xcode-project
 
25 、详解IOS SDK兼容性引导
 
转自: http: //mobile.51cto.com/iphone-284052.htm
 
  
 
IOS SDK兼容性引导是本文要介绍的内容,主要是基于IOS SDK基础的开发介绍说明如何应用于XCode工程的基于IOS SDK开发的技术。来看详细内容讲解。
 
1 、用(weakly linked)弱链接类、方法和函数来支持在不一样版本之间的程序运行
 
2 、弱链接整个框架(framework)
 
3 、为不一样的IOS SDK选择不一样的编译条件
 
4 、在代码中找出过期API的使用
 
5 、肯定在运行时操做系统和框架(framework)的版本
 
一 、在IOS中使用弱链接类
 
在工程中使用类的弱链接的时候必须确保这些类在运行时的可用性,要不会引发动态链接的错误。
 
在IOS4. 2 之后的版本都是使用NSObject  class 的方法来检测弱链接在运行时态的可用性,这种简单高效的机制使用了NS_CLASS_AVAILABLE的可用性宏。
 
检测最近release的framework还不支持NS_CLASS_AVAILABLE的宏
 
在支持NS_CLASS_AVAILABLE的宏framework的条件编译中,能够以下的使用
 
if  ([UIPrintInteractionController  class ]) {  
     // Create an instance of the class and use it.  
else  {  
     // Alternate code path to follow when the  
     // class is not available.  
}
若是你在不确保是否已经可使用类方法的时候你可使用NSClassFromString 方法来判断,使用方法以下:
 
Class cls = NSClassFromString (@ "NSRegularExpression" );  
if  (cls) {  
     // Create an instance of the class and use it.  
else  {  
     // Alternate code path to follow when the  
     // class is not available.  
}
2、在方法,函数和符号中使用弱链接
 
和使用类的弱链接同样,在使用它以前要确保方法函数和符号在运行时的可用性,要不在编译的时候会报错动态链接错误,假设你想使用新版本IOS
SDK的特性可是又想可以运行在低版本的SDK中,那么就要对早期的版本设置相应的开发target,在Object-c中
instancesRespondToSelector:
方法告诉咱们所给的方法是否可用,例如:使用availableCaptureModesForCameraDevice:这个方法(在 4.0 之后才是可
用的),咱们能够这样使用它。
 
1 、检查一个Object-c方法的可用性
 
if  ([UIImagePickerController instancesRespondToSelector:  
               @selector  (availableCaptureModesForCameraDevice:)]) {  
     // Method is available for use.  
     // Your code can check if video capture is available and,  
     // if it is, offer that option.  
else  {  
     // Method is not available.  
     // Alternate code to use only still image capture.  
}
判断一个弱链接的C函数是否可用,只要判断函数的地址是否返回为NULL,以CGColorCreateGenericCMYK 函数为例,咱们能够像如下那样使用。
 
2 、检查C方法的可用性
 
if  (CGColorCreateGenericCMYK != NULL) {  
     CGColorCreateGenericCMYK ( 0.1 , 0.5 . 0.0 , 1.0 , 0.1 );  
else  {  
     // Function is not available.  
     // Alternate code to create a color object with earlier technology  
要检测一个C方法是否可用,比较明确的为地址是否为NULL或零。你不能使用反运算符(!)来否认一个函数的可用性
 
检测一个 external(extern)常量或一个通知的名字应当比较它的地址(address)--而不是符号的名称, 判断是否为NULL or nil
 
3、弱链接整个Framework
 
好比一个在高版本中才出现的Framework,想在低版本使用他的特性。那你就必须弱链接那个使用的Framework,详见官方的图解---(其实就是在添加进去的Framework的 required 改为 optional)
 
http: //developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/XcodeProjectManagement/
130 -Files_in_Projects/project_files.html# //apple_ref/doc/uid/TP40002666-SW4
4、条件编译 for 不一样的SDK
 
若是你不止基于一个IOS SDK编译,你就可能须要为base
sdk使用条件化,可使用在Availability.h中的定义。这个.h文件存在于系统的文件夹/usr/include的文件夹下,例如想在
Mac OS X v10. 5 (而不是IOS)中使用函数 CGColorCreateGenericCMYK
 
使用预处理指令 for 条件编译
 
#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED  
     // code only compiled when targeting Mac OS X and not iOS  
     // note use of 1050 instead of __MAC_10_5  
# if  __MAC_OS_X_VERSION_MAX_ALLOWED >=  1050  
     if  (CGColorCreateGenericCMYK != NULL) {  
         CGColorCreateGenericCMYK( 0.1 , 0.5 . 0.0 , 1.0 , 0.1 );  
     else  {  
#endif  
     // code to create a color object with earlier technology  
# if  __MAC_OS_X_VERSION_MAX_ALLOWED >=  1050  
     }  
#endif  
#endif  
}
5、寻找出在程序中使用的以过期的实例
 
在IOS或Mac
OS中有时候API会过期,可是过期不表明着那些就从Library或framework中删除,可是在使用的过程当中会报出warning,而且在不远的
未来可能会被Apple从中移除。例如咱们在code中使用了过期的函数 HPurge那么就会报出以下
 
'HPurge'  is deprecated (declared at /Users/steve/MyProject/main.c: 51 )
因此咱们应当在工程中查找出以下的警告而且修改。
 
6、肯定操做系统和Framework的版本
 
在运行时检查IOS的版本
 
NSString *osVersion = [[UIDevice currentDevice] systemVersion];
在运行时检查Mac OS X用Gestalt function 和 系统版本常量
 
另外,对于许多的Framework你能够在运行时检查指定Framework的版本。
 
例如:Application Kit(NSApplication.h)定义了NSAppKitVersionNumber常量---能够用来检查Application Kit Framework的版本
 
 
APPKIT_EXTERN  double  NSAppKitVersionNumber;  
#define NSAppKitVersionNumber10_0  577  
#define NSAppKitVersionNumber10_1  620  
#define NSAppKitVersionNumber10_2  663  
#define NSAppKitVersionNumber10_2_3  663.6  
#define NSAppKitVersionNumber10_3  743  
#define NSAppKitVersionNumber10_3_2  743.14  
#define NSAppKitVersionNumber10_3_3  743.2  
#define NSAppKitVersionNumber10_3_5  743.24  
#define NSAppKitVersionNumber10_3_7  743.33  
#define NSAppKitVersionNumber10_3_9  743.36  
#define NSAppKitVersionNumber10_4  824  
#define NSAppKitVersionNumber10_4_1  824.1  
#define NSAppKitVersionNumber10_4_3  824.23  
#define NSAppKitVersionNumber10_4_4  824.33  
#define NSAppKitVersionNumber10_4_7  824.41  
#define NSAppKitVersionNumber10_5  949  
#define NSAppKitVersionNumber10_5_2  949.27  
#define NSAppKitVersionNumber10_5_3  949.33
因此咱们能够像以下使用:
 
if  (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_0) {  
   /* On a 10.0.x or earlier system */  
else  if  (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) {  
   /* On a 10.1 - 10.1.x system */  
else  if  (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_2) {  
   /* On a 10.2 - 10.2.x system */  
else  if  (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_3) {  
   /* On 10.3 - 10.3.x system */  
else  if  (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4) {  
   /* On a 10.4 - 10.4.x system */  
else  if  (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5) {  
   /* On a 10.5 - 10.5.x system */  
else  {  
   /* 10.6 or later system */  
}
跟以上同样在 NSObjCRuntime.h中用定义了NSFoundationVersionNumber全局常量
 
小结:详解IOS SDK兼容性引导的内容介绍玩玩了,但愿经过本文的学习能对你有所帮助!
 
原文地址:http: //blog.csdn.net/diyagoanyhacker/article/details/6673344
 
26 、NSDate 与 NSString 转换
 
将字符串 “Fri Nov  11  09 : 06 : 27  + 0800  2011 ” 转换成Date:
 
     NSDateFormatter *format = [[NSDateFormatter alloc] init];
     NSLocale *enLocale = [[NSLocale alloc] initWithLocaleIdentifier:@ "en-US" ];
     [format setLocale:enLocale];
     [enLocale release];
     [format setDateFormat:@ "EEE MMM dd HH:mm:ss ZZZ yyyy" ];
     NSDate *dateTime = [format dateFromString:message];
 
  
 
将Date转换成字符串:
 
     NSDate *date = [NSDate date];
     NSString * dateString = [format stringFromDate:date];
 
//字符串转换成NSDate 须要设置NSLocale 不然真机上会失败。
 
27 、数组中存储数据查询
 
NSMutableDictionary *userDic1 = [NSMutableDictionary dictionaryWithCapacity: 10 ];
     NSMutableDictionary *userDic2 = [NSMutableDictionary dictionaryWithCapacity: 10 ];
     [userDic1 setValue:@ "Li"  forKey:@ "name" ];
     [userDic2 setValue:@ "Wang"  forKey:@ "name" ];
     
     NSArray *userArray = [NSArray arrayWithObjects:userDic1,userDic2,nil];
     NSPredicate *namePredicate = [NSPredicate predicateWithFormat:@ "SELF.name contains[cd] %@ " ,@ "L" ];
     
     NSMutableArray *searchArray = [NSMutableArray arrayWithArray:[userArray filteredArrayUsingPredicate:namePredicate]];
     
     NSLog(@ "searchArray  == %@" ,searchArray);
 
28 、CoreText 总结
 
1 ) NSAttributedString
 
       NSAttributedString 能够将一段文字中的部分文字设置单独的字体和颜色。
 
       与UITouch结合能够实现点击不一样文字触发不一样事件的交互功能。
 
        主要方法:
 
            - ( void )addAttribute:(NSString *)name value:(id)value range:(NSRange)range;
 
            能够设置某段文字的字体名称,颜色,下滑线等信息。
 
            - ( void )removeAttribute:(NSString *)name range:(NSRange)range;
 
            移除以前设置的字体属性值。
 
            - ( void )addAttributes:(NSDictionary *)attrs range:(NSRange)range;
 
            存储某段文字包含的信息(包括字体属性或其它,也能够存储一些自定义的信息)
 
            - (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range;
 
            经过location来获取某段文字中以前存储的信息NSDictionary
 
  
 
    //设置字体
    CTFontRef aFont = CTFontCreateWithName((CFStringRef)textFont.fontName, textFont.pointSize, NULL);
    if  (!aFont)  return ;
    CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(aFont,  0.0 , NULL, kCTFontItalicTrait, kCTFontBoldTrait);     //将默认黑体字设置为其它字体
    [self removeAttribute:(NSString*)kCTFontAttributeName range:textRange];
    [self addAttribute:(NSString*)kCTFontAttributeName value:(id)newFont range:textRange];
    CFRelease(aFont);
    CFRelease(newFont);
    
    //设置字体颜色
    [self removeAttribute:(NSString*)kCTForegroundColorAttributeName range:textRange];
    [self addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)textColor.CGColor range:textRange];
    
    //设置对齐 换行
    CTTextAlignment coreTextAlign = kCTLeftTextAlignment;
    CTLineBreakMode coreTextLBMode = kCTLineBreakByCharWrapping;
    CTParagraphStyleSetting paraStyles[ 2 ] =
    {
        {.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = ( const  void *)&coreTextAlign},
        {.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = ( const  void *)&coreTextLBMode},
    };
    CTParagraphStyleRef aStyle = CTParagraphStyleCreate(paraStyles,  2 );
    [self removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:textRange];
    [self addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)aStyle range:textRange];
    CFRelease(aStyle);
 
  
 
2 )Draw NSAttributedString
 
 
        
    CGContextRef cgc = UIGraphicsGetCurrentContext();
    CGContextSaveGState(cgc);
    
    //图像方向转换
    CGContextConcatCTM(cgc, CGAffineTransformScale(CGAffineTransformMakeTranslation( 0 , self.bounds.size.height),  1 .f, - 1 .f));
    
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)weiBoText);
    drawingRect = self.bounds;
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, drawingRect);
    textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake( 0 , 0 ), path, NULL);
    CGPathRelease(path);
    CFRelease(framesetter);
    
    CTFrameDraw(textFrame, cgc);
    CGContextRestoreGState(cgc);
 
3 )图文混排
 
      CTFrameRef  textFrame      // coreText 的 frame
 
      CTLineRef      line              //  coreText 的 line
 
      CTRunRef      run              //  line  中的部分文字
 
      相关方法:
 
    
    CFArrayRef CTFrameGetLines    (CTFrameRef frame )       //获取包含CTLineRef的数组
 
    void  CTFrameGetLineOrigins(
    CTFrameRef frame,
    CFRange range,
    CGPoint origins[] )   //获取全部CTLineRef的原点
 
  CFRange CTLineGetStringRange  (CTLineRef line )     //获取line中文字在整段文字中的Range
 
  CFArrayRef CTLineGetGlyphRuns  (CTLineRef line )     //获取line中包含全部run的数组
 
  CFRange CTRunGetStringRange  (CTRunRef run )      //获取run在整段文字中的Range
 
  CFIndex CTLineGetStringIndexForPosition(
    CTLineRef line,
    CGPoint position )    //获取点击处position文字在整段文字中的index
 
    CGFloat CTLineGetOffsetForStringIndex(
    CTLineRef line,
    CFIndex charIndex,
    CGFloat* secondaryOffset )  //获取整段文字中charIndex位置的字符相对line的原点的x值
 
   主要步骤:
 
        1 )计算并存储文字中保含的全部表情文字及其Range
 
        2 )替换表情文字为指定宽度的NSAttributedString
 
            CTRunDelegateCallbacks callbacks;
    callbacks.version = kCTRunDelegateVersion1;
    callbacks.getAscent = ascentCallback;
    callbacks.getDescent = descentCallback;
    callbacks.getWidth = widthCallback;
    callbacks.dealloc = deallocCallback;
    
    CTRunDelegateRef runDelegate = CTRunDelegateCreate(&callbacks, NULL);
    NSDictionary *attrDictionaryDelegate = [NSDictionary dictionaryWithObjectsAndKeys:
                                            (id)runDelegate, (NSString*)kCTRunDelegateAttributeName,
                                            [UIColor clearColor].CGColor,(NSString*)kCTForegroundColorAttributeName,
                                            nil];
    
    NSAttributedString *faceAttributedString = [[NSAttributedString alloc] initWithString:@ "*"  attributes:attrDictionaryDelegate];
    
    [weiBoText replaceCharactersInRange:faceRange withAttributedString:faceAttributedString];
    [faceAttributedString release];   
 
        3 )  根据保存的表情文字的Range计算表情图片的Frame
 
                 textFrame 经过CTFrameGetLines 获取全部line的数组 lineArray
 
                遍历lineArray中的line经过CTLineGetGlyphRuns获取line中包含run的数组 runArray
 
                遍历runArray中的run 经过CTRunGetStringRange获取run的Range
 
                判断表情文字的location是否在run的Range
 
                若是在 经过CTLineGetOffsetForStringIndex获取x的值 y的值为line原点的值
 
        4 )Draw表情图片到计算获取到的Frame
 
  
 
3 )点击文字触发事件
 
   
 
   主要步骤:
 
        1 ) 根据touch事件获取点point
 
        2 )   textFrame 经过CTFrameGetLineOrigins获取全部line的原点
 
        3 ) 比较point和line原点的y值获取点击处于哪一个line
 
        4 )  line、point 经过CTLineGetStringIndexForPosition获取到点击字符在整段文字中的    index  
 
        5 )  NSAttributedString 经过index 用方法-(NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range  能够获取到点击到的NSAttributedString中存储的NSDictionary
 
        6 ) 经过NSDictionary中存储的信息判断点击的哪一种文字类型分别处理
 
23 、视频播放、编辑
 
 
 
 
  
 
转载: http: //www1.huachu.com.cn/read/readbookinfo.asp?sectionid=1000006772
 
 
对于不一样的设备,视频功能是各不相同的。全部的设备都可以回放视频,可是仅有iPhone 3GS设备有记录视频的能力。对于每一个设备而言,都存在API可以让您检测哪些功能是可用的和哪些功能是不可用的,这样就可以针对使用视频功能的全部用户建立优秀的用户体验。这一节内容讨论如何才能将视频集成到应用程序中,以及如何才能使用特定的设备记录视频。
 
10.2 . 1   播放视频
 
iPhone SDK提供了一个简单的控制器来在应用程序中播放视频。MPMoviePlayerController类位于MonoTouch.MediaPlayer名称空间中,它提供了播放影片、准备播放影片和中止播放影片的功能。程序清单 10 - 9 说明了如何开始播放视频。第一行代码显示的是实例化一个新的影片播放器对象,并将视频内容文件路径传入其构造函数内。第二行代码简单地调用了Play方法,该方法显示影片播放器并开始播放视频。
 
程序清单 10 - 9   播放视频文件
 
var player =  new  MPMoviePlayerController(NSUrl.FromFilename( "video.mp4" ));
 
player.Play();
 
若是但愿使用外部视频,并以渐进方式下载视频,而不是直接播放设备上的视频,那么就要使用NSUrl的FromString方法,而不是使用FromFilename,并将视频的URL地址传入其中。固然,须要使用本身的外部视频替换这里的URL字符串。
 
var videoUrl = NSUrl.FromString( "http://example.com/video.mp4" )
 
var player =  new  MPMoviePlayerController(videoUrl);
 
player.Play();
 
您也许会注意到,在视频开始播放以前有一个短暂的缓冲周期。这就是所谓的预加载过程。能够设置视频播放器上的通知,在视频已经开始预加载时让其引起一条消息,这样就可以显示加载屏幕,而后在预加载完成后开始显示视频。当视频完成播放或者用户改变视频的缩放比例时,也可使用通知引起消息。
 
使用NSNotificationCenter类的DefaultCenter属性添加观察者,从而在通知产生时引起这些消息。能够将观察者看做将事件添加到特定动做上的一种方式,使用字符串做为建立这些事件的方式,而不是使用您也许已经熟悉的C#内的强类型事件。对于本示例而言,只须要使用通知MPMoviePlayerContentPreloadDidFinishNotification和MPMoviePlayerPlaybackDid- FinishNotification。另外一个通知名为MPMoviePlayerScalingModeDidChangeNotification。还要添加两个NSObject类型的类变量,它们能够做为预加载和回放完成的观察者。使用AddObserver方法,为每一个观察者传入一个动做方法,当通知被调用时这些动做方法就会运行。可使用Lambda表达式之内联方式放置这段代码。当预加载通知被激活之后,只须要开始播放视频,所以能够调用MPMoviePlayerController上的Play方法;当回放通知激活之后,须要移除观察者,并清除影片播放器实例。可使用活动指示器确保让用户知道当应用程序启动时正在预加载视频。程序清单 10 - 10 给出了完成这项工做的示例代码。一样,须要确保改变第 8 行代码中的URL,让其指向选择的外部视频。
 
程序清单 10 - 10   使用影片播放器观察者
 
MPMoviePlayerController moviePlayer;
 
NSObject didFinishPreload, didFinishPlayback;
 
 
public  override  void  ViewDidLoad()
 
{
 
   base.ViewDidLoad ();
 
  
 
   var videoUrl = NSUrl.FromString( "http://example.com/video.mp4" );
 
   moviePlayer =  new  MPMoviePlayerController(videoUrl);
 
  
 
   activityIndicator.StartAnimating();
 
 
   var centre = NSNotificationCenter.DefaultCenter;
 
   var preloadFinish =  "MPMoviePlayerContentPreloadDidFinishNotification" ;
 
   didFinishPreload = centre.AddObserver(preloadFinish,
 
      (notify) => {
 
         Console.WriteLine ( "Start playing movie" );
 
         activityIndicator.StopAnimating();
 
         moviePlayer.Play();
 
      });
 
 
   var playbackFinished =  "MPMoviePlayerPlaybackDidFinishNotification" ;
 
   didFinishPlayback = centre.AddObserver(playbackFinished,
 
      (notify) => {
 
         Console.WriteLine ( "Movie finished, Clean up" );
 
 
         centre.RemoveObserver(didFinishPreload);
 
         centre.RemoveObserver(didFinishPlayback);
 
 
         activityIndicator.Hidden =  true ;
 
 
         moviePlayer.Dispose();
 
         moviePlayer =  null ;
 
      }); }
 
}
 
10.2 . 2   定制视频播放器
 
影片播放器提供的功能是至关有限的,仅容许对两个属性根据须要进行调整,这两个属性是ScalingMode和MovieControlMode。
 
缩放模式对播放影片的长宽比进行设置。可用的长宽比选项为Fill、AspectFill、AspectFit和None。
 
Fill选项用于让视频填满整个屏幕,这样视频的边缘会与屏幕吻合,可是可能没法保持原有的长宽比。
 
AspectFill选项在视频填满整个屏幕时不会扭曲视频,可是确实会对视频进行裁剪,这样视频才可以无缝地填满这个屏幕。
 
AspectFit选项会保留视频原有的长宽比,并让视频的边缘尽量地与屏幕吻合,但若是视频不是彻底吻合,那么可能会露出背景视图。
 
None选项不会调整视频,而是按照视频自身的大小进行播放。
 
使用MPMovieScalingMode枚举,能够将ScalingMode设置为这个列表中的任何选项。参见图 10 - 10 ~图 10 - 13 ,其中给出了每一种缩放模式的示例。播放器的背景设置为蓝色(在这些图中,背景是以浅灰色打印版本进行显示的),所以能够看到视频大小和播放器大小之间的差别。注意,在这个示例中,Aspect Fit和Fill视频是同样的。这是由于视频的当前长宽比容许视频的边缘与屏幕吻合,而无须改变长宽比。
 
 
图   10 - 10                                       图   10 - 11 
 
 
图   10 - 12                                     图   10 - 13 
 
另一个能够针对视频播放器修改的属性是MovieControlMode。使用MPMovieControlMode枚举,能够将控件模式设置为Default、Hidden或VolumeOnly。图 10 - 14 和图 10 - 15 给出了Default和VolumeOnly控件模式。Hidden模式隐藏了屏幕上全部默认的动做;若是但愿让本身提供的用户界面位于视频的上方,那么该模式就颇有用。
 
 
图   10 - 14                                      图   10 - 15 
 
影片播放器自己是做为一个关键窗口出如今屏幕上的。为了将自定义界面添加到影片播放器关键窗口的上方,能够从应用程序中具备的窗口列表内获取该关键窗口的引用(关键窗口在本质上是窗口框架内能够得到的最顶层的可见视图)。而后能够简单地将子视图添加到影片播放器关键窗口中。由于影片播放器是以横屏模式出现的,因此必须对叠加视图进行变换,从而使其可以与横屏模式匹配。程序清单 10 - 11 说明了如何使用代码实现此处提到的全部内容。
 
程序清单 10 - 11   在视频播放器上叠加视图
 
public  MPMoviePlayerController mPlayer;
 
 
public  override  void  ViewDidLoad ()
 
{
 
   base.ViewDidLoad ();
 
 
   var button = UIButton.FromType(UIButtonType.RoundedRect);
 
   button.Frame =  new  RectangleF(0f, 20f, 320f, 40f);
 
   button.SetTitle( "Play Video" , UIControlState.Normal);
 
   button.TouchUpInside += delegate(object sender, EventArgs e)
 
   {
 
      PlayMovie ();
 
 
      var windows = UIApplication.SharedApplication.Windows;
 
      if (windows.Count() >  1 )
 
      {
 
         var moviePlayerWindow = UIApplication.SharedApplication.KeyWindow;
 
         var customView =  new  MyOverlayView( this );
 
         moviePlayerWindow.AddSubview(customView);
 
      }
 
   };
 
   this .View.AddSubview(button);
 
}
 
 
void  PlayMovie ()
 
{
 
   var url = NSUrl.FromFilename( "video.mp4" );
 
   mPlayer =  new  MPMoviePlayerController(url);
 
   mPlayer.Play();
 
}
 
 
...
 
 
public  class  MyOverlayView : UIView
 
{
 
   public  MyOverlayView (MainViewController mvc)
 
   {
 
      this .Frame =  new  RectangleF(0f, 0f, 320f, 480f);
 
      this .Transform = CGAffineTransform.MakeRotation(( float )(Math.PI /  2 ));
 
 
      UIButton button = UIButton.FromType(UIButtonType.RoundedRect);
 
      button.SetTitle( "Pause" , UIControlState.Normal);
 
      button.Frame =  new  RectangleF(65f, 360f, 190f, 32f);
 
      button.TouchUpInside += delegate(object sender, EventArgs e) {
 
         Console.WriteLine ( "Paused the video" );
 
         mvc.mPlayer.Pause();
 
      };
 
 
      this .AddSubview(button);
 
   }
 
}
 
10 - 16 显示的是在程序清单 10 - 11 中建立的叠加视图。
 
 
图   10 - 16 
 
10.2 . 3   选取视频
 
为了让用户能够从存储在设备上的视频列表中选取视频,可使用UIImagePickerController,在本章前面已经使用过该类。由于面向iPhone的视频功能很是相似于摄像头功能,因此看到视频功能属于UIImagePickerController类的组成部分并不使人感到惊奇。在程序清单 10 - 6 中,咱们使用IsSourceTypeAvailable方法来肯定设备是否具备摄像头。由于视频功能仅限于iPhone3GS模型,因此只是弄清楚是否存在摄像头并不足够。这时就须要使用UIImagePickerController类上的AvailableMediaTypes静态方法。
 
AvailableMediaTypes方法以源类型做为输入,返回设备上可用媒体类型的数组。图像的媒体类型为 public .image,而视频的媒体类型为 public .movie。若是该方法返回 public .movie类型,那么能够将UIImagePickerController实例的MediaTypes属性设置为仅有 public .movie媒体类型。程序清单 10 - 12 给出了以这种方式设置的选取器。
 
程序清单 10 - 12   使用图像选取器控制器选取视频
 
if  (HasVideoSupport())
 
{
 
   UIImagePickerController picker =  new  UIImagePickerController();
 
   picker.SourceType = UIImagePickerControllerSourceType.PhotoLibrary;
 
   picker.MediaTypes =  new  []{ "public.movie" };
 
   picker.Delegate =  new  MyImagePickerDelegate( this );
 
   this .PresentModalViewController(picker,  true );
 
}
 
else
 
{
 
   using (var alert =  new  UIAlertView( "Whoops" "No video support found" ,
 
                                       null "Ok!" null ))
 
   {
 
      alert.Show();
 
   }
 
}
 
 
...
 
 
bool HasVideoSupport()
 
{
 
   var cameraType = UIImagePickerControllerSourceType.Camera;
 
   var cameraSupport =
 
                  UIImagePickerController.IsSourceTypeAvailable(cameraType);
 
   return  (!cameraSupport) ?  false  :
 
          UIImagePickerController.AvailableMediaTypes(cameraType)
 
                                        .Contains( "public.movie" );
 
}
 
在显示该选取器时,注意到您只看到了视频,由于视频是能够选取的惟一的媒体类型。图 10 - 17 说明了如何显示只选取视频的选取器。
 
 
图   10 - 17 
 
在选取视频之后,该选取器使用与图像选取器相同的回调:FinishedPickingMedia。NSDictionary带有两个键:UIImagePickerControllerMediaURL和UIImagePickerControllerMediaType。媒体URL包含一个指向所选择视频的临时位置的NSUrl对象。这就是您能够处理视频的地方—— 要么将视频移动到Documents文件夹中,要么经过其余方式使用视频。临时视频存储在应用程序的tmp文件夹中,OS在认为合适的时候会将其清除。
 
10.2 . 4   记录视频
 
使用iPhone记录视频很是相似于使用iPhone进行拍照。在前一个示例中,能够仅将源类型设置为摄像头而不是图片库的默认源类型,全部这些设置都是为了记录视频而不是拍摄照片。固然,这就是假设您已经使用AvailableMediaTypes方法验证了该设备能够记录视频。注意,摄像头控件会发生变化,从而反映出是记录视频而不是拍摄照片。做为可选项,能够选择经过将ShowsCameraControls设置为 false 来隐藏摄像头控件;然而,在编写本书的时候,若是不使用默认的摄像头控件,那么尚未方式能够经过编程来记录视频。程序清单 10 - 13 是设置UIImagePickerController以记录视频的一个示例。图 10 - 18 显示的是视频记录屏幕。
 
程序清单 10 - 13   记录视频
 
public  override  void  ViewDidLoad ()
 
{
 
   base.ViewDidLoad ();
 
 
   UIButton button = UIButton.FromType(UIButtonType.RoundedRect);
 
   button.Frame =  new  RectangleF(0f, 30f,  320 , 40f);
 
   button.SetTitle( "Record Video" , UIControlState.Normal);
 
   button.TouchUpInside += delegate(object sender, EventArgs e) {
 
 
      var cameraType = UIImagePickerControllerSourceType.Camera;
 
      if (HasVideoSupport())
 
      {
 
         UIImagePickerController picker =  new  UIImagePickerController();
 
         picker.SourceType = cameraType;
 
         picker.MediaTypes =  new  []{ "public.movie" };
 
         picker.Delegate =  new  MyImagePickerDelegate( this );
 
         this .PresentModalViewController(picker,  true );
 
      }
 
      else
 
      {
 
         using (var alert =  new  UIAlertView( "Whoops" ,
 
                           "No video support found" null "Ok!" null ))
 
         {
 
            alert.Show();
 
         }
 
      }
 
   };
 
   this .View.AddSubview(button);
 
}
 
 
...
 
 
bool HasVideoSupport()
 
{
 
   var cameraType = UIImagePickerControllerSourceType.Camera;
 
   var cameraSupport =
 
                  UIImagePickerController.IsSourceTypeAvailable(cameraType);
 
   return  (!cameraSupport) ?  false  :
 
          UIImagePickerController.AvailableMediaTypes(cameraType)
 
                                        .Contains( "public.movie" );
 
}
 
 
图   10 - 18 
 
在记录视频时,还能够设置视频记录的质量。质量越低,那么获得的视频文件越小。能够像下面的代码这样使用UIImagePickerControllerQualityType枚举设置图像选取器的VideoQuality属性:
 
picker.VideoQuality =  UIImagePickerControllerQualityType.Low;
 
该枚举提供 3 个质量选项:High、Medium和Low。视频记录中使用的默认设置是Medium。在记录视频时可使用的另一个属性是VideoMaximumDuration,这个属性用于设置记录视频的最长持续时间(单位为秒)。视频最长能够是 10 分钟,记录视频的默认时间值也是 10 分钟。
 
10.2 . 5   编辑视频
 
采用与经过UIImagePickerController编辑图像相同的方式,在记录或选取视频时也能够将AllowEditing属性设置为 true 。这样,从图像选取器中选取了视频之后,就可以有一个接口对视频进行裁剪。与编辑图像时不一样,在完成编辑时,只会使用NSDictionary中的UIImagePickerCon-trollerMediaURL键得到临时裁剪或编辑的视频(而不是原始视频),该键在选择或记录视频后可用。临时建立的视频最终会被设备自动地清除。UIImagePickerControllerMediaURL对象属于NSUrl类型,须要将该视频对象强制转换为NSUrl类型来提取定位该文件所需的Path属性。图 10 - 19 显示了图像选取器视频编辑器的外观。
 
 
图   10 - 19
 
可是,视频选取器不是编辑视频最值得推荐的方式。对于编辑视频而言,最好使用专门的UIVideoEditorController类做为替代。该视频编辑器控制器为您提供了一个编辑窗口,它相似于图像选取器所使用的编辑窗口。然而,注意到用户有两个选项能够选择:Cancel和Save。UIVideoEditorController类对此提供了 3 个不一样的事件:
 
UserCancelled  当用户单击Cancel按钮时处理这个事件。
 
Saved  当用户单击Save按钮时处理该事件。
 
Failed  当产生没法预料的错误时会引起该事件,例如视频的格式没法编辑这样的错误。
 
Saved事件返回编辑好的视频文件的路径,Failed事件返回一个NSError对象,UserCancelled事件不会返回任何额外的信息。若是但愿得到原始文件的路径,那么能够将发送方强制转换为UIVideoEditorController对象,而后使用该对象的VideoPath属性。
 
 
视频编辑器只能用在直屏模式中
 
 
 
 
有了视频编辑器之后,经过分别设置VideoQuality和VideoMaximumDuration属性,就能够将编辑好的视频设置为较低的质量和强制编辑好的视频具备最大时间长度。
 
建立视频编辑界面是至关直观的。实例化一个新的UIVideoEditorController,将VideoPath设置为但愿编辑的视频的路径,而后将视频编辑器做为一个模态视图展现。由于没法知道运行该应用程序的iPhone是否支持对视频进行编辑,因此须要使用视频编辑器的静态方法CanEditVideoAtPath。传入视频路径,若是该视频能够编辑,那么该方法就返回 true 。程序清单 10 - 14 给出了一个建立专用视频编辑器界面的示例,图 10 - 20 给出了UIVideoEditorController界面的显示外观。
 
程序清单 10 - 14   使用专用视频编辑器界面
 
if (UIVideoEditorController.CanEditVideoAtPath(ChosenVideoPath))
 
{
 
   var videoEditor =  new  UIVideoEditorController();
 
   videoEditor.VideoPath = ChosenVideoPath;
 
   videoEditor.Saved += delegate(object sender, UIPathEventArgs e) {
 
      this .DismissModalViewControllerAnimated( true );
 
      // Handle edited video with e.Path
 
   };
 
   videoEditor.Failed += delegate(object sender, NSErrorEventArgs e) {
 
      this .DismissModalViewControllerAnimated( true );
 
      // Handle error here with e.Error
 
   };
 
   videoEditor.UserCancelled += delegate(object sender, EventArgs e) {
 
      this .DismissModalViewControllerAnimated( true );
 
      // Handle cancel
 
   };
 
   this .PresentModalViewController(videoEditor,  true );
 
}
 
 
10 - 20
 
10.2 . 6   将视频保存到相册
 
在将图像保存到相册时,要使用UIImage类上的静态方法保存文件。由于对视频文件的全部引用都使用路径而不是内存中的对象,因此UIVideo静态类提供了将视频保存到相册中所需的方法。视频功能仅限于特定的设备,所以在将视频保存到相册以前,须要检查一下该设备是否可以真正将视频保存到其相册中。静态方法IsCompatibleWithSavedPhotosAlbum提供了这种功能,若是传入能够保存到相册的视频的路径,那么该方法就会返回 true
 
为了将视频保存到相册中,一旦经过检查肯定该设备确实能够保存视频,那么就可使用UIVideo类上的静态方法SaveToPhotosAlbum。将但愿保存的视频的路径传入该方法,当保存视频之后会触发一个回调函数。程序清单 10 - 15 给出了完成这些任务的代码。
 
程序清单 10 - 15   将视频保存到相册
 
var videoPath = videoSavePath;
 
if (UIVideo.IsCompatibleWithSavedPhotosAlbum(videoPath))
 
{
 
   UIVideo.SaveToPhotosAlbum(videoPath, delegate (string path,
 
                                                  NSError errors)
 
   {
 
      using (var alert =  new  UIAlertView( "Success" "Video saved!" ,
 
                                         null "Ok!" null ))
 
      {
 
         alert.Show();
 
      }
 
   });
 
}
 
 
24 、CoreText基础-字体必修课
 
 
转自:http: //www.dreamingwish.com/dream-2011/coretext-ji-chu-font-basis.html
 
介绍一些字体的术语,以及对应的英文名称
 
字体(Font):是一系列字号、样式和磅值相同的字符(例如: 10 磅黑体Palatino)。现多被视为字样的同义词
 
字面(Face):是全部字号的磅值和格式的综合
 
字体集(Font family):是一组相关字体(例如:Franklin family包括Franklin Gothic、Fran-klinHeavy和Franklin Compressed)
 
磅值(Weight):用于描述字体粗度。典型的磅值,从最粗到最细,有极细、细、book、中等、半粗、粗、较粗、极粗
 
样式(Style):字形有三种形式:Roman type是直体;oblique type是斜体;utakuc type是斜体兼曲线(比Roman type更像书法体)。
 
x高度(X height):指小写字母的平均高度(以x为基准)。磅值相同的两字母,x高度越大的字母看起来比x高度小的字母要大
 
Cap高度(Cap height):与x高度类似。指大写字母的平均高度(以C为基准)
 
下行字母(Descender):例如在字母q中,基线如下的字母部分叫下伸部分
 
上行字母(Ascender):x高度以上的部分(好比字母b)叫作上伸部分
 
基线(Baseline):一般在x、v、b、m下的那条线
 
描边(Stroke):组成字符的线或曲线。能够加粗或改变字符形状
 
衬线(Serif):用来使字符更可视的一条水平线。如字母左上角和下部的水平线。
 
无衬线(Sans Serif):可让排字员不使用衬线装饰。
 
方形字(Block):这种字体的笔画使字符看起来比无衬线字更显眼,但还不到常见的衬线字的程度。例如Lubalin Graph就是方形字,这种字看起来好像是木头块刻的同样
 
手写体脚本(Calligraphic script):是一种仿效手写体的字体。例如Murray Hill或者Fraktur字体
 
艺术字(Decorative):像绘画般的字体
 
Pi符号(Pisymbol):非标准的字母数字字符的特殊符号。例如Wingdings和Mathematical Pi
 
连写(Ligature):是一系列连写字母如fi、fl、ffi或ffl。因为字些字母形状的缘由常常被连写,故排字员已习惯将它们连写。
 
 
 
25 、准确计算CoreText高度的方法
 
- ( int )getAttributedStringHeightWithString:(NSAttributedString *)  string  WidthValue:( int ) width
{
    int  total_height =  0 ;
    
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string);     //string 为要计算高度的NSAttributedString
    CGRect drawingRect = CGRectMake( 0 0 , width,  1000 );   //这里的高要设置足够大
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddRect(path, NULL, drawingRect);
    CTFrameRef textFrame = CTFramesetterCreateFrame(framesetter,CFRangeMake( 0 , 0 ), path, NULL);
    CGPathRelease(path);
    CFRelease(framesetter);
    
    NSArray *linesArray = (NSArray *) CTFrameGetLines(textFrame);
    
    CGPoint origins[[linesArray count]];
    CTFrameGetLineOrigins(textFrame, CFRangeMake( 0 0 ), origins);
    
    int  line_y = ( int ) origins[[linesArray count] - 1 ].y;   //最后一行line的原点y坐标
    
    CGFloat ascent;
    CGFloat descent;
    CGFloat leading;
    
    CTLineRef line = (CTLineRef) [linesArray objectAtIndex:[linesArray count]- 1 ];
    CTLineGetTypographicBounds(line, &ascent, &descent, &leading);
    
    total_height =  1000  - line_y + ( int ) descent + 1 ;     //+1为了纠正descent转换成int小数点后舍去的值
    
    CFRelease(textFrame);
    
    return  total_height;
    
}
 
  
 
//关于line坐标位置y为下图黑线所在位置 descent为黑线下部分字体的高度
 
//关于字体各部分高度说明  http://ios-iphone.diandian.com/post/2012-03-29/18055023 
 
 
26 、自定义拷贝、粘贴窗口
 
1 )、重写canBecomeFirstResponder方法
 
   - (BOOL)canBecomeFirstResponder{
   
   [ super  canBecomeFirstResponder];
   return  YES;
}
 
2 )、建立自定义UIMenuController
 
   UIMenuItem *share = [[UIMenuItem alloc] initWithTitle:@ "分享"  action: @selector (share:)];
    UIMenuItem *email = [[UIMenuItem alloc] initWithTitle:@ "邮件"  action: @selector (email:)];
    UIMenuItem *print = [[UIMenuItem alloc] initWithTitle:@ "打印"  action: @selector (print:)];
 
    UIMenuController *menu = [UIMenuController sharedMenuController];
    [menu setMenuItems:[NSArray arrayWithObjects:share, email,print, nil]];
    [menu setTargetRect:self.frame inView:self.superview];
    [menu setMenuVisible:YES animated:YES];
 
3 )、判断显示哪一个menu
 
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
   [ super  canPerformAction:action withSender:sender];
  
   if  ( action ==  @selector (share:) || action ==  @selector (email:) || action ==  @selector (print:))
   {
       return  YES;   
   }
   else
   {
       return  NO;
   }
}
 
  
 
 
27 、iOS本地推送通知方法
 
   
可在应用后台执行时,本地弹出推送通知,也能够定时触发推送。
 
- ( void )applicationDidEnterBackground:(UIApplication *)application
{
    
    UIDevice* device = [UIDevice currentDevice];
    
    BOOL backgroundSupported = NO;
    
    if  ([device respondsToSelector: @selector (isMultitaskingSupported)])
    {   
        backgroundSupported = device.multitaskingSupported;
    }
    if  (backgroundSupported && _bgTask==UIBackgroundTaskInvalid)
    {
        UIApplication *app = [UIApplication sharedApplication];
        
        _bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
        }]; 
        
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            while  (app.applicationState==UIApplicationStateBackground && _bgTask!=UIBackgroundTaskInvalid  && [app backgroundTimeRemaining] >  10
            {
                [NSThread sleepForTimeInterval: 1 ];
                NSLog(@ "background task %d left left  time %d." , _bgTask, ( int )[app backgroundTimeRemaining]);
                                
                if  ([app backgroundTimeRemaining] <  580 )
                {
                    UILocalNotification *localNotif = [[UILocalNotification alloc] init];
                    if  (localNotif)
                    {
                        localNotif.alertBody = [NSString stringWithString:@ "测试本地通知消息,后台提示功能。" ];
                        localNotif.alertAction = NSLocalizedString(@ "查看" , nil);
                        localNotif.soundName = UILocalNotificationDefaultSoundName;
                        localNotif.applicationIconBadgeNumber =  1 ;           
                        [application presentLocalNotificationNow:localNotif];
                        [localNotif release];
                        break ;
                    }
                }
            }
            
            NSLog(@ "background task %d finished." , _bgTask);    
            [app endBackgroundTask:_bgTask];
            _bgTask = UIBackgroundTaskInvalid;  
               
        });     
    }
 
}
 
28 、CoreText绘制文本出现行间距不等及解决办法
 
 
转自: http: //willonboy.tk/?p=1163
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  
 
 
最终在http: //www.cocoanetics.com/2012/02/radar-coretext-line-spacing-bug/
 
找到了DTCoreText库
相关文章
相关标签/搜索