[转]项目功能大全,让你的项目一天搞定

转自http://www.cocoachina.com/bbs/read.php?tid-320726.html
因原格式稍乱,稍作整理

项目功能大全,让你的项目一天搞定(给新手们一点干货)

  • 工作了好久一直很忙,好不容易有些时间,今天有人问我如何开始写一个项目,不禁回忆起自己写第一个项目的时候,到现在,突然感觉自己写的好多都是在重复,有些感想,特此写下这篇文章,给想入这行的新手们一些参考

    • 1.写项目之前首先我们要确定需求,明确项目需要实现哪些功能(吐槽下:好多项目的大部分功能都是一样的)

    • 2.美工,后台啥的我都直不一一说了情况都不一样

废话不说了直接开写程序

  • 框架

    • (1)首先我们要确定明确开发需要的框架,一个好的框架可以让我们轻松很多

框架可以自己写,也可以从网上找,多对比一下会有惊喜的

  • 页面
    • (1)一般每个详情页面都有相应的导航栏;如果有直接参考(见导航Deno,直接输入图片网址或者本地图片,设置坐标一键搞定);如果没有直接跳过
    • (2)然后就到了图文布局了:(推荐xib或storyboard)强大快速(尤其项目比较急的时候更是不二选择);不熟练的话那就老实的算坐标,布局吧!这个情况太多,一般难度也不大,费点心基本都可以搞定(我在这里就不详细说了。)
      我这里就按功能说了(不需要就直接跳过)

功能

搜索
  • 第一种搜索:
UISearchBar   遵守协议
//将要进入编辑模式调用
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
//显示cancel 按钮
    [searchBar setShowsCancelButton:YES animated:YES];
    return YES;

}
//将要退出编辑模式调用
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {

//请把代码粘贴在这里

    //隐藏cancel 按钮
    [searchBar setShowsCancelButton:NO animated:YES];
    return YES;
}

// 点击 搜索按钮的时候调用
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    //写入搜索内容(根据需要进行搜索)

}
//点击cancel 被调用
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
   //清空内容
    searchBar.text = @"";
    [searchBar resignFirstResponder];//收键盘

}

  • 第二种搜索

iOS8新出的感觉很强大,大家以后尽量都用它吧,紧跟版本呀!
UISearchController :它的其中一个属性就是searchBar
需要先设置它的搜索结果视图


//nil为和当前视图总用一个视图
self.searchVC = [[UISearchController alloc] initWithSearchResultsController:nil];
//如果不需要刻意再创建一个如:
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];

注意需要两个协议
//搜索协议
delegate
//更新搜索内容的代理
searchResultsUpdater
//必须要加上 自适应才能显示 搜索条
[self.searchVC.searchBar sizeToFit];
UISearchResultsUpdating 协议
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
NSLog(@"searchBar 更新内容");
//搜索内容
    //检索推荐谓词检索,快准狠有没有!详细的去百度吧度娘威武!

  //最后搜索数据源变了  ->让搜索控制器 内部的结果视图控制器的tableView的刷新
    UITableViewController *tableVC = (UITableViewController *)searchController.searchResultsController;
    [tableVC.tableView reloadData];
}
- (void)willPresentSearchController:(UISearchController *)searchController {
    NSLog(@"searchController 将要 显示");
   
}
- (void)didPresentSearchController:(UISearchController *)searchController {
    NSLog(@"searchController 已经 显示");
}
- (void)willDismissSearchController:(UISearchController *)searchController {
    NSLog(@"searchController 将要 消失");
}

- (void)didDismissSearchController:(UISearchController *)searchController {
    NSLog(@"searchController 已经 消失");
}
!!如果需要页面跳转
在进行页面跳转的时候要注意现在有两个视图呀需要区分开
UIViewController *vc = nil;
    //self.presentedViewController获取已经模态跳转上册的视图控制器,如果dismiss 之后 这个值会变成nil
    if (self.presentedViewController) {
        //判断一下 当前视图控制器有没有 模态跳转 的视图,如果有 那么 做另外一个模态跳转的时候 应该用 上一个已经模态跳转的控制器进行 模态跳转下一个
        vc = self.presentedViewController;
    }else {
        vc = self;
    }
    //模态跳转
    [vc presentViewController:alert animated:YES completion:nil];
    
    

