首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

IOS开发——Protocol使用协议

protocol ['prəutəkɔl](样例:http://blog.sina.com.cn/s/blog_6aafe9c90100yozz.html)一、说明 两个类进行通讯,用协议就比較方便。 1.协议声明了能够被不论什么类实现的方法 2.协议不是类,它是定义了一个其它对象能够实现的接口 3.假设在某个类中实现了协议中的某个方法,也就是这个类实现了那个协议。 4.协议经经常使用来实现托付对象。一个托付对象是一种用来协同或者代表其它对象的特殊对象。 5:托付,就是调用自定义方法,别的类来实现。 6.新特性说明 @optional预编译指令:表示能够选择实现的方法 @required预编译指令:表示必须强制实现的方法 二、定义 .h @protocol ContactCtrlDelegate -(void)DismissContactsCtrl; @end @interface ContactsCtrl : UIViewController { id <ContactCtrlDelegate> delegate; } @property (nonatomic, assign) id <ContactCtrlDelegate> delegate; .m @synthesize delegate; 三、样例 比如:UITextView @protocol UITextViewDelegate <NSObject> @optional - (BOOL)textViewShouldBeginEditing:(UITextView *)textView; - (BOOL)textViewShouldEndEditing:(UITextView *)textView; - (void)textViewDidBeginEditing:(UITextView *)textView; - (void)textViewDidEndEditing:(UITextView *)textView; - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; - (void)textViewDidChange:(UITextView *)textView; - (void)textViewDidChangeSelection:(UITextView *)textView; @end 假设要调用以上这些方法。就必须设置UITextView的托付:TextView.delegate = self; 四、Demo 1、ContactsCtrl.h #import <UIKit/UIKit.h> //定义协议 @protocol ContactCtrlDelegate -(void)DismissContactsCtrl; @end @interface ContactsCtrl : UIViewController { IBOutlet UINavigationBar *ContactNavBar; id <ContactCtrlDelegate> delegate; } @property (nonatomic, assign) id <ContactCtrlDelegate> delegate; -(IBAction)canCelBtn:(id)sender; @end 2、ContactsCtrl.m @implementation ContactsCtrl @synthesize delegate; // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; ContactNavBar.topItem.prompt = @"选取联系人发送短信"; } //调用协议中的方法 -(IBAction)canCelBtn:(id)sender{ [delegate DismissContactsCtrl]; } 3、ProtocolDemoCtrl.h #import <UIKit/UIKit.h> #import "ContactsCtrl.h" @interface ProtocolDemoCtrl : UIViewController <ContactCtrlDelegate>{//加入托付 ContactsCtrl *contactsView; } 4、ProtocolDemoCtrl.m #import "ProtocolDemoCtrl.h" #define BARBUTTONADD(SELECTOR) [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:SELECTOR] autorelease]; @implementation ProtocolDemoCtrl @synthesize contactsView; // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.rightBarButtonItem = BARBUTTONADD(@selector(addContactAction:)); } - (void)addContactAction:(id)sender{ ContactsCtrl *contactView = [[ContactsCtrl alloc] initWithNibName:@"ContactsCtrl" bundle:nil]; self.contactsView = contactView; contactsView.delegate = self;//设置托付 [self presentModalViewController:contactsView animated:YES]; [contactView release]; } //实现ContactCtrlDelegate协议中的方法 -(void)DismissContactsCtrl{ [contactsView dismissModalViewControllerAnimated:YES]; } 综上,假设A类.h文件定义了一个协议,在A类里面我们还须要定义一个托付delegate,协议里面有个必须实现的methodA方法(@required,这种方法在实现了协议的类里面实现),在A类的.m文件里须要调用这个methodA方法,我们使用托付调用这个methodA方法 [delegate DismissContactsCtrl]; 类B实现了这个协议,在.h文件里定义类A的对象a,在.m文件里须要实现methodA方法。而且须要设置托付 a.delegate = self;//设置托付 假设MethodA返回的是B类的对象,那么在A类中就能够调用B类属性和方法国,B这个类可以调用A的属性和方法。 版权声明:本文博客原创文章。博客,未经同意,不得转载。 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/4657138.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS开发-UITableView常用方法

UITableView常用来展示数据,类似于Android中的ListView,相对于Android中的ListView而言,UITableView的实现是非常简单,继承UITableViewDataSource,UITableViewDelegate然后根据需要是实现对应的方法即可。UITableView有两个默认的内置风格,Plain和Grouped,Plain表明表格视图自身没有真正地在你自己实际地提供任何外观之前提供很多的外观,大部分情况下,它会做的唯一的事情是它会给你这些header和footer。Grouped表格视图是UIKit提供的分组风格。风格的话如果有特别的需求,还可以自定义分组的风格。 页面布局 页面比较简单,一个简单UITableView: 头文件中的不需要声明,需要实现一下协议: 1 2 3 @interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate> @end Demo实现 声明三个数据用来展示数据: 1 2 3 4 5 6 7 @interface ViewController () { NSArray *channelArr; NSMutableArray *filmArr; NSMutableArray *tvArr; } @end 初始化数据: 1 2 3 4 5 6 7 - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. channelArr=[[ NSArray alloc] initWithObjects:@ "电影" ,@ "电视剧" , nil ]; filmArr=[[ NSMutableArray alloc] initWithObjects:@ "智取威虎山" ,@ "一步之遥" ,@ "匆匆那年" ,@ "北京爱情故事" , nil ]; tvArr=[[ NSMutableArray alloc] initWithObjects:@ "何以笙箫默" ,@ "锋刃" ,@ "陆小凤与花满楼" ,@ "武媚娘传奇" , nil ]; } 设置分组的组数: 1 2 3 4 - ( NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{ NSLog (@ "%lu" ,(unsigned long )channelArr.count); return [channelArr count]; } 设置分组的标题: 1 2 3 - ( NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:( NSInteger )section{ return [channelArr objectAtIndex:section]; } 设置每个分组下内容的个数: 1 2 3 4 5 6 7 8 9 10 11 12 - ( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section{ NSInteger count=0; switch (section) { case 0: count=[filmArr count]; break ; case 1: count=[tvArr count]; break ; } return count; } 设置每个分组下的具体内容: 1 2 3 4 5 6 7 8 9 10 11 12 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath{ UITableViewCell *cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: nil ]; switch (indexPath.section) { case 0: [cell.textLabel setText:[filmArr objectAtIndex:indexPath.row]]; break ; case 1: [cell.textLabel setText:[tvArr objectAtIndex:indexPath.row]]; break ; } return cell; } 设置分组标题和底部的高度: 1 2 3 4 5 6 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:( NSInteger )section{ return 40; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:( NSInteger )section{ return 0; } 设置点击事件: 1 2 3 4 5 6 7 8 9 10 11 12 13 - ( void )tableView:(UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath{ NSString *content; switch (indexPath.section) { case 0: content=[ NSString stringWithFormat:@ "%@-%@" ,channelArr[0],[filmArr objectAtIndex:indexPath.row]]; break ; case 1: content=[ NSString stringWithFormat:@ "%@-%@" ,channelArr[1],[tvArr objectAtIndex:indexPath.row]]; break ; } UIAlertView *alterView=[[UIAlertView alloc] initWithTitle:@ "当前位置:" message:content delegate: self cancelButtonTitle:@ "确定" otherButtonTitles: nil ]; [alterView show]; } 最终效果: 源代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 // // ViewController.m // TableView //http://www.cnblogs.com/xiaofeixiang/ // Created by keso on 15/1/24. // Copyright (c) 2015年 keso. All rights reserved. // #import "ViewController.h" @interface ViewController () { NSArray *channelArr; NSMutableArray *filmArr; NSMutableArray *tvArr; } @end @implementation ViewController - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. channelArr=[[ NSArray alloc] initWithObjects:@ "电影" ,@ "电视剧" , nil ]; filmArr=[[ NSMutableArray alloc] initWithObjects:@ "智取威虎山" ,@ "一步之遥" ,@ "匆匆那年" ,@ "北京爱情故事" , nil ]; tvArr=[[ NSMutableArray alloc] initWithObjects:@ "何以笙箫默" ,@ "锋刃" ,@ "陆小凤与花满楼" ,@ "武媚娘传奇" , nil ]; } //设置分组的组数 - ( NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{ NSLog (@ "%lu" ,(unsigned long )channelArr.count); return [channelArr count]; } //设置分组的标题 - ( NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:( NSInteger )section{ return [channelArr objectAtIndex:section]; } //- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section{ // return @"我是底部"; //} //设置每个分组的个数 - ( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section{ NSInteger count=0; switch (section) { case 0: count=[filmArr count]; break ; case 1: count=[tvArr count]; break ; } return count; } //设置分组中具体的内容 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath{ UITableViewCell *cell =[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: nil ]; switch (indexPath.section) { case 0: [cell.textLabel setText:[filmArr objectAtIndex:indexPath.row]]; break ; case 1: [cell.textLabel setText:[tvArr objectAtIndex:indexPath.row]]; break ; } return cell; } //分组标题的行高 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:( NSInteger )section{ return 40; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:( NSInteger )section{ return 0; } //选中点击事件 - ( void )tableView:(UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath{ NSString *content; switch (indexPath.section) { case 0: content=[ NSString stringWithFormat:@ "%@-%@" ,channelArr[0],[filmArr objectAtIndex:indexPath.row]]; break ; case 1: content=[ NSString stringWithFormat:@ "%@-%@" ,channelArr[1],[tvArr objectAtIndex:indexPath.row]]; break ; } UIAlertView *alterView=[[UIAlertView alloc] initWithTitle:@ "当前位置:" message:content delegate: self cancelButtonTitle:@ "确定" otherButtonTitles: nil ]; [alterView show]; } - ( void )didReceiveMemoryWarning { [ super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4246563.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发5——文件读写

一、基本概念 在Android应用中保存文件,保存的位置有两处 ①手机自带的存储空间,较小(如200M),适合保存一些小文件,Android中保存位置在data/data/应用包名/files目录 ②外存储设备如SD卡,较大,适合保存大文件如视频,Android中保存位置在mnt/sdcard目录,androd1.5,android1.6保存在sdcard目录 保存的位置通过android的file explorer视图可以找到 二、例子 packagecn.xy.service; importjava.io.ByteArrayOutputStream; importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importandroid.content.Context; importandroid.os.Environment; /** *文件操作类 * *@authorXY * */ publicclassFileService { /** *上下文对象 */ privateContextcontext; publicFileService(Contextcontext) { super(); this.context=context; } /** *保存文件(保存至手机自带的存储空间) * *@paramfilename文件名 *@paramfileContent文件内容 */ @SuppressWarnings("static-access") publicvoidsave(Stringfilename,StringfileContent)throwsException { //私有操作模式:1.该文件只能被本应用访问。2.写入文件的内容会覆盖原有文件的内容 FileOutputStreamfos=context.openFileOutput(filename,context.MODE_PRIVATE);//默认保存在手机自带的存储空间 fos.write(fileContent.getBytes("UTF-8")); fos.close(); } /** *保存文件之SD卡 * *@paramfilename文件名 *@paramfileContent文件内容 */ publicvoidsaveInSDCard(Stringfilename,StringfileContent)throwsException { //若文件被保存在SDCard中,该文件不受读写控制 Filefile=newFile(Environment.getExternalStorageDirectory(),filename); FileOutputStreamfos=newFileOutputStream(file); fos.write(fileContent.getBytes("UTF-8")); fos.close(); } /** *读取文件内容 *在创建ByteArrayOutputStream类实例时,内存中会创建一个byte数组类型的缓冲区,缓冲区会随着数据的不断写入而自动增长,可使用 *toByteArray()和toString()获取数据关闭ByteArrayOutputStream *无效,此类中的方法在关闭此流后仍可被调用,而不会产生任何IOException * *@paramfilename文件名 *@return */ publicStringread(Stringfilename)throwsException { FileInputStreamfis=context.openFileInput(filename);//默认到手机自带的存储空间去找 ByteArrayOutputStreamoutStream=newByteArrayOutputStream(); byte[]buffer=newbyte[1024]; intlen=0; //将内容读到buffer中,读到末尾为-1 while((len=fis.read(buffer))!=-1) { //本例子将每次读到字节数组(buffer变量)内容写到内存缓冲区中,起到保存每次内容的作用 outStream.write(buffer,0,len); } //取内存中保存的数据 byte[]data=outStream.toByteArray(); fis.close(); Stringresult=newString(data,"UTF-8"); returnresult; } } MainActivity try { //存储在手机自带存储空间 fs.save(filename,fileContent); Toast.makeText(getApplicationContext(),R.string.success,Toast.LENGTH_SHORT).show(); //存储在外部设备SD卡 //判断SDCARD是否存在和是否可读写 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { fs.saveInSDCard(filename,fileContent); Toast.makeText(getApplicationContext(),R.string.success,Toast.LENGTH_SHORT).show(); } else { Toast.makeText(getApplicationContext(),R.string.failsdcard,Toast.LENGTH_SHORT).show(); } } catch(Exceptione) { Toast.makeText(getApplicationContext(),R.string.fail,Toast.LENGTH_SHORT).show(); Log.e(tag,e.getMessage()); } 文件名不带路径,直接输入如xy.txt 对于SD卡的操作,需要在AndroidManifest.xml加入权限 <!--在SDCard中创建和删除文件的权限--> <uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!--往SDCard中写入数据的权限--> <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 三、一些API ①Environment.getExternalStorageDirectory()获取的路径为mnt/sdcard目录,对于android1.5,1.6的路径是sdcard目录 ②Activity中提供了两个API getCacheDir()获取的路径为data/data/应用包名/cache目录 getFilesDir()获取的路径为data/data/应用包名/files目录 本文转自IT徐胖子的专栏博客51CTO博客,原文链接http://blog.51cto.com/woshixy/1076826如需转载请自行联系原作者 woshixuye111

优秀的个人博客,低调大师

iOS开发-多线程简介

多线程从概念上理解是指从软件或者硬件上实现多个线程并发执行的技术,简单点理解就是同一时间可以执行多个事情(比如说一边听歌一边码代码),听歌是一个线程,码代码是一个线程,如果是单核CPU的话,上面两个动作其实可以确切的理解为并发,也就是伪并行,只是两者相差的时间太快没有察觉。电脑现在一般都是双核的或者四核的,比以往的运算能有提高了不少,iOS中六种可以选择的操作线程的方式,具体方式如下: iOS和OS X线程的底层实现机制是Mach线程,我们基本不会处理线程到这个级别,一般应用中可以使用的线程管理技术有Cocoa threads,POSIX threads,Mulitprocessing Services,通过我们选择实战的方式就是Cocoa threads。 iOS和OS X中的应用可以是单线程也可以是多线程的,iOS的应用相当于一个PC上常说的进程,可以扩展子线程,扩展出来的子线程拥有可执行的栈和运行时调度在内存中。线程可以与其他线程或者进程之间通信,一般都是通过I/O读写操作或者其他你需要的方式。同一个应用中的线程拥有同样的虚拟内存空间和访问应用程序进程的权利,简单理解可以理解为在方法中可以访问全局变量。网上很多文章都讨论多线程,不过很少说一些具体线程的分配的空间,一下也是本人从苹果官网找的一张关于线程空间分配的图片: 创建底层线程是相对简单的,不过一个必要的条件就是必须有一个函数或方法作为线程的主要入口点,这样我们就可以简单的实例化一个NSThread线程来展示一下效果,NSThread有两种实例方法: 1 2 3 4 5 NSThread *myThread = [[ NSThread alloc] initWithTarget: self selector: @selector (methodTask) object: nil ]; [ NSThread detachNewThreadSelector: @selector (methodDetachTask) toTarget: self withObject: nil ]; 调用方法: 1 2 3 4 5 6 -( void )methodTask{ NSLog (@ "NSTread线程的调用" ); } -( void )methodDetachTask{ NSLog (@ "Detach线程的调用" ); } 参数解释: selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。target :selector消息发送的对象argument:传输给target的唯一参数,也可以是nil; 如果你当前主线程正在运行,你想发送消息给主线程,可以通过performSelectorOnMainThread执行: 1 [ self performSelectorOnMainThread: @selector (mainTask) withObject: nil waitUntilDone: YES ]; 调用方法: 1 2 3 -( void )mainTask{ NSLog (@ "performSelectorOnMainThread线程的调用" ); } 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4282754.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS开发-单例模式

单例模式是一种非常常见的设计模式,之前文章中UIApplication就是一种典型的单例模式,单例理解起来叶很简单,就不是不管如果访问始终只有一个实例化对象,定义全局共享的变量,如果对象是空则初始化一个对象,如果对象已经存在则使用已经实例化的对象。单例设计模式的作用是使得这个类的一个对象成为系统中的唯一实例,因此需要用一种唯一的方法去创建这个对象并返回这个对象的地址。下面有一张苹果官网的图片可以参考一下: 定义一个Food类,大家共享同一个食物,定义一个静态变量,一个实例方法: 1 2 3 4 5 6 7 8 static Food *sharedFoodObj= nil ; +(Food *)sharedFood{ if (!sharedFoodObj) { sharedFoodObj=[[Food alloc]init]; } return sharedFoodObj; } 执行以下代码,最后发现两个实例对象food和foodNext地址是一样的: 1 2 3 Food *food=[Food sharedFood]; Food *foodNext=[Food sharedFood]; NSLog (@ "共享地址:%p-共享地址:%p" ,food,foodNext); 如果每次都遵守规则调用sharedFood方法,单例模式算是完成了,但是对象是可以实例化的,看一段下面的代码: 1 2 3 Food *food=[Food sharedFood]; Food *foodInit=[[Food alloc]init]; NSLog (@ "共享地址:%p-实例地址:%p" ,food,foodInit); food和foodInit的地址是不一样,这个时候我们需要动手改造以下改成的方法,让实例化对象的出来的地址也是一样的,这个时候需要重写allocWithZone方法: 1 2 3 4 5 6 7 8 9 10 +(Food *)sharedFood{ if (!sharedFoodObj) { sharedFoodObj=[[ super allocWithZone: NULL ]init]; } return sharedFoodObj; } +(instancetype)allocWithZone:( struct _NSZone *)zone{ return [ self sharedFood]; } 如果对象拷贝的时候也需要是同一对象的话,可以加一个方法: 1 2 3 +( id )copyWithZone:( struct _NSZone *)zone{ return [ self sharedFood]; } 如果为了确保多线程情况下,仍然确保实体的唯一性,这个时候可以加上@synchronized,@synchronized的作用是创建一个互斥锁,保证此时没有其它线程对self对象进行修改。这个是objective-c的一个锁定令牌,防止self对象在同一时间内被其它线程访问,起到线程的保护作用。单例模式或者操作类的static变量中使用比较多。当两个并发线程访问同一个对象@synchronized(self)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。 1 2 3 4 5 6 7 8 +(Food *)sharedFood{ @synchronized ( self ){ if (!sharedFoodObj) { sharedFoodObj=[[Food alloc]init]; } } return sharedFoodObj; } 苹果Mac OS 10.6和iOS4.0后引入了GCD,利用GCD(Grand Central Dispatch)和ARC(Automatic Reference Counting)实现单例,这个时候我们可以通过dispatch_once简单的实现,代码如下: 1 2 3 4 5 6 7 8 9 10 + (instancetype)sharedInstance { static Food *sharedFoodObj = nil ; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedFoodObj =[[ super allocWithZone: NULL ]init]; }); return sharedFoodObj; } Food.m中的代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 // // Food.m // Demo //http://www.cnblogs.com/xiaofeixiang // Created by keso on 15/2/8. // Copyright (c) 2015年 keso. All rights reserved. // #import "Food.h" @implementation Food static Food *sharedFoodObj= nil ; +(Food *)sharedFood{ if (!sharedFoodObj) { sharedFoodObj=[[ super allocWithZone: NULL ]init]; } return sharedFoodObj; } // +( id )copyWithZone:( struct _NSZone *)zone{ return [ self sharedFood]; } - ( id )copyWithZone:( NSZone *)zone { return self ; } + (instancetype)sharedInstance { static Food *sharedFoodObj = nil ; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedFoodObj =[[ super allocWithZone: NULL ]init]; }); return sharedFoodObj; } +(instancetype)allocWithZone:( struct _NSZone *)zone{ return [ self sharedInstance]; } @end 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4280182.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS开发-UITableView表格优化

之前的一篇文章大概讲述了一下UITableView的使用,UITableView在iOS的地位和ListView在Android中的地位基本上算是不相上下,关于ListView的优化网上的也有很多文章。UITableView苹果公司本身就已经优化了其中的功能,不管你有多少数据,每次加载的时候只是加载当前页面的数据,以免造成不必要的内存占用。一个非常常见的优化就是使用Identifier,也就是唯一标示,将页面中不用的对象放在缓存池中,如果有新的对象出现从缓存池中取出。 页面布局 页面布局还是跟上篇文章一样,一个TableView: 不过需要额外的工作的时本次暂时的是服装信息,通过弹框修改服装的价格,需要新建一个服装类,实现UIAlertViewDelegate协议,头文件中的声明: 1 2 3 @interface ViewController : UIViewController <UITableViewDataSource,UITableViewDelegate,UIAlertViewDelegate> @property (weak, nonatomic ) IBOutlet UITableView *tableView; @end 服装类的定义: 1 2 3 4 5 6 7 8 9 @interface Dress : NSObject @property (strong, nonatomic ) NSString *dressName; @property (strong, nonatomic ) NSString *dressDetial; @property (strong, nonatomic ) NSString *dressImage; @end 优化与实现 优化之前先实现一些必要的功能,以及一些方法的使用,上篇文章只是涉及了其中的一部分,为了更好的理解,可以先看下实现的效果: 定义存储数据的数组: 1 2 3 4 5 6 7 @interface ViewController () { NSArray *imageArr; NSArray *dressArr; NSMutableArray *dressList; } @end 初始化数据: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - ( void )viewDidLoad { [ super viewDidLoad]; // Do any additional setup after loading the view. imageArr=[[ NSArray alloc]initWithObjects:@ "dress1.jpeg" ,@ "dress2.jpg" ,@ "dress3.jpg" , nil ]; dressArr=[[ NSArray alloc]initWithObjects:@ "七匹狼" ,@ "森马" ,@ "杰克琼斯" ,@ "美特斯邦威" ,@ "以纯" ,@ "真维斯" ,@ "海南之家" , nil ]; dressList=[ NSMutableArray arrayWithCapacity:30]; for ( NSInteger i=0; i<30; i++) { Dress *dress=[[Dress alloc]init]; NSInteger imageRandom=arc4random_uniform(3); NSInteger dressRandom=arc4random_uniform(7); NSInteger price=arc4random_uniform(1000)+100; dress.dressImage=imageArr[imageRandom]; dress.dressName=dressArr[dressRandom]; dress.dressDetial=[ NSString stringWithFormat:@ "促销价:%ld" ,( long )price]; [dressList addObject:dress]; } } 设置行数: 1 2 3 - ( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section{ return [dressList count]; } 设置分组: 1 2 3 - ( NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } 设置单元格内容,通过reuseIdentifier设置重用的单元格,dequeueReusableCellWithIdentifier取出可以重用的单元格: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath{ static NSString *flag=@ "cacheCell" ; //生成唯一的标记 UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:flag]; if (cell== nil ) { //设置需要显示详情的样式 cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:flag]; } Dress *dress=dressList[indexPath.row]; UIImage *image=[UIImage imageNamed:dress.dressImage]; [cell.imageView setImage:image]; [cell.imageView setFrame:CGRectMake(0, 0, 80, 50)]; [cell.textLabel setText:dress.dressName]; //设置展示小箭头 [cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator]; //设置Tag // [cell setTag:indexPath.row]; [cell.detailTextLabel setText:dress.dressDetial]; NSLog (@ "获取更新之后的行:%ld" ,indexPath.row); return cell; } 选中行之后的弹框设置: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - ( void )tableView:(UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath{ UIAlertView *alterView=[[UIAlertView alloc] initWithTitle:@ "服装价格:" message: nil delegate: self cancelButtonTitle:@ "取消" otherButtonTitles:@ "修改" , nil ]; [alterView setAlertViewStyle:UIAlertViewStylePlainTextInput]; //选中的Cell UITableViewCell *cell=[tableView cellForRowAtIndexPath:indexPath]; UITextField *textField=[alterView textFieldAtIndex:0]; //设置修改的服装信息 [textField setText:cell.detailTextLabel.text]; [textField setTag:indexPath.row]; [alterView show]; } UIAlterView中的点击事件: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - ( void )alertView:(UIAlertView *)alertView clickedButtonAtIndex:( NSInteger )buttonIndex{ if (buttonIndex==1) { UITextField *textField=[alertView textFieldAtIndex:0]; NSArray *selectedRow=[ self .tableView indexPathsForSelectedRows]; NSIndexPath *indexPath=selectedRow[0]; Dress *dress=dressList[indexPath.row]; dress.dressDetial=textField.text; NSLog (@ "%@---%ld" ,textField.text,( long )indexPath.row); [ self .tableView reloadRowsAtIndexPaths:selectedRow withRowAnimation:UITableViewRowAnimationRight]; } } 设置行高: 1 2 3 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:( NSIndexPath *)indexPath{ return 50; } 关于UITable的优化: 1.最常用的就是不重复生成单元格,很常见,很实用; 2.使用不透明的视图可以提高渲染速度,xCode中默认TableCell的背景就是不透明的; 3.如果有必要减少视图中的条目,本文中设置textLabel,detialTextLabel,imageView,accessoryType; 4.更新条目的时候不要整体更新,更新选中的即可,建议reloadRowsAtIndexPaths,而不是使用reloadData; 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4248066.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS开发-数据存储NSCoder

软件中永远绕不开的一个问题就是数据存储的问题,PC的时候一般都是选择在数据库中存储,iOS如果是和后端配合的话,那么不需要考虑数据存储的这个问题,上次写了一下plist的存储,不过数据都是存储一些简单的键值对对象。本次需要将一些自己定义的类型存储在plist比如说图片,这个时候可以利用NSCoding协议,将数据地以类似档案的形式存储到plist文件中,然后从plist的文件中读取数据,使用协议的时候这个时候就会用到了NSCoder,如果对存档和解压没有概念的话,可以简单的理解为数据的序列化与反序列化。 基础概念 NSCoding是一个protocol. 如果实现了NSCoding,需要实现其中的两个方法: 1 2 - ( void )encodeWithCoder:( NSCoder *)aCoder; - ( id )initWithCoder:( NSCoder *)aDecoder; // NS_DESIGNATED_INITIALIZER 方法中的主要的参数就是NSCoder,它是archivie字节流的抽象类.可以将数据写入一个coder,也可以从coder中读取我们写入的数据.NSCoder是一个抽象类,不能直接使用它来创建对象. 但是可以通过其子类NSKeyedUnarchiver从字节流中读取数据,NSKeyedArchiver将对象写入到字节流。本文以书籍为例: 新建一个Book类,Book.h中的代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface Book : NSObject < NSCoding > @property (strong, nonatomic ) UIImage *ConverPicture; @property (strong, nonatomic ) NSString *BookName; @property (strong, nonatomic ) NSString *Author; @property (strong, nonatomic ) NSNumber *Price; @end Book.m中实现NSCoding的两个方法,注意中UIImage的写法与其他有所不同: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @implementation Book - ( void )encodeWithCoder:( NSCoder *)aCoder{ //注意这里是存储的是JPG图片的调用 [aCoder encodeObject:UIImageJPEGRepresentation( self .ConverPicture,1.0)forKey:@ "ConverPicture" ]; [aCoder encodeObject:_BookName forKey:@ "BookName" ]; [aCoder encodeObject:_Author forKey:@ "Author" ]; [aCoder encodeObject:_Price forKey:@ "Price" ]; } - ( id )initWithCoder:( NSCoder *)aDecoder{ self .ConverPicture=[UIImage imageWithData:[aDecoder decodeObjectForKey:@ "ConverPicture" ]]; self .BookName=[aDecoder decodeObjectForKey:@ "BookName" ]; self .Author=[aDecoder decodeObjectForKey:@ "Author" ]; self .Price=[aDecoder decodeObjectForKey:@ "Price" ]; return self ; } @end Demo实现 正常的情况的不需要新建页面的,不过需要演示一下UIImage的效果,Main.storyboard中的布局: 稍微解释一下,前两个是存的单文件,后两个存的是多文件,UIImage展示存储的图片: ViewController定义字段: 1 2 3 4 5 @property (strong, nonatomic ) NSString *storagePath; @property (strong, nonatomic ) NSString *storageListPath; @property (strong, nonatomic ) NSMutableArray *bookList; 设置路径,如果不是很清晰,可参考本文之前的博客: 1 2 3 4 NSArray *codepath= NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES ); _storagePath = [codepath[0] stringByAppendingPathComponent:@ "book.plist" ]; NSLog (@ "%@" , NSHomeDirectory ()); _storageListPath = [codepath[0] stringByAppendingPathComponent:@ "booklist.plist" ]; 单个存档: 1 2 3 4 5 6 7 8 9 Book *book=[[Book alloc]init]; UIImage *image=[UIImage imageNamed:@ "Code1.jpg" ]; book.ConverPicture=image; book.BookName=@ "百年孤独" ; book.Author=@ "加西亚.马尔克斯" ; book.Price=[[ NSNumber alloc] initWithInteger:45]; if ([ NSKeyedArchiver archiveRootObject:book toFile:_storagePath]) { NSLog (@ "数据存档成功" ); } 单个解压: 1 2 3 4 5 Book *decodeBook=[ NSKeyedUnarchiver unarchiveObjectWithFile:_storagePath]; self .myImageView.image=decodeBook.ConverPicture; NSLog (@ "%@" ,decodeBook.ConverPicture); NSLog (@ "%@" ,decodeBook.BookName); NSLog (@ "解档成功" ); 多个存档: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 self .bookList=[ NSMutableArray array]; for ( NSInteger i=1; i<3; i++) { Book *book=[[Book alloc]init]; NSString *imageName=[ NSString stringWithFormat:@ "Code%ld.jpg" ,( long )i]; UIImage *image=[UIImage imageNamed:imageName]; book.ConverPicture=image; book.BookName=[ NSString stringWithFormat:@ "百年孤独%ld" ,( long )i]; book.Author=[ NSString stringWithFormat:@ "加西亚.马尔克斯%ld" ,( long )i]; book.Price=[[ NSNumber alloc] initWithInteger:45]; [ self .bookList addObject:book]; } if ([ NSKeyedArchiver archiveRootObject: self .bookList toFile:_storageListPath]) { NSLog (@ "数据存档成功" ); } 多个解档: 1 2 3 4 self .bookList=[ NSKeyedUnarchiver unarchiveObjectWithFile:_storageListPath]; Book *nextBook= self .bookList[1]; self .myImageView.image=nextBook.ConverPicture; NSLog (@ "解档成功" ); 通过代码基本上发现其实存档和解压是非常简单的一个事情,不过事实这种方式缺点还是很明显的,以这种方式保存数据只能一次性归档保存以及一次性解压。数据较少的时候如果使用感觉比较方便,数据量过多的时候如果想修改其中的某一条,解压整个数据然后归档整个数据还是比较耗时的。最终演示效果如下: 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4266156.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS开发-ScrollView图片缩放

智能手机一般常用常用的操作触摸,滑动,缩放,感觉对于生活而言就是手机在手,天下我有,看网页的时候字体太小,缩放一下,看美女的看的不爽,缩放一下,地图看的不清,缩放一下。缩放是一个很常见的操作,不论是从生活还是写程序而言,都是一个绕不开的东西,做了一个Demo,缩放一下美女,熟悉ScrollView中的常见属性的设置,开始正题吧。 常见属性 先看图,要实现的效果: 1 2 3 4 5 6 7 UIImage *image=[UIImage imageNamed:@ "girl0.jpg" ]; _imageView=[[UIImageView alloc] initWithImage:image]; [_scrollView addSubview:_imageView]; //设置ScrollView和image是一样的大小 [_scrollView setContentSize:image.size]; 可以设置ScrollView的初始位置和大小: 1 2 //CGRect枚举一个矩形,然后设置imageView的位置 [_imageView setFrame:CGRectMake(0, 0, 100, 100)]; 设置边界区域: 1 2 //设置边界区域 [_scrollView setContentInset:UIEdgeInsetsMake(20, 20.0, 20.0, 20.0)]; 上下左右移动调用哪个同意IBAction,通过Tag区分(之前文章有介绍),移动就是控制坐标,IOS中左上角是0,X轴向右自增,Y轴向下自增: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 UIButton *button=(UIButton *)sender; CGPoint currentPoint= self .scrollView.contentOffset; switch (button.tag) { case 0: currentPoint.y-=50; break ; case 1: currentPoint.y+=50; break ; case 2: currentPoint.x-=50; break ; case 3: currentPoint.x+=50; break ; default : break ; } //横轴的边界值 if (currentPoint.x<0) { currentPoint.x=0; } else if (currentPoint.x>_scrollView.contentSize.width-_scrollView.bounds.size.width){ currentPoint.x=_scrollView.contentSize.width-_scrollView.bounds.size.width; } //纵轴的边界值 if (currentPoint.y<0) { currentPoint.y=0; } else if (currentPoint.y>_scrollView.contentSize.height-_scrollView.bounds.size.height){ currentPoint.y=_scrollView.contentSize.height-_scrollView.bounds.size.height; } //动画效果 [ self .scrollView setContentOffset:currentPoint animated: YES ]; 动画效果可以通过block设置: 1 2 3 4 [UIView animateWithDuration:0.3f animations: ^{ [ self .scrollView setContentOffset:currentPoint]; }]; 缩放 缩放之前需要涉及到一个东西就是控制器需要遵守UIScrollViewDelegate协议,然后实现协议中方法,应用场景中如果我们在对ScrollView中图片进行缩放,将消息通知给UIScrollViewDelegate,最终将事件实现委托给是实现方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // // ViewController.h // ScrollView // http://www.cnblogs.com/xiaofeixiang // Created by keso on 15/1/20. // Copyright (c) 2015年 keso. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController <UIScrollViewDelegate> @property (weak, nonatomic ) IBOutlet UIScrollView *scrollView; @end 设置一下最大和最小缩放比例,设置委托: 1 2 3 [_scrollView setMinimumZoomScale:0.3]; [_scrollView setMaximumZoomScale:1.8]; [_scrollView setDelegate: self ]; 实现一个返回的图像,如果不是实现,没有效果: 1 2 3 4 //缩放过程中的图像 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{ return _imageView; } 有的时候如果可能有业务需要会需要一个缩放结束的方法: 1 2 3 4 ////缩放结束 - ( void )scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale{ NSLog (@ "缩放比例:%f" ,scale); } 还有一个不常用的,缩放中的方法: 1 2 3 4 //缩放中 - ( void )scrollViewDidZoom:(UIScrollView *)scrollView{ NSLog (@ "缩放中的调用~" ); } 最终效果: 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4240324.html,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册