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:@"[email protected]",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:[email protected][email protected]&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 [email protected] 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. } 二、在方法,函數和符號中使用弱連接 和使用類的弱連接一樣,在使用它之前要確保方法函數和符號在運行時的可用性,要不在編譯的時候會報錯動態連接錯誤,假設你想使用新版本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 三、弱連接整個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 四、條件編譯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 } 五、尋找出在程序中使用的以過時的實例 在IOS或Mac OS中有時候API會過時,但是過時不代表著那些就從Library或framework中刪除,但是在使用的過程中會報出warning,並且在不遠的 將來可能會被Apple從中移除。例如我們在code中使用了過時的函數 HPurge那麼就會報出如下 'HPurge' is deprecated (declared at /Users/steve/MyProject/main.c:51) 所以我們應當在工程中查找出如下的警告並且修改。 六、確定操作系統和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庫 Radar: “CoreText Line Spacing Bug” b 05, 2012 I finally got around to report an annoying bug in CoreText that has been bugging us in DTCoreText until I wrote a method to correct line origins as a workaround. rdar://10810114 The annoying thing about this bug is that it adds visual noise to otherwise pristinely rendered text. Especially on larger font sizes you see that additional space appears before each CTLine that ends with a paragraph break (\n). UPDATE: This is a duplicate of rdar://9931615. CoreText Line Spacing BugSummary CoreText inserts too much space before any line that ends with a \n. This extra space depends on the font and font size. On large print this causes visual noise by not being uniform. Steps to Reproduce Create a CTFrame from a CTFrameSetter with a string that is long enough to wrap and that contains paragraph breaks. Use a non-UI font, like for example AriaMT. Expected Results Line origins should be spaced by exactly the same distance for identical text and identical attributes. Actual Results Each line that ends with a paragraph break is shifted down. With the system UI font, size 54 baselines are spaced exactly 64 pixels apart. With ArialMT, size 54, baseline spacing differs between 62 and 65. Regression This has been a bug since before iOS 4.3. Notes This does not occur with all fonts, Using a system font the spacing is precisely correct. I have attached a project to demonstrate the issue. See TextView.m. It appears that the text metrics for an (invisible) paragraph glyph are miscalculated. Since the glyph is not visible you’d expect neither and ascender nor descender value. But instead the descender is too large. If you walk through the entire line and get the maximum ascenders and descenders the value is correct if you omit the \n in this calculation. In short: A trailing \n messes up the font metrics for the entire CTLine. Attachment: CoreTextLineOrigins Demo Project