下载

  • 首先判断是否已经下载过,然后告知服务器从哪里下载,
    -(1)下载前需要先确定路径

获取文件在沙盒中Documents下的全路径
//我们把url作为文件名字-》但是url 中可能存在一些非法字符不能作为文件名,这时我们可以用md5 对文件名进行加密 产生一个唯一的字符串 (十六进制的数字+A-F表示),这样就可以保证文件名不出现非法字符
   NSString *fileName = [url MD5Hash];//MD5
    //获取Documents
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject];
    //拼接路径
    NSString *filePath = [docPath stringByAppendingPathComponent:fileName];
    NSLog(@"path:%@",filePath);
***这里需要用到OC文件管理的知识!
//创建文件(首先检测有没有存在,如果没有在创建)
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
        //检测文件是否存在
        //不存在那么要创建
                   //NSFileManager 文件管理句柄
        [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
    }
//如果已存在获取已近下载的大小,如果不存在那么大小为0;   
      NSDictionary *fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
   //保存已经下载文件的大小
    self.loadedFileSize = fileSize;
   //下载前需要打开文件
    self.fileHandle = [NSFileHandle fileHandleForWritingAtPath:filePath];
*****(如果服务器支持可变断点续传可以照用,如果不支持请忽略 头域)
   //把文件大小告知服务器
    //创建可变请求 增加请求头
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
    //增加头域 告知服务器 从 哪个字节之后开始下载(不了解头域的还是那句话百度),不支持头域的可以直接跳过
    [request addValue:[NSString stringWithFormat:@"bytes=%llu-",fileSize] forHTTPHeaderField:@"Range"];
    //创建请求连接 开始异步下载
    _httpRequest = [[NSURLConnection alloc] initWithRequest:request delegate:self];
   NSURLConnectionDataDelegate
//接收服务器响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
在这里我们可以计算文件的总大小,获取数据的类型 : httpResponse.MIMEType ,数据的大小: NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response
NSLog(@"url:%@",httpResponse.URL.absoluteString);
//计算文件总大小 = 已经下载的+服务器将要发的
     ( self.loadedFileSize和上面关联着  数据是一段一段下载的)
    self.totalFileSize = self.loadedFileSize+httpResponse.expectedContentLength;
}
//接收数据过程 一段一段接收
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    //都是OC文件管理的知识,我就不细说了吧
    //下载一段 写一段数据
    //先把文件偏移量定位到文件尾
    [_fileHandle seekToEndOfFile];
    //写文件
    [_fileHandle writeData:data];
    //立即同步到磁盘
    [_fileHandle synchronizeFile];
    //记录已经下载数据大小
    self.loadedFileSize += data.length
}
//下载完成一定要关闭呀
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self stopDownload];//停止下载
}
//下载失败也要关闭呀
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [self stopDownload];
}
- (void)stopDownload {
    if (_httpRequest) {
        [_httpRequest cancel];
        _httpRequest = nil;
    }
    [_fileHandle closeFile];//关闭文件
}

收藏(关注)

  • 这和数据库有关联(数据库下面我会说的,不懂得也可以先看后面的数据库)

  • 点击收藏按钮的时候相当于在数据库里面增加了一条数据
    和关注按钮基本一样,有时候只是表现形似不同罢了本质都是一样

  • 这里我用的是DBManager

