二維碼, 是用某種特定的幾何圖形按必定規律在平面(二維方向上)分佈的黑白相間的圖形記錄數據符號信息的;
● 信息獲取(名片、地圖、WIFI密碼、資料) ● 網站跳轉(跳轉到微博、手機網站、網站) ● 廣告推送(用戶掃碼,直接瀏覽商家推送的視頻、音頻廣告) ● 手機電商(用戶掃碼、手機直接購物下單) ● 防僞溯源(用戶掃碼、便可查看生產地;同時後臺能夠獲取最終消費地) ● 優惠促銷(用戶掃碼,下載電子優惠券,抽獎) ● 會員管理(用戶手機上獲取電子會員信息、VIP服務) ● 手機支付(掃描商品二維碼,經過銀行或第三方支付提供的手機端通道完成支付)
> 從iOS7開始集成了二維碼的生成和讀取功能 > 此前被普遍使用的zbarsdk目前不支持64位處理器
導入CoreImage框架session
#import <CoreImage/CoreImage.h>
經過濾鏡CIFilter生成二維碼框架
> 1. 實例化二維碼濾鏡 CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; > 2. 恢復濾鏡的默認屬性 [filter setDefaults]; > 3. 將字符串轉換成NSData NSData *data = [@"小碼哥" dataUsingEncoding:NSUTF8StringEncoding]; > 4. 經過KVC設置濾鏡inputMessage數據 [filter setValue:data forKey:@"inputMessage"]; > 5. 得到濾鏡輸出的圖像 CIImage *outputImage = [filter outputImage]; > 6. 將CIImage轉換成UIImage,並放大顯示 return [UIImage imageWithCIImage:outputImage scale:20.0 orientation:UIImageOrientationUp];
讀取二維碼須要導入AVFoundation框架ide
利用攝像頭識別二維碼中的內容(模擬器不行)工具
實例化拍攝設備測試
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
設置輸入設備網站
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:nil];
設置元數據輸出ui
3.1 實例化拍攝元數據輸出 AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init]; 3.2 設置輸出數據代理 [output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; 3.3 設置掃描取景範圍(rectOfInterest 都是按照橫屏來計算的 因此當豎屏的狀況下 x軸和y軸要交換一下) CGFloat screenW = [UIScreen mainScreen].bounds.size.width; CGFloat screenH = [UIScreen mainScreen].bounds.size.height; CGFloat scanW = screenW * 0.6; CGRect scanRect = CGRectMake((screenW - scanW) * 0.5, (screenH - scanW) * 0.5, scanW, scanW); output.rectOfInterest = CGRectMake(scanRect.origin.y / screenH, scanRect.origin.x / screenW, scanRect.size.height / screenH, scanRect.size.width / screenW); 3.4 設置掃描區域的邊框 UIView *scanV = [[UIView alloc] initWithFrame:scanRect]; [self.view addSubview:scanV]; scanV.layer.borderWidth = 2; scanV.layer.borderColor = [UIColor redColor].CGColor;
添加拍攝會話spa
4.1 實例化拍攝會話 AVCaptureSession *session = [[AVCaptureSession alloc] init]; 4.2 添加會話輸入 [session addInput:input]; 4.3 添加會話輸出 [session addOutput:output]; 4.3 設置輸出數據類型,須要將元數據輸出添加到會話後,才能指定元數據類型,不然會報錯 [output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
視頻預覽圖層代理
5.1 實例化預覽圖層 AVCaptureVideoPreviewLayer *preview = [AVCaptureVideoPreviewLayer layerWithSession:_session]; preview.videoGravity = AVLayerVideoGravityResizeAspectFill; preview.frame = self.view.bounds; 5.2 將圖層插入當前視圖 [self.view.layer addSublayer:preview]; self.previewLayer = preview;
啓動會話指針
[_session startRunning];
做用: > 邏輯錯誤:訪問未初始化的變量, 野指針等; > 聲明錯誤:從未使用過的對象; > 內存管理錯誤:如內存泄漏等; 分析方法: > 靜態內存分析是不運行程序,直接對代碼進行分析. > 根據代碼的上下文的語法結構,來分析是否有內存泄露 缺點: > 不必定準確,可是若是發現有提示,那麼去結合上下文看一下,這裏的代碼是否有問題 場景演練: > MRC 下橋接 - Foundation 和 CoreFoundation框架的數據類型轉換 > ARC 下橋接 - Foundation 和 CoreFoundation框架的數據類型轉換
做用: > 查看是內存的分配狀況 > 查看內存是否有釋放 場景演示: > UIImage 的兩種建立方法測試 > imageNamed: > imageWithContentOfFile:
做用: > 檢測程序在運行過程當中是否存在內存泄露 場景演示: > 模擬循環引用, 測試內存泄露
1. 最多見的是一些即時通信APP, 關聯聯繫人;
AddressBookUI.framework 框架
> 提供了聯繫人列表界面、聯繫人詳情界面、添加聯繫人界面等 > 通常用於選擇聯繫人
AddressBook.framework 框架
> 純C語言的API,僅僅是得到聯繫人數據 > 沒有提供UI界面展現,須要本身搭建聯繫人展現界面 > 裏面的數據類型大部分基於Core Foundation框架,使用起來極其蛋疼
ContactsUI.framework (iOS9.0最新框架)
> 方案1/方案2 的替代品
第三方框架 RHAddressBook
> 對AddressBook.framework框架的封裝
建立選擇聯繫人的控制器
ABPeoplePickerNavigationController *ppnc = [[ABPeoplePickerNavigationController alloc] init];
設置代理(用來接收用戶選擇的聯繫人信息)
ppnc.peoplePickerDelegate = self;
彈出聯繫人控制器
[self presentViewController:ppnc animated:YES completion:nil];
實現代理
// 1. 選中某個聯繫人時調用 - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person { } // 2. 選中某個聯繫人某個屬性時調用 - (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker didSelectPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier { } // 3. 點擊了取消按鈕會執行該方法 - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { }
在對應的代理方法中獲取聯繫人信息
// 1. 獲取選中聯繫人的姓名(姓lastname和名firstname) CFStringRef firstname = ABRecordCopyValue(person, kABPersonFirstNameProperty); CFStringRef lastname = ABRecordCopyValue(person, kABPersonLastNameProperty); NSString *firstName = (__bridge_transfer NSString *)(firstname); NSString *lastName = (__bridge_transfer NSString *)(lastname); NSLog(@"%@ %@", firstName, lastName); // 2. 獲取聯繫人的電話號碼 ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty); CFIndex count = ABMultiValueGetCount(phones); for (CFIndex i = 0; i < count; i++) { NSString *phoneLabel = (__bridge_transfer NSString *)ABMultiValueCopyLabelAtIndex(phones, i); NSString *phoneValue = (__bridge_transfer NSString *)ABMultiValueCopyValueAtIndex(phones, i); NSLog(@"label : %@ value : %@", phoneLabel, phoneValue); } // 3. 釋放再也不使用的對象 CFRelease(phones);
請求受權
// 1.獲取受權的狀態 ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); // 2.判斷受權狀態,若是是未決定狀態,才須要請求 if (status == kABAuthorizationStatusNotDetermined) { // 2.1.建立通訊錄對象 ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL); // 2.2.請求受權 ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { if (granted) { NSLog(@"受權成功"); } else { NSLog(@"受權失敗"); } }); }
判斷受權狀態, 若是已受權, 則繼續; 未受權, 則提示用戶, 並返回;
// 1.獲取受權的狀態 ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); // 2.若是用戶已經受權 if (status != kABAuthorizationStatusAuthorized) return;
建立通信錄對象
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
從通訊錄對象中, 獲取全部的聯繫人
CFArrayRef peopleArray = ABAddressBookCopyArrayOfAllPeople(addressBook);
遍歷全部的聯繫人
// 5.遍歷全部的聯繫人(每個聯繫人都是一條記錄) CFIndex peopleCount = CFArrayGetCount(peopleArray); for (CFIndex i = 0; i < peopleCount; i++) { // 6.獲取到聯繫人 ABRecordRef person = CFArrayGetValueAtIndex(peopleArray, i); // 7.獲取姓名 NSString *lastname = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty); NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty); NSLog(@"%@ %@", lastname, firstName); }
釋放再也不使用的對象
CFRelease(peopleArray); CFRelease(addressBook);
集成框架
> 1. 將整個工程拖入項目 > 2. 添加工程依賴 Build Phases -> Target Dependencies -> + > 3. 添加連接項 Build Settings -> Other Linker Flags -> -ObjC -all_load > 4. 導入框架頭文件 #import <RHAddressBook/AddressBoook.h>
使用框架獲取全部聯繫人信息
> 請求受權 // 1. 獲取受權狀態 RHAuthorizationStatus status = [RHAddressBook authorizationStatus]; if (status == RHAuthorizationStatusNotDetermined) { // 2. 建立通信錄對象 RHAddressBook *addressBook = [[RHAddressBook alloc] init]; // 3. 請求受權 [addressBook requestAuthorizationWithCompletion:^(bool granted, NSError *error) { if (granted) { NSLog(@"受權成功!"); } else { NSLog(@"受權失敗"); } }]; } > 獲取聯繫人信息 // 1. 判斷當前受權狀態 RHAuthorizationStatus status = [RHAddressBook authorizationStatus]; if (status != RHAuthorizationStatusAuthorized) { return; } // 2. 建立通信錄對象 RHAddressBook *addressBook = [[RHAddressBook alloc] init]; // 3. 獲取全部聯繫人 NSArray *peoples = addressBook.people; // 4. 遍歷全部聯繫人 for (RHPerson *person in peoples) { // 4.1 獲取聯繫人姓名 NSString *firstName = person.firstName; NSString *lastName = person.lastName; NSLog(@"%@---%@", firstName, lastName); // 4.2 獲取聯繫人電話 RHMultiStringValue *mv = person.phoneNumbers; for (int i = 0; i < mv.count; i ++) { // 4.2.1 獲取電話標籤 NSString *label = [mv labelAtIndex:i]; // 4.2.2 獲取電話號碼 NSString *phone = [mv valueAtIndex:i]; NSLog(@"%@--%@", label, phone); } }
通常應用在某些APP , 在節假日更換主題, 或者切換白天或者夜間模式時使用.
1. 將圖片以及顏色按照主題命名,使用虛擬文件夾, 直接在各個控制器針對不一樣主題單獨設置 缺點 : 1. 擴展性差, 增長一個主題很是複雜 2. 代碼分散, 可維護性差 3. 使用虛擬文件夾保存資源, 容易與其餘資源容易產生衝突
2. 抽取公共的切換主題類, 使用物理文件夾, 並將圖片按照應用場景命名, 不按照主題命名, 可是按照主題劃分文件夾 優勢: 1. 擴展性好, 增長主題簡單 2. 功能代碼集中, 方便維護 3. 資源包單獨管理, 不會產生資源衝突
1. 實現基本的換膚功能 2. 使用用戶偏好記錄當前皮膚主題 3. 抽取公共的皮膚管理類, 簡化控制器邏輯 4. 驗證多處加載主題情景 5. 加載主題文字顏色功能實現
例如 QQ空間APP 發說說時, 出現的什麼什麼型號的手機; 迅雷APP 下載文件時提示剩餘空間,已用空間
直接經過第三方工具類(UIDevice的分類), 進行獲取對應信息 緣由: 本身寫起來比較複雜, 不少C語言的東西, 並且沒有必要;
框架存在問題: 該第三方框架從2012年就中止更新了,意味着12年以後的手機型號都沒有, 須要手動添加, 修改框架 解決方案: 找到對應的實現方法, 使用真機進行測試, 手動新增手機型號