工作了好久一直很忙,好不容易有些時間,今天有人問我如何開始寫一個項目,不禁回憶起自己寫第一個項目的時候,到現(xiàn)在,突然感覺自己寫的好多都是在重復(fù),有些感想,特此寫下這篇文章,給想入這行的新手們一些參考
1.寫項目之前首先我們要確定需求,明確項目需要實現(xiàn)哪些功能(吐槽下:好多項目的大部分功能都是一樣的)
2,美工,后臺啥的我都直不一一說了情況都不一樣
廢話不說了直接開寫程序
很重要(1)首先我們要確定明確開發(fā)需要的框架,一個好的框架可以讓我們輕松很多
框架可以自己寫,也可以從網(wǎng)上找,多對比一下會有驚喜的
頁面
(1)一般每個詳情頁面都有相應(yīng)的導(dǎo)航欄;如果有直接參考(見導(dǎo)航Deno,直接輸入圖片網(wǎng)址或者本地圖片,設(shè)置坐標一鍵搞定);如果沒有直接跳過
(2)然后就到了圖文布局了:(推薦xib或storyboard)強大快速(尤其項目比較急的時候更是不二選擇);不熟練的話那就老實的算坐標,布局吧!這個情況太多,一般難度也不大,費點心基本都可以搞定(我在這里就不詳細說了。)
我這里就按功能說了(不需要就直接跳過)
功能
搜索
第一種搜索:
UISearchBar?? 遵守協(xié)議
//將要進入編輯模式調(diào)用
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
//顯示cancel 按鈕
[searchBar setShowsCancelButton:YES animated:YES];
return YES;
}
//將要退出編輯模式調(diào)用
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
請把代碼粘貼在這里
//隱藏cancel 按鈕
[searchBar setShowsCancelButton:NO animated:YES];
return YES;
}
// 點擊 搜索按鈕的時候調(diào)用
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
//寫入搜索內(nèi)容(根據(jù)需要進行搜索)
}
//點擊cancel 被調(diào)用
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
//清空內(nèi)容
searchBar.text = @"";
[searchBar resignFirstResponder];//收鍵盤
}
第二種搜索
iOS8新出的感覺很強大,大家以后盡量都用它吧,緊跟版本呀!
UISearchController :它的其中一個屬性就是searchBar
需要先設(shè)置它的搜索結(jié)果視圖
//nil為和當前視圖總用一個視圖
self.searchVC = [[UISearchController alloc] initWithSearchResultsController:nil];
//如果不需要刻意再創(chuàng)建一個如:
UITableViewController *tableVC = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
tableVC.tableView.delegate = self;
tableVC.tableView.dataSource = self;
[tableVC.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"Cell"];
self.searchVC = [[UISearchController alloc] initWithSearchResultsController:tableVC];
注意需要兩個協(xié)議
//搜索協(xié)議
delegate
//更新搜索內(nèi)容的代理
searchResultsUpdater
//必須要加上 自適應(yīng)才能顯示 搜索條
[self.searchVC.searchBar sizeToFit];
UISearchResultsUpdating 協(xié)議
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
NSLog(@"searchBar 更新內(nèi)容");
//搜索內(nèi)容
//檢索推薦謂詞檢索,快準狠有沒有!詳細的去百度吧度娘威武!
//最后搜索數(shù)據(jù)源變了??->讓搜索控制器 內(nèi)部的結(jié)果視圖控制器的tableView的刷新
UITableViewController *tableVC = (UITableViewController *)searchController.searchResultsController;
[tableVC.tableView reloadData];
}
- (void)willPresentSearchController:(UISearchController *)searchController {
NSLog(@"searchController 將要 顯示");
}
- (void)didPresentSearchController:(UISearchController *)searchController {
NSLog(@"searchController 已經(jīng) 顯示");
}
- (void)willDismissSearchController:(UISearchController *)searchController {
NSLog(@"searchController 將要 消失");
}
- (void)didDismissSearchController:(UISearchController *)searchController {
NSLog(@"searchController 已經(jīng) 消失");
}
!!如果需要頁面跳轉(zhuǎn)
在進行頁面跳轉(zhuǎn)的時候要注意現(xiàn)在有兩個視圖呀需要區(qū)分開
UIViewController *vc = nil;
//self.presentedViewController獲取已經(jīng)模態(tài)跳轉(zhuǎn)上冊的視圖控制器,如果dismiss 之后 這個值會變成nil
if (self.presentedViewController) {
//判斷一下 當前視圖控制器有沒有 模態(tài)跳轉(zhuǎn) 的視圖,如果有 那么 做另外一個模態(tài)跳轉(zhuǎn)的時候 應(yīng)該用 上一個已經(jīng)模態(tài)跳轉(zhuǎn)的控制器進行 模態(tài)跳轉(zhuǎn)下一個
vc = self.presentedViewController;
}else {
vc = self;
}
//模態(tài)跳轉(zhuǎn)
[vc presentViewController:alert animated:YES completion:nil];
下載
首先判斷是否已經(jīng)下載過,然后告知服務(wù)器從哪里下載,
(1)下載前需要先確定路徑
獲取文件在沙盒中Documents下的全路徑
//我們把url作為文件名字-》但是url 中可能存在一些非法字符不能作為文件名,這時我們可以用md5 對文件名進行加密 產(chǎn)生一個唯一的字符串 (十六進制的數(shù)字+A-F表示),這樣就可以保證文件名不出現(xiàn)非法字符
NSString *fileName = [url MD5Hash];//MD5
//獲取Documents
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
//拼接路徑
NSString *filePath = [docPath stringByAppendingPathComponent:fileName];
NSLog(@"path:%@",filePath);
***這里需要用到OC文件管理的知識!
//創(chuàng)建文件(首先檢測有沒有存在,如果沒有在創(chuàng)建)
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
//檢測文件是否存在
//不存在那么要創(chuàng)建
//NSFileManager 文件管理句柄
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
}
//如果已存在獲取已近下載的大小,如果不存在那么大小為0;
NSDictionary *fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
//保存已經(jīng)下載文件的大小
self.loadedFileSize = fileSize;
//下載前需要打開文件
self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
*****(如果服務(wù)器支持可變斷點續(xù)傳可以照用,如果不支持請忽略 頭域)
//把文件大小告知服務(wù)器
//創(chuàng)建可變請求 增加請求頭
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
//增加頭域 告知服務(wù)器 從 哪個字節(jié)之后開始下載(不了解頭域的還是那句話百度),不支持頭域的可以直接跳過
[request addValue:[NSString stringWithFormat:@"bytes=%llu-",fileSize] forHTTPHeaderField:@"Range"];
//創(chuàng)建請求連接 開始異步下載
_httpRequest = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSURLConnectionDataDelegate
//接收服務(wù)器響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
在這里我們可以計算文件的總大小,獲取數(shù)據(jù)的類型 : httpResponse.MIMEType ,數(shù)據(jù)的大小: NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response
NSLog(@"url:%@",httpResponse.URL.absoluteString);
//計算文件總大小 = 已經(jīng)下載的+服務(wù)器將要發(fā)的
( self.loadedFileSize和上面關(guān)聯(lián)著??數(shù)據(jù)是一段一段下載的)
self.totalFileSize = self.loadedFileSize+httpResponse.expectedContentLength;
}
//接收數(shù)據(jù)過程 一段一段接收
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//都是OC文件管理的知識,我就不細說了吧
//下載一段 寫一段數(shù)據(jù)
//先把文件偏移量定位到文件尾
[_fileHandle seekToEndOfFile];
//寫文件
[_fileHandle writeData:data];
//立即同步到磁盤
[_fileHandle synchronizeFile];
//記錄已經(jīng)下載數(shù)據(jù)大小
self.loadedFileSize += data.length
}
//下載完成一定要關(guān)閉呀
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self stopDownload];//停止下載
}
//下載失敗也要關(guān)閉呀
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self stopDownload];
}
- (void)stopDownload {
if (_httpRequest) {
[_httpRequest cancel];
_httpRequest = nil;
}
[_fileHandle closeFile];//關(guān)閉文件
}
收藏(關(guān)注)
這和數(shù)據(jù)庫有關(guān)聯(lián)(數(shù)據(jù)庫下面我會說的,不懂得也可以先看后面的數(shù)據(jù)庫)
點擊收藏按鈕的時候相當于在數(shù)據(jù)庫里面增加了一條數(shù)據(jù)
和關(guān)注按鈕基本一樣,有時候只是表現(xiàn)形似不同罷了本質(zhì)都是一樣
這里我用的是DBManager
//關(guān)于數(shù)據(jù)庫的方法,自己寫的,就是這里面記錄的都是收藏過得數(shù)據(jù)
//獲取所有的收藏過得數(shù)據(jù),放在數(shù)組里
self.favoriteArr = [[DBManager sharedManager]fetchall];
然后遍歷數(shù)組獲取相關(guān)圖片的的URL下載圖片
for (int i = 0; i<_self.favoriteArr.count; i++) {
AppModel *model = _favoriteArr;
//我這里建個button 來顯示收藏(具體問題具體分析說白了就是把你收藏的東西展現(xiàn)出來)圖片下載用的是SDimage第三方庫
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn sd_setImageWithURL:[NSURL URLWithString:model.iconUrl] forState:UIControlStateNormal placeholderImage:[UIImage imageNamed: @"account_candou"]];
。
。
。
}
登錄和注冊(每個App必備的功能)
分為 ,自身登錄*注冊(自己起的名字知道大概意思就行了哈,別在意哈) 和 第三方登錄(微博,QQ,微信,等外國的不常用,基本就是那幾個社交的,忘了還有人人(話說沒多少人用了吧),第三方遵循的基本原則:那個人多就用那個)
主要說下自身登錄*注冊
大多數(shù)登錄和注冊都用的是post請求{這里需要我們和做服務(wù)器的協(xié)調(diào)好,登陸成功,登錄失敗返回什么
我們根據(jù)這些來提示用戶是否登陸成功,!
如果用戶登錄成功我們需要記錄用戶登錄成功這個狀態(tài),以防止用戶多次登錄,重復(fù)登錄
這時我們需要定義一個全局變量
在登錄成功后記錄登錄狀態(tài)
如
extern:引入外部變量
extern BOOL isLogin;
isLogin=YES;
在其他頁面再需要登錄的先判斷登錄狀態(tài),如果為YES就不需要在登陸了,如果沒有提示用戶需要登錄后才可以進入
}
第三方登錄直接到開放平臺下demo;
清除緩存
這里我用的SDimage庫的
#import "UIImageView+WebCache.h"
-(double)getCachesSize
{
//SDimage緩存
NSInteger sdfileSize=[[SDImageCache sharedImageCache]getSize];?? NSString*caches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
NSString*mycacehs=[caches stringByAppendingPathComponent:@"MyCaches"];
NSDirectoryEnumerator*enumor=[[NSFileManager defaultManager]enumeratorAtPath:mycacehs];
NSUInteger mysize=0;
for (NSString *filename in enumor) {
NSString*filepath=[mycacehs??stringByAppendingPathComponent:filename];
NSDictionary*filedict=[[NSFileManager defaultManager]attributesOfItemAtPath:filepath error:nil];
//自身緩存
mysize+=filedict.fileSize;
}
return (mysize+sdfileSize)/1024.0/1024.0;
}
分享
:(系統(tǒng)的和第三方的: 第三方的推薦友盟(簡單呀兩句話sdk:直接抄不用改省事哈哈,不過就一個微博可以用,如果想用QQ,微信,等,自有大家蛋疼的去對著文檔來吧,))
系統(tǒng)的:
協(xié)議:MFMessageComposeViewControllerDelegate(信息),MFMailComposeViewControllerDelegate(郵箱)
1(信息)
//需要真機,虛擬機沒效果
if ([MFMessageComposeViewController canSendText]) {
//檢測 當前應(yīng)用 是否支持短信功能
//支持的話 創(chuàng)建??具有短信模塊的界面
MFMessageComposeViewController *message = [[MFMessageComposeViewController alloc] init];
//設(shè)置聯(lián)系人 (可以群發(fā))
message.recipients = @[@"10086",@"10011"];
//設(shè)置短信的內(nèi)容
message.body = [NSString stringWithFormat:@"快來下載,這里有驚喜:%@“,@“網(wǎng)址”];
message.messageComposeDelegate = self;
//模態(tài)跳轉(zhuǎn)(內(nèi)部有導(dǎo)航)
[self presentViewController:message animated:YES completion:nil];
}
//協(xié)議
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
switch (result) {
case MessageComposeResultCancelled:
{
NSLog(@"取消");
}
break;
case MessageComposeResultSent:
{
NSLog(@"短信已發(fā)送");
}
break;
case MessageComposeResultFailed:
{
NSLog(@"短信失敗");
}
break;
default:
break;
}
//最后要模態(tài)跳轉(zhuǎn)返回
[controller dismissViewControllerAnimated:YES completion:nil];
}
(2)郵箱
if ([MFMailComposeViewController canSendMail]) {
//檢測是否支持郵箱功能
//如果支持 創(chuàng)建界面
MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
//設(shè)置聯(lián)系人
[mail setToRecipients:@[@"xxxxx@qq.com”,@“zzzz@163.com"]];
//設(shè)置抄送
[mail setCcRecipients:@[@"xxx@sina.com"]];
//設(shè)置標題
[mail setSubject:@"分享愛限免應(yīng)用"];
//設(shè)置內(nèi)容
NSString *str = [NSString stringWithFormat:@"點擊有驚喜:%@“,@“網(wǎng)址”];
//第二個參數(shù) 是否以HTML格式
[mail setMessageBody:str isHTML:YES];
//添加附件
NSData *data = UIImagePNGRepresentation([UIImage??imageNamed: @"account_candou"]);
//第一個參數(shù) 文件二進制??2 文件的類型 3??文件的名字
[mail addAttachmentData:data mimeType:@"image/png" fileName:@"account_candou"];
//設(shè)置代理
mail.mailComposeDelegate = self;
//模態(tài)跳轉(zhuǎn)
[self presentViewController:mail animated:YES completion:nil];
}
//協(xié)議
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
switch (result) {
case MFMailComposeResultCancelled:
NSLog(@"郵件取消");
break;
case MFMailComposeResultSaved:
NSLog(@"郵件保存");
break;
case MFMailComposeResultSent:
NSLog(@"郵件發(fā)送");
break;
case MFMailComposeResultFailed:
NSLog(@"郵件失敗");
break;
default:
break;
}
//模態(tài)跳轉(zhuǎn)返回
[self dismissViewControllerAnimated:YES completion:nil];
}
//友盟的(不懂可以看官網(wǎng))建立使用UM的 ,系統(tǒng)的太坑了,在咱們這沒人用呀
//協(xié)議
UMSocialUIDelegate
[UMSocialSnsService presentSnsIconSheetView:self appKey:@"507fcab25270157b37000010" shareText:str??shareImage:[UIImage imageNamed: @"account_candou"] shareToSnsNames:[NSArray arrayWithObjects:UMShareToSina,UMShareToSms,UMShareToEmail,UMShareToWechatTimeline,nil] delegate:self];(寫了這么多也就前三個有用微信需要自己去注冊)
在appdelgete.m中(其他的,哎都是淚看文檔把,你妹的呀)
//初始化UM
- (void)initUM {
//初始化
[UMSocialData setAppKey:@"507fcab25270157b37000010"];
}
地圖
又到了都是淚的地方,文檔走起吧,大蘋果太渣
推薦百度,高德,騰訊(百度最好,但是那啥注冊一把淚呀)
(1)定位:
//1.頭文件
#import
協(xié)議 CLLocationManagerDelegate
//必須要強引用 在定位之前不能釋放
@property (nonatomic,strong) CLLocationManager *manager;
kCLLocationAccuracyBestForNavigation?? -->最好的精度 用于導(dǎo)航
kCLLocationAccuracyBest;//精度高的
kCLLocationAccuracyNearestTenMeters;?? 10m
kCLLocationAccuracyHundredMeters;??100m
kCLLocationAccuracyKilometer;????1000m
kCLLocationAccuracyThreeKilometers;??3000m
//精度越高 越耗電
- (void)initLocationManager {
//用的時候才創(chuàng)建 懶加載
if (!self.manager) {
//實例化 管理器
self.manager = [[CLLocationManager alloc] init];
//設(shè)置精度類型
self.manager.desiredAccuracy = kCLLocationAccuracyBest;
//設(shè)置 精度的大小
self.manager.distanceFilter = 10;
//獲取定位的數(shù)據(jù) 必須要設(shè)置代理
self.manager.delegate = self;
//iOS8之后 必須要向用戶申請授權(quán)
/*
1.在Info.plist中 添加選項
Privacy - Location Usage Description(可選)
NSLocationAlwaysUsageDescription(和代碼要對應(yīng))
或者
NSLocationWhenInUseUsageDescription(代碼要對應(yīng))
2.在代碼中 添加
[self.manager requestAlwaysAuthorization];
或者
[self.manager requestWhenInUseAuthorization];
*/
double v = [UIDevice currentDevice].systemVersion.doubleValue;
if (v >= 8.0) {//判斷版本
//設(shè)置一個就可以
//始終允許授權(quán)打開定位 (前后臺都允許)
[self.manager requestAlwaysAuthorization];
//使用的時候允許 (前臺允許)
//[self.manager requestWhenInUseAuthorization];//
//允許之后 第一次 會彈出一個警告框 選擇允許
}
//下面的條件編譯也可以 判斷當前系統(tǒng) 版本
#ifdef __IPHONE_8_0 //如果定義過這個宏__IPHONE_8_0,iOS8.0之后就會定義宏__IPHONE_8_0
#endif
}
}
//開始定位
- (void)startLocation:(UIBarButtonItem *)item {
//判斷是否具備定位功能
if ([CLLocationManager locationServicesEnabled]) {
//懶加載管理器
[self initLocationManager];
//開始定位
[self.manager startUpdatingLocation];
}
}
//停止定位
- (void)stopLocation:(UIBarButtonItem *)item {
[self.manager stopUpdatingLocation];
}
定位協(xié)議
//當定位的位置 發(fā)生改變的時候 一會一直調(diào)用
//會把定位的地理位置 傳入
//locations 存放的就是地理位置
//數(shù)組中就一個元素
//
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (locations.count) {
//獲取定位 位置
CLLocation *location = [locations lastObject];
//得到經(jīng)緯度
CLLocationCoordinate2D coordinate = location.coordinate;
//打印經(jīng)緯度
NSLog(@"location:%f %f",coordinate.longitude,coordinate.latitude);
//地理反編碼
//把經(jīng)緯度裝化為具體的地址
#if 0
[self reverseGeocoderWithBaidu:coordinate];
#else
[self reverseGeocoderWithSystem:location];
#endif
}
}
//百度的
//需要OCJson解析
- (void)reverseGeocoderWithBaidu:(CLLocationCoordinate2D)coordinate {
//用多線程 異步下載
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:kPathUrl,coordinate.latitude,coordinate.longitude]]];
//json解析
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
NSDictionary *resultDict = dict[@"result"];
NSLog(@"address:%@",resultDict[@"formatted_address"]);//獲取地址
});
}
//系統(tǒng) 地理反編碼
- (void)reverseGeocoderWithSystem:(CLLocation*)location {
//創(chuàng)建對象
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
//根據(jù)location內(nèi)部的經(jīng)緯度 進行 地理反編碼
[geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
//placemarks??我們要的反編碼信息
for (CLPlacemark *placemark in placemarks) {
NSLog(@"country:%@",placemark.country);
NSLog(@"name:%@",placemark.name);
//遍歷地址字典
for (NSString *key in placemark.addressDictionary) {
NSLog(@"%@",placemark.addressDictionary[key]);
}
}
}];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(@"定位失敗");
}
(2)導(dǎo)航:在定位的基礎(chǔ)的延伸
(3)查詢:在定位的基礎(chǔ)的延伸
(4)地圖:
我把系統(tǒng)的說了,其他的百度和高德,騰訊的自己下()
和定位很類似
#import
協(xié)議
MKMapViewDelegate
@property (nonatomic, strong) MKMapView *mapView;//地圖
(void)initMapView {
[self initManager];//需要定位 就調(diào)用
//實例化 地圖
self.mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
self.mapView.mapType = MKMapTypeStandard;
//設(shè)置地圖顯示的 區(qū)域 (給一個中心位置)
// 給一個 經(jīng)緯度 和 縮放比例(0.01---0.05)
//34.77274892, 113.67591140
self.mapView.region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(34.77274892, 113.67591140),MKCoordinateSpanMake(0.01, 0.01));
//是否顯示 用戶位置
self.mapView.showsUserLocation = YES;
//設(shè)置代理
self.mapView.delegate = self;//可以操作點標注
//粘貼地圖
[self.view addSubview:self.mapView];
//增加大頭針(需要就創(chuàng)建不需要可以無視)
[self createAnnotation];
}
協(xié)議方法
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation {
if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
//判斷是哪一類點標注數(shù)據(jù)
//創(chuàng)建 點標注視圖 (采用復(fù)用機制)
//隊列獲取空閑的
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"MKPinAnnotationView"];
if (pinView == nil) {
//沒有那么創(chuàng)建新的
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"MKPinAnnotationView"];
}
//設(shè)置屬性(不需要的可以不設(shè)置)
//是否顯示氣泡
pinView.canShowCallout = YES;
//是否有掉落的動畫
pinView.animatesDrop = YES;//(點標注視圖子類MKPinAnnotationView才可以設(shè)置)
//設(shè)置大頭針視圖的顏色??紅??綠??紫三種
pinView.pinColor =??MKPinAnnotationColorPurple;
//設(shè)置氣泡的左右側(cè)附件
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 30, 30)];
redView.backgroundColor = [UIColor redColor];
pinView.leftCalloutAccessoryView = redView;
UIButton *button = [UIButton buttonWithType:UIButtonTypeInfoLight];
button.frame = CGRectMake(0, 0, 30, 30);
//氣泡附件 如果是UIControl的子類 不需要再增加事件,有一個協(xié)議的方法可以替代
//[button addTarget:<#(id)#> action:<#(SEL)#> forControlEvents:<#(UIControlEvents)#>];
pinView.rightCalloutAccessoryView = button;
return pinView;//返回對象地址
}
}
如果需要的還可以添加手勢
- (void)createLongPress {
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[self.mapView addGestureRecognizer: longPress];
}
根據(jù)手勢做出不同的調(diào)用
- (void)longPress:(UILongPressGestureRecognizer *)press {
}
數(shù)據(jù)庫
sqlite(一般我們不直接向數(shù)據(jù)庫進行操作,使用 第3方庫來操作數(shù)據(jù)庫,方便快速,但不能認為這些庫就能存儲數(shù)據(jù),簡單點理解這玩意就是中介)
常用的有FMDB(開源庫)??coredata(官方系統(tǒng)庫)
常用的數(shù)據(jù)庫操作,增刪改查
首先導(dǎo)入第三方庫FMDB
封裝一個類來管理數(shù)據(jù)庫
方法:
代碼操作數(shù)據(jù)庫 用fmdb 第三庫操作 sqlite
fmdb 就是 通過對C語言的底層函數(shù)封裝 對 數(shù)據(jù)庫進行創(chuàng)建 增刪改查數(shù)據(jù)
步驟
1.導(dǎo)入fmdb
2.導(dǎo)入libsqlite3.dylib
3.導(dǎo)入頭文件??#import "FMDatabase.h"
4. 創(chuàng)建 數(shù)據(jù)庫
4.1打開數(shù)據(jù)庫 創(chuàng)建表
4.2 增刪改查數(shù)據(jù)??代碼執(zhí)行sql 語句
//導(dǎo)入頭文件
#import "FMDatabase.h"
創(chuàng)建數(shù)據(jù)庫
- (void)createDataBase {
//沙盒路徑
NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//拼接 數(shù)據(jù)庫的路徑后面的數(shù)據(jù)庫的名字
NSString *dataPath = [docPath stringByAppendingPathComponent:@"myData.sqlite"];
//實例化一個 fmdb 對象
NSLog(@"%@",dataPath);
_database = [[FMDatabase alloc] initWithPath:dataPath];
//如果打開成功 返回yes
//調(diào)用open 的時候 如果數(shù)據(jù)庫不存在那么就會先創(chuàng)建再打開,如果存在直接打開
if ([_database open]) {//打開數(shù)據(jù)庫
//打開成功之后創(chuàng)建表
[self createTable];
}else{
NSLog(@"open error:%@",[_database lastErrorMessage]);//最近一次錯誤
}
//數(shù)據(jù)庫 一般 只打開一次??這樣可以提高效率
}
創(chuàng)建表格
//其實的在數(shù)據(jù)庫里面創(chuàng)建表是一樣只不過用庫來代創(chuàng)建方便(和用中介找房子一樣的)
//user是表名(后面的表的屬性)
- (void)createTable {
NSString *sql = @"CREATE TABLE if not exists user (serial integer??Primary Key Autoincrement,num integer,name Varchar(256),mydate datetime,headimage blob)";
//執(zhí)行 sql 語句 成功返回yes 失敗返回no
BOOL isSuccess = [_database executeUpdate:sql];
if (!isSuccess) {
NSLog(@"create table error:%@",_database.lastErrorMessage);
}
}
//增加數(shù)據(jù)
- (void)insertData {
NSInteger num = arc4random()%69+1;
NSString *name = [NSString stringWithFormat:@"xiaohong%u",arc4random()%100];
//時間
NSDate *date = [NSDate date];
//圖片要存成二進制
NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed: @"0"]);
//要用 ? 占位符 在sql 中 ? 表示的是對象的占位符
// ???對應(yīng)的必須是一個 OC的對象的地址
//增加 sql 語句
NSString *sql = @"insert into user(num,name,mydate,headimage) values (?,?,?,?)";
//執(zhí)行sql
BOOL isS = [_database executeUpdate:sql,@(num),name,date,imageData];
if (!isS) {
NSLog(@"insert into error :%@",_database.lastErrorMessage);
}
}
//查詢
- (void)fetchAllData{
//1.sql
NSString *sql = @"select num,name,mydate,headimage from user";
//2.執(zhí)行
//會返回一個結(jié)果集合 查找的結(jié)果都在 FMResultSet中
FMResultSet *rs = [_database executeQuery:sql];
//遍歷集合
while ([rs next]) {//表示 FMResultSet中還有沒有記錄
NSInteger num = [rs intForColumnIndex:0];//根據(jù)字段索引獲取值
NSInteger num2 = [rs intForColumn:@"num"];//根據(jù)字段名字獲取值
NSLog(@"num:%ld num2:%ld",num,num2);
NSLog(@"name:%@",[rs stringForColumn:@"name"]);
NSLog(@"date:%@",[rs dateForColumn:@"mydate"]);
NSLog(@"image_length:%ld",[rs dataForColumn:@"headimage"].length);
NSLog(@"-------------------------------");
//[rs objectForColumnName:<#(NSString *)#>];//通用
}
//第一循環(huán) 遍歷第0條記錄
//第二循環(huán)??????1
//...
//直到最后沒有了記錄 循環(huán)退出
}
//更新數(shù)據(jù)
-(void)updateData
{
NSString*sql=@"update user name=? where num<50 ";
if ([_database executeUpdate:sql,@"小紅" ]) {
NSLog(@"updata error:%@",_database.lastErrorMessage);
}
}}
}
//刪除數(shù)據(jù)
-(void)deletedatawithNUm:(NSInteger)num
{
NSString*sql=@"delete from user where num=?";
if ([_database executeUpdate:sql,@(num)]) {
NSLog(@"%@",_database.lastErrorMessage);
}
}
coredata蘋果官方的效果棒棒噠,也很好用
首先先右鍵—》newfile—> (iOS )core data—>DataModel??完成后會有類名.xcdatamodel文件,可視化操作,創(chuàng)建表(注意改下表名字,默認的有可能關(guān)聯(lián)不上),然后在表里面添加屬性,完成后右鍵—》newfile—> (iOS )core data—>NSManagerObject subclass ,然后和你的表關(guān)聯(lián)一下model層就創(chuàng)建出來了,
下面就是封裝一個類來專門管理coredata,方便我們對數(shù)據(jù)庫盡心操作
導(dǎo)入頭文件
#import
/設(shè)計一個單例類 管理數(shù)據(jù)庫
@interface CoreDataManager : NSObject
//非標準單例
+ (instancetype)defaultManager;
//上下文管理對象
@property (nonatomic,strong) NSManagedObjectContext *context;
//增刪改查
//增加一個數(shù)據(jù)
- (void)insertDataWithName:(NSString *)name age:(int)age;
//根據(jù)名字刪除
- (void)deleteDataWithName:(NSString *)name;
//修改數(shù)據(jù) 根據(jù)名字修改年齡
- (void)updateDataWithName:(NSString *)name age:(int)age;
//查詢
//查詢所有的數(shù)據(jù)
- (NSArray *)fetchAllData;
//根據(jù)名字查找
- (NSArray *)fetchDataWithName:(NSString *)name;
實現(xiàn)方法:
//(創(chuàng)建單例類的方法網(wǎng)上有好多)
+ (instancetype)defaultManager {
static CoreDataManager *manager = nil;
@synchronized(self) {
manager = [[self alloc] init];
}
return manager;
}
//初始化準備工作
//1.導(dǎo)入頭文件 CoreData/CoreData.h
//2.創(chuàng)建一個 一個數(shù)據(jù)模型文件(和數(shù)據(jù)庫中的表類似),里面創(chuàng)建一些數(shù)據(jù)模型(設(shè)計屬性)
//3.設(shè)計 一個數(shù)據(jù)模型類(根據(jù)數(shù)據(jù)模型文件)
//術(shù)語不明白的度娘走起(我就不嘮叨了)
- (instancetype)init {
if (self = [super init]) {
//1.將數(shù)據(jù)模型文件中的 的模型 放入 modelFile 指向的 對象中
//關(guān)聯(lián)數(shù)據(jù)模型
NSManagedObjectModel *modelFile = [NSManagedObjectModel mergedModelFromBundles:nil];
//2.設(shè)置 存儲 協(xié)調(diào)器??(協(xié)調(diào) 底層和上層)
//2.1讓 協(xié)調(diào)器 和 modelFile產(chǎn)生關(guān)聯(lián)
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:modelFile];
//2.2設(shè)置數(shù)據(jù)庫文件的路徑
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/Mydata.sqlite"];
NSError *error = nil;
//2.3設(shè)置 存儲方式 根據(jù)路徑創(chuàng)建 數(shù)據(jù)庫文件
///將coreData數(shù)據(jù)??映射到數(shù)據(jù)庫
NSPersistentStore *store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:path] options:nil error:&error];
if (!store) {
//創(chuàng)建 失敗
NSLog(@"creat store falied:%@",error.localizedDescription);
return nil;
}
//3.托管對象 /上下文管理對象
self.context = [[NSManagedObjectContext alloc] init];
//托管對象 和 協(xié)調(diào)器 產(chǎn)生 關(guān)聯(lián)
self.context.persistentStoreCoordinator = coordinator;
//_context 對數(shù)據(jù)庫 進行增刪改查
}
return self;
}
下面就是增刪改查了
//增加一個數(shù)據(jù)
- (void)insertDataWithName:(NSString *)name age:(int)age {
//1.給_context 操作的數(shù)據(jù) 增加一個UserModel實例對象
//用 NSEntityDescription來增加
UserModel *model = (UserModel *)[NSEntityDescription insertNewObjectForEntityForName:@"UserModel" inManagedObjectContext:self.context];
model.name = name;
model.age = @(age);
model.fName = [name substringToIndex:1];
//保存數(shù)據(jù)
[self saveDataWithType:@"addData"];
}
- (void)saveDataWithType:(NSString *)type {
NSError *error = nil;
//回寫 保存到數(shù)據(jù)庫文件
if (![self.context save:&error]) {
//保存失敗
NSLog(@"%@:%@",type,error.localizedDescription);
}
}
//根據(jù)名字刪除
- (void)deleteDataWithName:(NSString *)name {
//根據(jù)名字 找到對象
NSArray *arr = [self fetchDataWithName:name];
//遍歷數(shù)組
for (UserModel *model in arr) {
[self.context deleteObject:model];
}
//保存數(shù)據(jù)
[self saveDataWithType:@"deleteData"];
}
//修改數(shù)據(jù) 根據(jù)名字修改年齡
- (void)updateDataWithName:(NSString *)name age:(int)age{
//1.根據(jù)名字 找到對象
NSArray *arr = [self fetchDataWithName:name];
//2.遍歷數(shù)組
for (UserModel *model in arr) {
model.age = @(age);
}
//3.保存數(shù)據(jù)
[self saveDataWithType:@"updateData"];
}
//查詢
//查詢所有的數(shù)據(jù)
- (NSArray *)fetchAllData {
return [self fetchDataWithName:nil];
}
根據(jù)名字 在數(shù)據(jù)庫中 查找 數(shù)據(jù)模型對象
//根據(jù)名字查找
- (NSArray *)fetchDataWithName:(NSString *)name {
//1.先設(shè)置查找請求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
//2.設(shè)置 查找的數(shù)據(jù)模型對象
request.entity = [NSEntityDescription??entityForName:@"UserModel" inManagedObjectContext:_context];
//3.設(shè)置 謂詞 (根據(jù)條件 找要設(shè)置謂詞)
if (name) {
//name 不是nil 那么就根據(jù)名字找 設(shè)置謂詞
//要查詢 一個對象的 匹配的屬性 那么需要設(shè)置謂詞
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@",name];
request.predicate = predicate;
}
//還可以設(shè)置排序 從小到大 或者從大到小
//按照年齡降序 的一個描述
NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
//按照 name 進行 升序排列
NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
#if 0
request.sortDescriptors = @[sort1];//按照一個準則排序 age
#else
//先按照 age 進行降序排 ,如果出現(xiàn)age 相同 那么 再按照name 升序排序
request.sortDescriptors = @[sort1,sort2];
#endif
//不設(shè)置 謂詞 那么找所有
//5.執(zhí)行 查詢請求??返回一個數(shù)組
NSArray *resultArr = [_context executeFetchRequest:request error:nil];
return resultArr;
}
封裝以后直接調(diào)就行了
二維碼(多關(guān)注點github好東西很多的)
第三方庫ZBarSDK
導(dǎo)入庫
導(dǎo)入系統(tǒng)庫
libz.dylib
libicony.dylib
QuartzCore.framework
CoreVideo.framework
CoreMedia.framework
AVfoundation.framwork
原理示例:
二維碼編譯順序
Zbar編譯
需要添加AVFoundation??CoreMedia??CoreVideo QuartzCore libiconv
ZCZBarViewController*vc=[[ZCZBarViewController alloc]initWithBlock:^(NSString *str, BOOL isScceed) {
if (isScceed) {
NSLog(@"掃描后的結(jié)果~%@",str);
}
}];
[self presentViewController:vc animated:YES completion:nil];
生成二維碼
拖拽libqrencode包進入工程,注意點copy
添加頭文件#import "QRCodeGenerator.h"
imageView.image=[QRCodeGenerator qrImageForString:@"這個是什么" imageSize:imageView.bounds.size.width];
#import "ZCZBarViewController.h"
#import "QRCodeGenerator.h"
UIButton*button=[UIButton buttonWithType:UIButtonTypeSystem];
button.frame=CGRectMake(0, 70, 100, 100);
[button addTarget:self action:@selector(btn:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"掃描二維碼" forState:UIControlStateNormal];
[self.view addSubview:button];
UIImageView*imageview=[[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 200, 200)];
imageview.image=[QRCodeGenerator qrImageForString:@"生成二維碼" imageSize:300];
[self.view addSubview:imageview];
-(void)btn:(UIButton*)button
{
ZCZBarViewController*vc=[[ZCZBarViewController alloc]initWithBlock:^(NSString *str, BOOL isScceed) {
if (isScceed) {
NSLog(@"掃描后的結(jié)果~%@",str);
}
}];
[self presentViewController:vc animated:YES completion:nil];
}
推送
本地推送,網(wǎng)絡(luò)推送,激光推送(要錢呀!屌絲傷不起)
網(wǎng)絡(luò)推送:
應(yīng)用場景
提醒業(yè)務(wù),比如一些秀場,女主播可以通知他們的土豪(比如我),趕緊來撒錢
每天晚上8點影視劇的推送
小說更新
游戲活動推送等
//在這個方法里面寫
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([[[UIDevice currentDevice]systemVersion]floatValue]>=8.0) {
[[UIApplication sharedApplication]registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeAlert|UIUserNotificationTypeSound|UIUserNotificationTypeBadge) categories:nil]];
//開啟通知
[[UIApplication sharedApplication]registerForRemoteNotifications];
}
}
//當我們接到通知之后,如何去處理,首先去處理一個標識
-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
//我們首先獲取一個token值,相當于我們用的QQ,需要一個QQ號碼,那么這個QQ是誰,是蘋果服務(wù)器,我們自己通過自己的設(shè)備向蘋果服務(wù)器發(fā)送一個請求,告訴他們我們應(yīng)用的一個標示,作為他們的聯(lián)系
//獲取token需要進行處理,把這個標示發(fā)給我們服務(wù)器端做記錄,當我們的服務(wù)器需要給用戶發(fā)消息的時候,使用這個標示符+我們要發(fā)送的消息給蘋果服務(wù)器,拼過會根據(jù)這個標示符發(fā)到對應(yīng)的手機的里面
//因為在有網(wǎng)的情況下,手機是一直和蘋果服務(wù)器保持者聯(lián)系,從理論上來說蘋果可以控制任何一臺手機的情況下進行相關(guān)的操作
//最明顯的就是,在有網(wǎng)的情況下,你收不到任何消息,但是在有網(wǎng)的情況下會彈出很多消息
NSLog(@"%@",deviceToken );
}
//出錯處理
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
NSLog(@"%@",error);
}
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
//接受推到消息的是一個字典,是規(guī)定的格式
}
本地推送:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
/創(chuàng)建一個本地推送
UILocalNotification*local=[[UILocalNotification alloc]init];
//設(shè)置推送內(nèi)容
local.alertBody=@“親,什么時候約;
//設(shè)置聲音
local.soundName=@"au_gameover.wav";
//設(shè)置推送數(shù)目
local.applicationIconBadgeNumber=1000;
local.fireDate=[NSDate??dateWithTimeIntervalSinceNow:10];
//把推送任務(wù)增加到推送隊列中,需要注意,推送通知后,程序就算被殺掉,推送通知任然可以運行
//虛擬機上如果要看效果的話
//如果要彈出推送通知,需要程序退出后臺,快捷鍵Connand+Shitf+h
[[UIApplication sharedApplication]scheduleLocalNotification:local];
/*
//刪除通知
NSArray*localArray=[UIApplication sharedApplication].scheduledLocalNotifications;
//遍歷通知
for (UILocalNotification* notification in localArray) {
if ([notification.alertBody isEqual:@"親,什么時候約"]) {
[[UIApplication sharedApplication]cancelLocalNotification:notification];
}
}
//刪除所有的通知
// [[UIApplication sharedApplication]cancelAllLocalNotifications];
/*
本地推送的加入方式,比如判斷。3天沒來,每次程序啟動,把原來的舊通知,并且計算出3天后的時間
*/
//????NSInteger num=[UIApplication sharedApplication].applicationIconBadgeNumber;
//????num=num+1;
//????local.applicationIconBadgeNumber=num;
*/
}
//激光有Demo
VLC(網(wǎng)上有教程)
VLC集成指南
添加libMobileVLCKit
添加庫
libstdc++
libiconv
libbz2
Security
QuartzCore
CoreText
CFnetWork
OpenGLES
AudioToolbox
修改C++編譯器為stdC++
聊天(tcp-udp)
(socket庫)
#import "AsyncSocket.h"
協(xié)議
AsyncSocketDelegate
//建立發(fā)送端
AsyncSocket * sendSocket;
//建立服務(wù)端
AsyncSocket * severSocket;
//建立一個數(shù)組保存連接
@property(nonatomic,strong)NSMutableArray * socketArray;
/*
建立一個群聊,學(xué)生向教師端發(fā)送消息,教師端顯示所有消息
*/
- (void)CreatSocket
{
sendSocket=[[AsyncSocket alloc] initWithDelegate:self];
severSocket=[[AsyncSocket alloc] initWithDelegate:self];
//服務(wù)端綁定端口,監(jiān)聽該端口接收的數(shù)據(jù)
/*
端口最大為65535,其中建議設(shè)置為5000以上,另外還有一些特殊的端口,例如8080為視頻端口,建議不要占用
*/
[severSocket acceptOnPort:5678 error:nil];
}
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
//接收的一個新連接,這個連接需要保存一下,然后持續(xù)保持連接
[self.socketArray addObject:newSocket];
//其中-1標示持續(xù)觀察,如果設(shè)置為300,那么300秒以后就不在觀察
[newSocket readDataWithTimeout:-1 tag:100];
}
//協(xié)議方法
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
//接收到的數(shù)據(jù)
NSString * message=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (_textView) {
//在原來的舊數(shù)據(jù)上面,追加新的數(shù)據(jù)
_textView.text=[NSString stringWithFormat:@"%@%@",_textView.text,message];
}
[sock readDataWithTimeout:-1 tag:100];
}
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
//發(fā)送成功
}
//textfild協(xié)議
//發(fā)送數(shù)據(jù)
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
if (textField.text.length>0) {
// 發(fā)送數(shù)據(jù)
if (![sendSocket isConnected]) {
//確定是否連接,如果沒有連接,則開始連接host:后面是iP地址
[sendSocket connectToHost:@"192.168.2.7" onPort:5678 error:nil];
}
//當連接完成以后,發(fā)送數(shù)據(jù)
//拼接數(shù)據(jù)是誰說,我希望獲得當前設(shè)備的名稱
// [[UIDevice currentDevice]systemName];該方法只有在真機上才有效,在模擬器上無效
NSString * message=[NSString stringWithFormat:@"%@說:%@\n",@"房騫",textField.text];
[sendSocket writeData:[message dataUsingEncoding:NSUTF8StringEncoding] withTimeout:-1 tag:100];
}
return YES;
}
屏幕截圖
ZCScreenShot庫
此類用于屏幕截圖
添加庫:無
代碼示例 為截取全屏
[BeginImageContext beginImageContext:self.view.frame View:self.view];
2個參數(shù) 第一個參數(shù)用于截取的范圍,第二個參數(shù)截取哪個view上
//示例代碼
[ZCScreenShot beginImageContext:self.view.frame View:self.view];
//第一個參數(shù)是截取圖片的范圍,第二個參數(shù)是截取的那一層
#import "ZCScreenShot.h"
UIImage *image=[ZCScreenShot beginImageContext:self.view.frame View:self.view];
(上面兩個加起來就是一個小型教學(xué)客戶端呀)