//关于数据库的方法,自己写的,就是这里面记录的都是收藏过得数据
//获取所有的收藏过得数据,放在数组里
self.favoriteArr = [[DBManager sharedManager]fetchall];
然后遍历数组获取相关图片的的URL下载图片
for (int i = 0; i<_self.favoriteArr.count; i++) {
    AppModel *model = _favoriteArr;
//我这里建个button 来显示收藏(具体问题具体分析说白了就是把你收藏的东西展现出来)图片下载用的是SDimage第三方库
     UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn sd_setImageWithURL:[NSURL URLWithString:model.iconUrl] forState:UIControlStateNormal placeholderImage:[UIImage imageNamed: @"account_candou"]];
。
。
。
}

登录和注册(每个App必备的功能)

  • 分为:自身登录注册 和 第三方登录

  • 主要说下自身登录*注册

大多数登录和注册都用的是post请求{这里需要我们和做服务器的协调好,登陆成功,登录失败返回什么
我们根据这些来提示用户是否登陆成功,!
如果用户登录成功我们需要记录用户登录成功这个状态,以防止用户多次登录,重复登录
这时我们需要定义一个全局变量
在登录成功后记录登录状态

extern:引入外部变量
extern BOOL isLogin;
isLogin=YES;

在其他页面再需要登录的先判断登录状态,如果为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;
}

分享

  • 系统和第三方

  • 系统

    • 协议:MFMessageComposeViewControllerDelegate(信息),MFMailComposeViewControllerDelegate(邮箱)

    • 1(信息)

