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

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

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

废话不说了直接开写程序
很重要(1)首先我们要确定明确开发需要的框架,一个好的框架可以让我们轻松很多

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

功能:搜索

第一种搜索:UISearchBar 遵守协议
//将要进入编辑模式调用

  • (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
    //显示cancel 按钮
    [searchBar setShowsCancelButton:YES animated:YES];
    return YES;}

//将要退出编辑模式调用

  • 1 (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
    2 请把代码粘贴在这里
    3 //隐藏cancel 按钮
    4 [searchBar setShowsCancelButton:NO animated:YES];
    5 return YES;
    6 }

// 点击 搜索按钮的时候调用

  • 1 (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar { 2 //写入搜索内容(根据需要进行搜索) 3 }

//点击cancel 被调用

  • 1 (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    2 //清空内容
    3 searchBar.text = @"";
    4 [searchBar resignFirstResponder];//收键盘
    5 }

  • 第二种搜索

  • 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必备的功能)
    分为 ,自身登录注册(自己起的名字知道大概意思就行了哈,别在意哈) 和 第三方登录(微博,QQ,微信,等外国的不常用,基本就是那几个社交的,忘了还有人人(话说没多少人用了吧),第三方遵循的基本原则:那个人多就用那个)
    主要说下自身登录注册
    大多数登录和注册都用的是post请求{这里需要我们和做服务器的协调好,登陆成功,登录失败返回什么
    我们根据这些来提示用户是否登陆成功,!
    如果用户登录成功我们需要记录用户登录成功这个状态,以防止用户多次登录,重复登录
    这时我们需要定义一个全局变量
    在登录成功后记录登录状态
    如
    extern:引入外部变量
    extern BOOL isLogin;
    isLogin=YES;在其他页面再需要登录的先判断登录状态,如果为YES就不需要在登陆了,如果没有提示用户需要登录后才可以进入
    }
    第三方登录直接到开放平台下demo;清除缓存这里我用的SDimage库的import "UIImageView+WebCache.h"
    -(double)getCachesSize
    {
    //SDimage缓存
    NSInteger sdfileSize=[[SDImageCache sharedImageCache]getSize]; NSStringcaches=[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)lastObject];
    NSStringmycacehs=[caches stringByAppendingPathComponent:@"MyCaches"];
    NSDirectoryEnumeratorenumor=[[NSFileManager defaultManager]enumeratorAtPath:mycacehs];
    NSUInteger mysize=0;
    for (NSString filename in enumor) {
    NSStringfilepath=[mycacehs stringByAppendingPathComponent:filename];
    NSDictionaryfiledict=[[NSFileManager defaultManager]attributesOfItemAtPath:filepath error:nil];
    //自身缓存
    mysize+=filedict.fileSize;
    }
    return (mysize+sdfileSize)/1024.0/1024.0;
    }
    分享
    :(系统的和第三方的: 第三方的推荐友盟(简单呀两句话sdk:直接抄不用改省事哈哈,不过就一个微博可以用,如果想用QQ,微信,等,自有大家蛋疼的去对着文档来吧,))
    系统的:
    协议: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];
    }
    //友盟的(不懂可以看官网)建立使用UM的 ,系统的太坑了,在咱们这没人用呀
    //协议
    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.导入头文件 #import "FMDatabase.h"创建 数据库
    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
    {
    NSStringsql=@"update user name=? where num<50 ";
    if ([_database executeUpdate:sql,@"小红" ]) {
    NSLog(@"updata error:%@",_database.lastErrorMessage);
    }
    }
    //删除数据
    -(void)deletedatawithNUm:(NSInteger)num
    {
    NSStringsql=@"delete from user where num=?";
    if ([_database executeUpdate:sql,@(num)]) {
    NSLog(@"%@",_database.lastErrorMessage);
    }
    }
    coredata苹果官方的效果棒棒哒,也很好用首先先右键—》newfile—> (iOS )core data—>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];//按照一个准则排序 ageelse
    //先按照 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 libiconv
    ZCZBarViewControllervc=[[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"
    UIButtonbutton=[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];
    UIImageViewimageview=[[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 200, 200)];
    imageview.image=[QRCodeGenerator qrImageForString:@"生成二维码" imageSize:300];
    [self.view addSubview:imageview];
    -(void)btn:(UIButton*)button
    {ZCZBarViewControllervc=[[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]];
    }
    /创建一个本地推送
    UILocalNotificationlocal=[[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];
    /
    //删除通知
    NSArraylocalArray=[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];

上面两个加起来就是一个小型教学客户端呀

转载于:https://www.cnblogs.com/xjy-123/p/5162995.html

项目功能大全,让你的项目一天搞定相关推荐

  1. 【2022 CCF BDCI 文心大模型创意项目】中秋款文心带你轻松搞定MV制作

    [2022 CCF BDCI 文心大模型创意项目]中秋款文心带你轻松搞定MV制作 项目效果先知 项目地址: https://aistudio.baidu.com/aistudio/projectdet ...

  2. 不懂技术的项目经理,学会这2点就能搞定项目!

    "不懂技术"一直是一类项目经理最大的痛楚. 我之前还特意写过一篇关于项目经理要不要懂技术的文章. 里面的观点很明确:不懂技术的PM,最终会尝尽生活的苦. 项目经理到底要不要懂技术? ...

  3. 图片提取文字功能很神奇?Java几行代码搞定它!

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/weixin_44671737/ article/details/110000864 摘要 近日浏 ...

  4. 图片提取文字功能很神奇?Java几行代码搞定它

    摘要 近日浏览网上一些图片提取文字的网站,觉得甚是有趣,花费半日也做了个在线图片识别程序,完成了两个技术方案的选择,一是tesseract+python flask的方案实现,二是tesseract+ ...

  5. Photoshop CC重磅功能发布:复杂抠图也能一键搞定

    近日,Adobe正式推出了Photoshop CC 19. 1 版本,去年 11 月份曾预告过的"选取对象"功能正式上线,不管是人物.动物.车辆.玩具--只需一个按钮,就能快速选取 ...

  6. 支付宝上线新功能:去这个国家入境十分钟搞定!

    11月15日,作为"新马泰"旅游胜地的泰国是出国旅游热度最高的几个国家之一.据统计,2018年中国游客赴泰旅游突破了1054万人,比2017年上升了7.4%.2018年赴泰旅游的中 ...

  7. Qt框架类图大全,类继承关系一图搞定

    一张图搞定所有Qt类,点击进入可查看各个类的详细信息. 新手最合适哦. Qt类详细

  8. android个人支付功能,个人app支付接入(三分钟搞定个人微信支付,支付宝支付问题)---贝贝支付...

    前言 想必很多人个人开发者和我有同样的感触,想要在自己开发的app中接入微信支付和支付宝支付,仅仅是去申请支付接口就把我们挡在了门外,微信和支付宝都只对接企业的,那不是想逼死我们个人开发者吗?一开始使 ...

  9. android开源项目框架大全:《IT蓝豹》

    2019独角兽企业重金招聘Python工程师标准>>> android开源项目框架大全: 1.多页切换TabHost 9 android-sticky-viewpager ViewP ...

最新文章

  1. AI一分钟 | “芯片门”影响仍在,英伟达旗下多款芯片也遭遇“幽灵”漏洞影响;贾跃亭邀媒体试乘法乐第FF91,你怎么看?
  2. Apache Maven 2 简介
  3. PAT甲级1071 Speech Patterns :[C++题解]字符串哈希
  4. linux下执行shell脚本文件,Linux下使用shell脚本自动执行脚本文件
  5. SAP Fiori Elements save按钮的实现细节
  6. python使用工具简介介绍
  7. ROS入门 SLAM
  8. virt-install选项详解
  9. Java POI 导出EXCEL经典实现 Java导出Excel弹出下载框(转载)
  10. 倒车雷达matlab仿真,倒车雷达系统设计(超声波-SEG4)
  11. Java中Object转化为int类型
  12. 小米笔记本备份、SSD分区、U盘Ghost详解及对产品的建议
  13. OPNsense用户手册中文版
  14. python元类 orm_Python3 元类与ORM
  15. android屏幕亮度自动调节解析
  16. 【技美百人计划】图形 4.4 抗锯齿概论
  17. D41FCB31FC1NE70 派克比例阀
  18. java工具类获取文件扩展名与content-type、http与content-type映射关系
  19. linux4.1内核配置以及编译及千兆网卡dp83867网卡驱动移植
  20. 刀片式服务器与虚拟机,为什么人们在开发虚拟主机时更喜欢刀片服务器?

热门文章

  1. 最新MyEclipseIDEAWebStorm安装 激活
  2. 那年学过的Web前端笔记
  3. 那年学过的Oracle笔记
  4. 台式计算机的主流配置,2017年台式电脑主流配置单
  5. xampp安装后无法启动apache
  6. list(链表)容器
  7. excel服务器没有响应怎么办,勤哲Excel服务器技术支持|Excel服务器常见问题解答...
  8. mysql的设计模式_数据库设计中使用设计模式
  9. 扫描服务器用户,服务器安全工具(自动扫描后门路径)
  10. android post数据到php服务器,通过post方法将数据上传到服务器Android Studio