//需要真机,虚拟机没效果
  if ([MFMessageComposeViewController canSendText]) {
//检测 当前应用 是否支持短信功能
   //支持的话 创建  具有短信模块的界面
MFMessageComposeViewController *message = [[MFMessageComposeViewController alloc] init];
                //设置联系人 (可以群发)
                message.recipients = @[@"10086",@"10011"];
                //设置短信的内容
                message.body = [NSString stringWithFormat:@"快来下载,这里有惊喜:%@“,@“网址”];
                   message.messageComposeDelegate = self;
                //模态跳转(内部有导航)
                [self presentViewController:message animated:YES completion:nil];

}
//协议
- (void)messageComposeViewController:(MFMessageComposeViewController *)controller didFinishWithResult:(MessageComposeResult)result {
    switch (result) {
        case MessageComposeResultCancelled:
        {
            NSLog(@"取消");
        }
            break;
        case MessageComposeResultSent:
        {
            NSLog(@"短信已发送");
        }
            break;
        case MessageComposeResultFailed:
        {
            NSLog(@"短信失败");
        }
            break;
            
        default:
            break;
    }
    //最后要模态跳转返回
    [controller dismissViewControllerAnimated:YES completion:nil];
}

(2)邮箱

if ([MFMailComposeViewController canSendMail]) {
                //检测是否支持邮箱功能
                //如果支持 创建界面
                MFMailComposeViewController *mail = [[MFMailComposeViewController alloc] init];
                //设置联系人
                [mail setToRecipients:@[@"xxxxx@qq.com”,@“zzzz@163.com"]];
                //设置抄送
                [mail setCcRecipients:@[@"xxx@sina.com"]];
                //设置标题
                [mail setSubject:@"分享爱限免应用"];
                //设置内容
                NSString *str = [NSString stringWithFormat:@"点击有惊喜:%@“,@“网址”];
                //第二个参数 是否以HTML格式
                [mail setMessageBody:str isHTML:YES];
                
                //添加附件
                NSData *data = UIImagePNGRepresentation([UIImage  imageNamed: @"account_candou"]);
                //第一个参数 文件二进制  2 文件的类型 3  文件的名字
                [mail addAttachmentData:data mimeType:@"image/png" fileName:@"account_candou"];
                
                //设置代理
                mail.mailComposeDelegate = self;
                //模态跳转
                [self presentViewController:mail animated:YES completion:nil];
            }

//协议
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
    switch (result) {
        case MFMailComposeResultCancelled:
            NSLog(@"邮件取消");
            break;
        case MFMailComposeResultSaved:
            NSLog(@"邮件保存");
            break;
        case MFMailComposeResultSent:
            NSLog(@"邮件发送");
            break;
        case MFMailComposeResultFailed:
            NSLog(@"邮件失败");
            break;
            
        default:
            break;
    }
    //模态跳转返回
    [self dismissViewControllerAnimated:YES completion:nil];
}
  • 友盟 (TODO)
//协议
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 <CoreLocation/CoreLocation.h>
协议 CLLocationManagerDelegate
//必须要强引用 在定位之前不能释放
@property (nonatomic,strong) CLLocationManager *manager;
  kCLLocationAccuracyBestForNavigation   -->最好的精度 用于导航
  kCLLocationAccuracyBest;//精度高的
  kCLLocationAccuracyNearestTenMeters;   10m
  kCLLocationAccuracyHundredMeters;  100m
  kCLLocationAccuracyKilometer;    1000m
  kCLLocationAccuracyThreeKilometers;  3000m
   //精度越高 越耗电
- (void)initLocationManager {
    //用的时候才创建 懒加载
    if (!self.manager) {
        //实例化 管理器
        self.manager = [[CLLocationManager alloc] init];
        //设置精度类型
        self.manager.desiredAccuracy = kCLLocationAccuracyBest;
        //设置 精度的大小
        self.manager.distanceFilter = 10;
        //获取定位的数据 必须要设置代理
        self.manager.delegate = self;
        //iOS8之后 必须要向用户申请授权
        /*
         1.在Info.plist中 添加选项
            Privacy - Location Usage Description(可选)
            NSLocationAlwaysUsageDescription(和代码要对应)
            或者
            NSLocationWhenInUseUsageDescription(代码要对应)
         2.在代码中 添加
            [self.manager requestAlwaysAuthorization];
            或者
            [self.manager requestWhenInUseAuthorization];
         */
        
        double v = [UIDevice currentDevice].systemVersion.doubleValue;
        if (v >= 8.0) {//判断版本
            //设置一个就可以
            //始终允许授权打开定位 (前后台都允许)
            [self.manager requestAlwaysAuthorization];
            //使用的时候允许 (前台允许)
            //[self.manager requestWhenInUseAuthorization];//
            //允许之后 第一次 会弹出一个警告框 选择允许
        }
        //下面的条件编译也可以 判断当前系统 版本
#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];
}
定位协议
//当定位的位置 发生改变的时候 一会一直调用
//会把定位的地理位置 传入
//locations 存放的就是地理位置
//数组中就一个元素
//
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
    if (locations.count) {
        //获取定位 位置
        CLLocation *location = [locations lastObject];
        //得到经纬度
        CLLocationCoordinate2D coordinate = location.coordinate;
        //打印经纬度
        NSLog(@"location:%f %f",coordinate.longitude,coordinate.latitude);
        //地理反编码
    //把经纬度装化为具体的地址    
#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"]);//获取地址
        
    });
}
//系统 地理反编码
- (void)reverseGeocoderWithSystem:(CLLocation*)location {
    //创建对象
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    //根据location内部的经纬度 进行 地理反编码
    [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)导航:在定位的基础的延伸

(3)查询:在定位的基础的延伸

(4)地图:
我把系统的说了,其他的百度和高德,腾讯的自己下()
和定位很类似

#import <MapKit/MapKit.h>
协议
MKMapViewDelegate
@property (nonatomic, strong) MKMapView *mapView;//地图
(void)initMapView {
    [self initManager];//需要定位 就调用
    
    //实例化 地图
    self.mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
    self.mapView.mapType = MKMapTypeStandard;
    //设置地图显示的 区域 (给一个中心位置)
    // 给一个 经纬度 和 缩放比例(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;
    
    //设置代理
    self.mapView.delegate = self;//可以操作点标注
    
    //粘贴地图
    [self.view addSubview:self.mapView];
    
    //增加大头针(需要就创建不需要可以无视)
    [self createAnnotation];

}

协议方法
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {

if ([annotation isKindOfClass:[MKPointAnnotation class]]) {
        //判断是哪一类点标注数据
        //创建 点标注视图 (采用复用机制)
        //队列获取空闲的
        MKPinAnnotationView *pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:@"MKPinAnnotationView"];
        if (pinView == nil) {
            //没有那么创建新的
            pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:@"MKPinAnnotationView"];
        }
     //设置属性(不需要的可以不设置)
        //是否显示气泡
        pinView.canShowCallout = YES;
        //是否有掉落的动画
        pinView.animatesDrop = YES;//(点标注视图子类MKPinAnnotationView才可以设置)
        //设置大头针视图的颜色  红  绿  紫三种
        pinView.pinColor =  MKPinAnnotationColorPurple;
        
        //设置气泡的左右侧附件
        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的子类 不需要再增加事件,有一个协议的方法可以替代
        //[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];
}
根据手势做出不同的调用
- (void)longPress:(UILongPressGestureRecognizer *)press {

}

数据库

  • sqlite(一般我们不直接向数据库进行操作,使用 第3方库来操作数据库,方便快速,但不能认为这些库就能存储数据,简单点理解这玩意就是中介)

  • 常用的有FMDB(开源库) CoreData(官方系统库)

常用的数据库操作,增删改查

  • 首先导入第三方库FMDB
    封装一个类来管理数据库

  • 方法:
    代码操作数据库 用fmdb 第三库操作 sqlite

  • fmdb 就是 通过对C语言的底层函数封装 对 数据库进行创建 增删改查数据

  • 步骤

    • 1.导入fmdb
    • 2.导入libsqlite3.dylib
    • 3.导入头文件FMDatabase.h
    • 4.创建数据库
      • 4.1打开数据库 创建表
      • 4.2 增删改查数据 代码执行sql 语句

//导入头文件
#import "FMDatabase.h"
创建数据库
- (void)createDataBase {
//沙盒路径
    NSString *docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    //拼接 数据库的路径后面的数据库的名字
    NSString *dataPath = [docPath stringByAppendingPathComponent:@"myData.sqlite"];
    //实例化一个 fmdb 对象
    NSLog(@"%@",dataPath);
    _database = [[FMDatabase alloc] initWithPath:dataPath];
    
    //如果打开成功 返回yes
    //调用open 的时候 如果数据库不存在那么就会先创建再打开,如果存在直接打开
    if ([_database open]) {//打开数据库
        //打开成功之后创建表
        [self createTable];
    }else{
        NSLog(@"open error:%@",[_database lastErrorMessage]);//最近一次错误
    }
    //数据库 一般 只打开一次  这样可以提高效率
}
创建表格
//其实的在数据库里面创建表是一样只不过用库来代创建方便(和用中介找房子一样的)
//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)";
    //执行 sql 语句 成功返回yes 失败返回no
    BOOL isSuccess = [_database executeUpdate:sql];
    if (!isSuccess) {
        NSLog(@"create table error:%@",_database.lastErrorMessage);
    }
}
//增加数据
- (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 中 ? 表示的是对象的占位符
    // ?  对应的必须是一个 OC的对象的地址
    
    //增加 sql 语句
    NSString *sql = @"insert into user(num,name,mydate,headimage) values (?,?,?,?)";
    
    //执行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.执行
    //会返回一个结果集合 查找的结果都在 FMResultSet中
    FMResultSet *rs = [_database executeQuery:sql];
    //遍历集合
    while ([rs next]) {//表示 FMResultSet中还有没有记录
        NSInteger num = [rs intForColumnIndex:0];//根据字段索引获取值
        NSInteger num2 = [rs intForColumn:@"num"];//根据字段名字获取值
        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 *)#>];//通用
    }
    //第一循环 遍历第0条记录
    //第二循环      1
    //...
    //直到最后没有了记录 循环退出
    
}
//更新数据
-(void)updateData
{
    NSString*sql=@"update user name=? where num<50 ";
    if ([_database executeUpdate:sql,@"小红" ]) {
        NSLog(@"updata error:%@",_database.lastErrorMessage);
    }
}
//删除数据
-(void)deletedatawithNUm:(NSInteger)num
{
    NSString*sql=@"delete from user where num=?";
    if ([_database executeUpdate:sql,@(num)]) {
        NSLog(@"%@",_database.lastErrorMessage);
    }
}
  • CoreData苹果官方的效果棒棒哒,也很好用

首先先右键—》Newfile—> (iOS )CoreData—>DataModel 完成后会有类名.xcdatamodel文件,可视化操作,创建表(注意改下表名字,默认的有可能关联不上),然后在表里面添加属性,完成后右键—》Newfile—> (iOS )Core data—>NSManagerObject subclass ,然后和你的表关联一下model层就创建出来了,
下面就是封装一个类来专门管理coredata,方便我们对数据库尽心操作

//导入头文件
#import <CoreData/CoreData.h>
//设计一个单例类 管理数据库
@interface CoreDataManager : NSObject
//非标准单例
+ (instancetype)defaultManager;

//上下文管理对象
@property (nonatomic,strong) NSManagedObjectContext *context;


//增删改查
//增加一个数据
- (void)insertDataWithName:(NSString *)name age:(int)age;

//根据名字删除
- (void)deleteDataWithName:(NSString *)name;

//修改数据 根据名字修改年龄
- (void)updateDataWithName:(NSString *)name age:(int)age;

//查询
//查询所有的数据
- (NSArray *)fetchAllData;

//根据名字查找
- (NSArray *)fetchDataWithName:(NSString *)name;

实现方法:
//(创建单例类的方法网上有好多)
+ (instancetype)defaultManager {
    static CoreDataManager *manager = nil;
    
    @synchronized(self) {
        manager = [[self alloc] init];
    }
    return manager;
}
//初始化准备工作
//1.导入头文件 CoreData/CoreData.h
//2.创建一个 一个数据模型文件(和数据库中的表类似),里面创建一些数据模型(设计属性)
//3.设计 一个数据模型类(根据数据模型文件)
//术语不明白的度娘走起(我就不唠叨了)
- (instancetype)init {
    if (self = [super init]) {
        //1.将数据模型文件中的 的模型 放入 modelFile 指向的 对象中
        //关联数据模型
         NSManagedObjectModel *modelFile = [NSManagedObjectModel mergedModelFromBundles:nil];

        //2.设置 存储 协调器  (协调 底层和上层)
        //2.1让 协调器 和 modelFile产生关联
        NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:modelFile];
        
        //2.2设置数据库文件的路径
        NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/Mydata.sqlite"];
        NSError *error = nil;
        //2.3设置 存储方式 根据路径创建 数据库文件
        ///将coreData数据  映射到数据库
        
        NSPersistentStore *store = [coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:path] options:nil error:&error];
        if (!store) {
            //创建 失败
            NSLog(@"creat store falied:%@",error.localizedDescription);
            return nil;
        }
        
        //3.托管对象 /上下文管理对象
        self.context = [[NSManagedObjectContext alloc] init];
        //托管对象 和 协调器 产生 关联
        self.context.persistentStoreCoordinator = coordinator;
        //_context 对数据库 进行增删改查
    }
    return self;
}
下面就是增删改查了
//增加一个数据
- (void)insertDataWithName:(NSString *)name age:(int)age {
    //1.给_context 操作的数据 增加一个UserModel实例对象
    
    //用 NSEntityDescription来增加
    UserModel *model = (UserModel *)[NSEntityDescription insertNewObjectForEntityForName:@"UserModel" inManagedObjectContext:self.context];
    model.name = name;
    model.age = @(age);
    model.fName = [name substringToIndex:1];
    
    //保存数据
    [self saveDataWithType:@"addData"];
}
- (void)saveDataWithType:(NSString *)type {
    NSError *error = nil;
    //回写 保存到数据库文件
    if (![self.context save:&error]) {
        //保存失败
        NSLog(@"%@:%@",type,error.localizedDescription);
    }
}
//根据名字删除
- (void)deleteDataWithName:(NSString *)name {
    //根据名字 找到对象
    NSArray *arr = [self fetchDataWithName:name];
    //遍历数组
    for (UserModel *model in arr) {
        [self.context deleteObject:model];
    }
    //保存数据
    [self saveDataWithType:@"deleteData"];
}
//修改数据 根据名字修改年龄
- (void)updateDataWithName:(NSString *)name age:(int)age{
    //1.根据名字 找到对象
    NSArray *arr = [self fetchDataWithName:name];
    //2.遍历数组
    for (UserModel *model in arr) {
        model.age = @(age);
    }
    //3.保存数据
    [self saveDataWithType:@"updateData"];

}
//查询
//查询所有的数据
- (NSArray *)fetchAllData {
    return [self fetchDataWithName:nil];
}
根据名字 在数据库中 查找 数据模型对象
//根据名字查找
- (NSArray *)fetchDataWithName:(NSString *)name {
    //1.先设置查找请求
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    //2.设置 查找的数据模型对象
    request.entity = [NSEntityDescription  entityForName:@"UserModel" inManagedObjectContext:_context];
    //3.设置 谓词 (根据条件 找要设置谓词)
    if (name) {
        //name 不是nil 那么就根据名字找 设置谓词
        //要查询 一个对象的 匹配的属性 那么需要设置谓词
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like %@",name];
        request.predicate = predicate;
    }
    //还可以设置排序 从小到大 或者从大到小
    //按照年龄降序 的一个描述
    NSSortDescriptor *sort1 = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
    //按照 name 进行 升序排列
    NSSortDescriptor *sort2 = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
#if 0
    request.sortDescriptors = @[sort1];//按照一个准则排序 age
#else
    //先按照 age 进行降序排 ,如果出现age 相同 那么 再按照name 升序排序
    request.sortDescriptors = @[sort1,sort2];
#endif
   
    //不设置 谓词 那么找所有
    
    //5.执行 查询请求  返回一个数组
    NSArray *resultArr = [_context executeFetchRequest:request error:nil];
    return resultArr;
}

封装以后直接调就行了

二维码(多关注点github好东西很多的)

参考
程胖出品——二维码扫描-(原生扫描+生成二维码+读取相册二维码)

第三方库ZBarSDK
导入库
导入系统库
libz.dylib
libicony.dylib
QuartzCore.framework
CoreVideo.framework
CoreMedia.framework
AVfoundation.framwork
原理示例:
二维码编译顺序
Zbar编译
需要添加AVFoundation CoreMedia CoreVideo QuartzCore lib


ZCZBarViewController*vc=[[ZCZBarViewController alloc]initWithBlock:^(NSString *str, BOOL isScceed) {
    if (isScceed) {
    NSLog(@"扫描后的结果~%@",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(@"扫描后的结果~%@",str);
        }
    }];
    [self presentViewController:vc animated:YES completion:nil];
}

推送

本地推送,网络推送,极光推送
网络推送:
应用场景
提醒业务,比如一些秀场,女主播可以通知他们的土豪(比如我),赶紧来撒钱
每天晚上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是谁,是苹果服务器,我们自己通过自己的设备向苹果服务器发送一个请求,告诉他们我们应用的一个标示,作为他们的联系
    //获取token需要进行处理,把这个标示发给我们服务器端做记录,当我们的服务器需要给用户发消息的时候,使用这个标示符+我们要发送的消息给苹果服务器,拼过会根据这个标示符发到对应的手机的里面
    //因为在有网的情况下,手机是一直和苹果服务器保持者联系,从理论上来说苹果可以控制任何一台手机的情况下进行相关的操作
    //最明显的就是,在有网的情况下,你收不到任何消息,但是在有网的情况下会弹出很多消息
NSLog(@"%@",deviceToken );
}
//出错处理
-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    NSLog(@"%@",error);
}
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    //接受推到消息的是一个字典,是规定的格式
    
}
  • 本地推送:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
        [application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
    }
   /创建一个本地推送
    UILocalNotification*local=[[UILocalNotification alloc]init];
    //设置推送内容
    local.alertBody=@“亲,什么时候约;
    //设置声音
    local.soundName=@"au_gameover.wav";
   //设置推送数目
    local.applicationIconBadgeNumber=1000;
    local.fireDate=[NSDate  dateWithTimeIntervalSinceNow:10];
    //把推送任务增加到推送队列中,需要注意,推送通知后,程序就算被杀掉,推送通知任然可以运行
//虚拟机上如果要看效果的话
//如果要弹出推送通知,需要程序退出后台,快捷键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(网上有教程)

VLC集成指南
添加libMobileVLCKit
添加库
libstdc++
libiconv
libbz2
Security
QuartzCore
CoreText
CFnetWork
OpenGLES
AudioToolbox
修改C++编译器为stdC++

聊天(tcp-udp)

(socket库)

#import "AsyncSocket.h"
协议
AsyncSocketDelegate
//建立发送端
    AsyncSocket * sendSocket;
    //建立服务端
    AsyncSocket * severSocket;
//建立一个数组保存连接
@property(nonatomic,strong)NSMutableArray * socketArray;

/*
       建立一个群聊,学生向教师端发送消息,教师端显示所有消息
     */
    
   - (void)CreatSocket
{
    sendSocket=[[AsyncSocket alloc] initWithDelegate:self];
    severSocket=[[AsyncSocket alloc] initWithDelegate:self];
    //服务端绑定端口,监听该端口接收的数据
    /*
       端口最大为65535,其中建议设置为5000以上,另外还有一些特殊的端口,例如8080为视频端口,建议不要占用
     */
    [severSocket acceptOnPort:5678 error:nil];
    
    
}
- (void)onSocket:(AsyncSocket *)sock didAcceptNewSocket:(AsyncSocket *)newSocket
{
  //接收的一个新连接,这个连接需要保存一下,然后持续保持连接
    [self.socketArray addObject:newSocket];
    
    //其中-1标示持续观察,如果设置为300,那么300秒以后就不在观察
    [newSocket readDataWithTimeout:-1 tag:100];
    
    
}
//协议方法
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
   //接收到的数据
    NSString * message=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if (_textView) {
        //在原来的旧数据上面,追加新的数据
        _textView.text=[NSString stringWithFormat:@"%@%@",_textView.text,message];
    }
    
    [sock readDataWithTimeout:-1 tag:100];
    
}

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
//发送成功
}
//textfild协议
//发送数据
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    if (textField.text.length>0) {
        // 发送数据
        if (![sendSocket isConnected]) {
            //确定是否连接,如果没有连接,则开始连接host:后面是iP地址
            [sendSocket connectToHost:@"192.168.2.7" onPort:5678 error:nil];
        }
        //当连接完成以后,发送数据
        //拼接数据是谁说,我希望获得当前设备的名称
       // [[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个参数 第一个参数用于截取的范围,第二个参数截取哪个view上

//示例代码
[ZCScreenShot beginImageContext:self.view.frame View:self.view];
//第一个参数是截取图片的范围,第二个参数是截取的那一层
#import "ZCScreenShot.h"
    UIImage *image=[ZCScreenShot beginImageContext:self.view.frame View:self.view];
(上面两个加起来就是一个小型教学客户端呀)

语音

(科大讯飞)
讯飞官方demo吧,实在是太全了我就不献丑了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,277评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,777评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,946评论 0 245
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,271评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,636评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,767评论 1 221
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,989评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,733评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,457评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,674评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,155评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,518评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,160评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,114评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,898评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,822评论 2 280
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,705评论 2 273

推荐阅读更多精彩内容