热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一个java程序员自学IOS开发之路(五)

20151024Day23我插入移动硬盘后,电脑右上角老是出现一个齿轮转啊转,然后弹出对话框说有新文件加入电脑什么文件夹,要不要去看,关还关不掉,于是乎,昨晚脑袋一抽就把那个弹出来

2015/10/24

Day 23

我插入移动硬盘后,电脑右上角老是出现一个齿轮转啊转,然后弹出对话框说有新文件加入电脑什么文件夹,要不要去看,关还关不掉,于是乎,昨晚脑袋一抽就把那个弹出来的文件夹移入废纸篓,然后发现不能这么干,就从废纸篓恢复,然而Finder就卡死了= =不管怎样都没响应,我烦的不行就强制按电源键重启电脑了(用Win系统的坏习惯,有事没事重启一下),然后!!!输入密码登陆,如下图:

 技术分享

然后就重启了= =,无限循环进不了系统,各种方法无果后,没办法去了售后店。解决方法,重装系统,花费300大洋,我去!真特么贵,唉~谁叫自己作呢,弄好后回家第一件事就是自制U盘启动盘。

其实很简单,先下好镜像文件,然后插入U盘,格式化它,再可以给它分区,这个随意我就没分,最后终端输入命令,等着就行了。

命令如下

安装包名称:Install OS X El Capitan.app

制作U盘启动盘指令

sudo /Applications/Install\ OS\ X\ El\ Capitan.app/Contents/Resources/createinstallmedia --volume /Volumes/u盘 --applicationpath /Applications/Install\ OS\ X\ El\ Capitan.app --nointeraction

第二件事就是开启TimeMachine备份。

之前写的代码都没了= =,唉,不说这事了,都是泪%>_<%

 

2015/10/25

Day 24

调试新系统,调整心情,再一次安装Xcode,继续学习啦~

今天开始学习UITableView

UITableView

在众多app中,能看到各式各样的表格数据,如下

 技术分享

iOS中,要实现表格数据展示,最常用的做法就是使用UITableView

UITableView继承自UIScrollView,因此支持垂直滚动,而且性能极佳

UITableView的两种样式

技术分享


  1. UITableView需要一个数据源(dataSource)来显示数据

  2. UITableView会向数据源查询一共有多少行数据以及每一行显示什么数据等

  3. 没有设置数据源的UITableView只是个空壳

  4. 凡是遵守UITableViewDataSource协议的OC对象,都可以是UITableView的数据源

UITableViewDataSource协议

 技术分享

Cell简介

UITableView的每一行都是一个UITableViewCell,通过dataSource的tableView:cellForRowAtIndexPath:方法来初始化每一行

UITableViewCell内部有个默认的子视图:contentView,contentView是UITableViewCell所显示内容的父视图,可显示一些辅助指示视图。还可以通过cell的accessoryView属性来自定义辅助指示视图(比如往右边放一个开关)

UITableViewCellcontentView

contentView下默认有3个子视图

其中2个是UILabel(通过UITableViewCell的textLabel和detailTextLabel属性访问)

第3个是UIImageView(通过UITableViewCell的imageView属性访问)

UITableViewCell还有一个UITableViewCellStyle属性,用于决定使用contentView的哪些子视图,以及这些子视图在contentView中的位置

 技术分享

Cell的重用


  • iOS设备的内存有限,如果用UITableView显示成千上万条数据,就需要成千上万个UITableViewCell对象的话,那将会耗尽iOS设备的内存。要解决该问题,需要重用UITableViewCell对象

  • 重用原理:当滚动列表时,部分UITableViewCell会移出窗口,UITableView会将窗口外的UITableViewCell放入一个对象池中,等待重用。当UITableView要求dataSource返回UITableViewCell时,dataSource会先查看这个对象池,如果池中有未使用的UITableViewCell,dataSource会用新的数据配置这个UITableViewCell,然后返回给UITableView,重新显示到窗口中,从而避免创建新对象

  • 还有一个非常重要的问题:有时候需要自定义UITableViewCell(用一个子类继承UITableViewCell),而且每一行用的不一定是同一种UITableViewCell,所以一个UITableView可能拥有不同类型的UITableViewCell,对象池中也会有很多不同类型的UITableViewCell,那么UITableView在重用UITableViewCell时可能会得到错误类型的UITableViewCell

  • 解决方案:UITableViewCell有个NSString *reuseIdentifier属性,可以在初始化UITableViewCell的时候传入一个特定的字符串标识来设置reuseIdentifier(一般用UITableViewCell的类名)。当UITableView要求dataSource返回UITableViewCell时,先通过一个字符串标识到对象池中查找对应类型的UITableViewCell对象,如果有,就重用,如果没有,就传入这个字符串标识来初始化一个UITableViewCell对象

Cell的重用代码

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    // 1.定义一个cell的标识

      static NSString *yu3 = @“yu3”;

    // 2.从缓存池中取出cell

      UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:yu3];

    // 3.如果缓存池中没有cell

      if (cell == nil) {

        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:yu3];

    }

    // 4.设置cell的属性...

    

      return cell;

}

上面的写法并不好,因为数据源不需要知道cell内部的标识为什么,cell的标识cell自己最清楚,应该把创建cell的代码封装在cell里面,如下(YUCell为我自定义的cell类名)

+ (instancetype)cellWithTableView:(UITableView *)tableView{

    static NSString *yu3 = @“yu3Cell";

    YUCell *cell = [tableView dequeueReusableCellWithIdentifier:yu3];

    if (cell == nil) {

        cell = [[YUCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:yu3];

    }

    return cell;

}

这样,数据源里的方法就很简单

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    //创建cell

    YUCell *cell = [YUCell cellWithTableView:tableView];

    //设置cell的属性...

    

    return cell;

}

这样的话,如果以后cell里面的东西要变化,只需要动cell里的代码,数据源里代码不需要改变。

2015/10/26

Day 25

今天做了一个UIScrollView和UITableView综合的小项目

技术分享    技术分享

仿造团购app的界面,上面的广告可以自动翻页,滑到下面有按钮点击后加载数据

 

上面的广告,每个cell还有下面的加载更多按钮都是用xib封装的

 技术分享

技术分享

技术分享

使用xib封装一个view的步骤:

1.新建一个xib文件描述一个view的内部结构

2.新建一个自定义的类(自定义类需要继承自系统自带的view, 继承自哪个类,  取决于xib根对象的Class)

3.新建类的类名最好跟xib的文件名保持一致

4.将xib中的控件 自定义类的.m文件 进行连线

5.提供一个类方法返回一个创建好的自定义view(屏蔽从xib加载的过程)

6.提供一个模型属性让外界传递模型数据

7.重写模型属性的setter方法,在这里将模型数据展示到对应的子控件上面

代理的使用

像上面的加载更多按钮,他是在xib里面的,如果想让用户点击它加载新数据,这件事得控制器ViewController来做。可以用代理模式实现,让ViewController成为YUTgFooterView(我封装该View的类名)的代理(delegate),这样ViewController就可以监听那个按钮点击做出反应了。

使用delegate的步骤


  • 先搞清楚谁是谁的代理(delegate)

  • 定义代理协议,协议名称的命名规范:控件类名 + Delegate

  • 定义代理方法


    • 代理方法一般都定义为@optional

    • 代理方法名都以控件名开头

    • 代理方法至少有1个参数,将控件本身传递出去


技术分享 


  • 设置代理(delegate)对象  (比如myView.delegate = xxxx;)

 技术分享


  • 代理对象遵守协议

技术分享 


  • 代理对象实现协议里面该实现的方法

 技术分享


  • 在恰当的时刻调用代理对象(delegate)的代理方法,通知代理发生了什么事情(在调用之前判断代理是否实现了该代理方法)

 技术分享

 

2015/10/27

Day 26

昨天的项目中,cell是xib封装的,每个cell的内容都是类似的,高度也是一样的,这样太局限,比如微博页面,它的每个cell的内容是不一样的,这就需要用代码来自定义cell 

如图,每个cell最多可以有一个头像,一个名字,一个vip标识,一个文本,一张图片,plist文件结构如下 

技术分享  技术分享 

首先,把plist封装成模型

 技术分享

技术分享

创建自定义的cell类继承自UItableViewCell 

 技术分享

cell内部的控件属性要写在.m文件中的类扩展中 

 技术分享

实现cell的构造方法

/**

 *  构造方法(在初始化对象的时候会调用)

 *  一般在这个方法中添加需要显示的子控件

 */

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {

        UIImageView *icOnView= [[UIImageView alloc] init];

        [self.contentView addSubview:iconView];

        self.icOnView= iconView;

        UILabel *nameView = [[UILabel alloc] init];

        nameView.fOnt= YUNameFont;

        nameView.backgroundColor = [UIColor orangeColor];

        [self.contentView addSubview:nameView];

        self.nameView = nameView;

        UIImageView *vipView = [[UIImageView alloc] init];

        [self.contentView addSubview:vipView];

        self.vipView = vipView;

        UILabel *textView = [[UILabel alloc] init];

        textView.fOnt= YUTextFont;

        textView.numberOfLines = 0;//自动换行!

        textView.backgroundColor = [UIColor blueColor];

        [self.contentView addSubview:textView];

        self.textView = textView;

        UIImageView *pictureView = [[UIImageView alloc] init];

        [self.contentView addSubview:pictureView];

        self.pictureView = pictureView;

    }

    return self;

}

再重写成员属性的setter方法,里面设置控件数据

/**设置子控件的大小和数据 */

-(void)setStatus:(YUStatus *)status {

    _status = status;

    //设置数据

    [self setData];

    //设置控件大小

    [self setFrame];

}

设置的代码冗长,我把他们封装了

别忘了实现.h中声明的类方法

+ (instancetype)cellWithTableView:(UITableView *)tableView{

    static NSString *yu3 = @"statusCell";

    YUStatusCell *cell = [tableView dequeueReusableCellWithIdentifier:yu3];

    if (cell == nil) {

        cell = [[YUStatusCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:yu3];

    }

    return cell;

}

最后到控制器,先让控制器继承自UITableViewController 

 技术分享 

设置成员属性 

 技术分享

重写getter方法加载数据

- (NSArray *)statuses {

    NSMutableArray *result = [[NSMutableArray alloc] init];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];

    NSArray *dics = [NSArray arrayWithContentsOfFile:path];

    for (NSDictionary *dic in dics) {

        YUStatus *status = [YUStatus statusWithDic:dic];

        [result addObject:status];

    }

    return result;

}

最后重写数据源方法

//默认就是1,可以不写这个方法

//- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

//    return 1;

//}

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.statuses.count;

}

 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    YUStatusCell *cell = [YUStatusCell cellWithTableView:tableView];

    cell.status = self.statuses[indexPath.row];

    return cell;

}

这样运行出来是这个效果,很坑爹,因为个cell默认的高度是一样的,有个方法可以改变 

 技术分享

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //如何自定义cell高度?

    return 100;

}

这里插播一下,计算一个字符串所占的size,如图我文本的背景色

第一种方法,利用控件的一个方法

//根据内部文字以及参数中给的参考size计算自适应的size

    CGSize nameSize = [self.nameView sizeThatFits:CGSizeZero];

第二种方法,利用NSString一个类别(分类)中的方法 

//根据内部文字以及参数中给的参考的最大size计算自适应的size

    CGSize nameSize = [status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]} context:nil].size;

第一个参数:参考的最大size,这里可以规定最大宽度和高度

第二个参数:一般写NSStringDrawingUsesLineFragmentOrigin |NSStringDrawingUsesFontLeading

第三个参数:是个字典,传入字体大小

 

那么问题来了,如何计算每个cell的高度?

cell的高度是根据里面的数据决定的,数据是由模型传过来的,因此cell的高度应该由模型来计算!

解决方法:

1.提供2个模型


  • 数据模型: 存放文字数据\图片数据

  • frame模型: 存放数据模型\所有子控件的frame\cell的高度 

 技术分享

2.cell拥有一个frame模型(frame模型已经包含数据模型了)

技术分享 

3.重写frame模型属性的setter方法: 在这个方法中设置子控件的显示数据和frame

- (void)setStatus:(YUStatus *)status {

    _status = status;

    CGFloat padding = 20;

    CGFloat icOnX= padding;

    CGFloat icOnY= padding;

    CGFloat icOnW= 30;

    CGFloat icOnH= 30;

    _icOnF= CGRectMake(iconX, iconY, iconW, iconH);

    //根据内部文字以及参数中给的参考的最大size计算自适应的size

    CGSize nameSize = [status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : YUNameFont} context:nil].size;

    CGFloat nameX = CGRectGetMaxX(_iconF) + padding;

    CGFloat nameY = iconY + (iconH - nameSize.height) / 2;

    _nameF = CGRectMake(nameX, nameY, nameSize.width, nameSize.height);

    

    CGFloat vipX = nameX + nameSize.width + padding;

    CGFloat vipY = nameY;

    CGFloat vipW = 14;

    CGFloat vipH = 14;

    _vipF = CGRectMake(vipX, vipY, vipW, vipH);

    

    CGFloat textX = iconX;

    CGFloat textY = CGRectGetMaxY(_iconF) + padding;

    CGSize textSize = [status.text boundingRectWithSize:CGSizeMake(345, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName : YUTextFont} context:nil].size;

    _textF = CGRectMake(textX, textY, textSize.width, textSize.height);

    

    if (status.picture) {

        CGFloat picX = textX;

        CGFloat picY = CGRectGetMaxY(_textF) + padding;

        CGFloat picW = 200;

        CGFloat picH = 200;

        _picF = CGRectMake(picX, picY, picW, picH);

        _cellHight = CGRectGetMaxY(_picF) + padding;

    } else {

        _cellHight = CGRectGetMaxY(_textF) + padding;

    }

}

4.frame模型数据的初始化已经采取懒加载的方式(每一个cell对应的frame模型数据只加载一次)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    YUStatusCellFrame *frame = self.statusFrames[indexPath.row];

    return frame.cellHight;

}

最后这样返回每个cell的高度就可以啦

技术分享 

最后说一下弹窗事件,我做了个点击cell弹出对话框修改用户名的功能

 技术分享

iOS8以前,弹窗需要遵守协议还有实现按钮的点击处理,比较麻烦,而iOS8以后可以在一个方法里搞定,而且不用遵守协议

// cell点击事件监听

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    YUStatusCellFrame *statusFrame = self.statusFrames[indexPath.row];

    NSString *name = statusFrame.status.name;

    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"博主" message:nil preferredStyle:UIAlertControllerStyleAlert];

    [alert addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {

        textField.text = name;

    }];

    UIAlertAction *modify = [UIAlertAction actionWithTitle:@"修改" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {

        statusFrame.status.name = alert.textFields[0].text;

        //修改后计算出新的name所占frame的大小

        CGSize newSize = [statusFrame.status.name boundingRectWithSize:CGSizeMake(MAXFLOAT, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : YUTextFont} context:nil].size;

        statusFrame.nameF = CGRectMake(CGRectGetMinX(statusFrame.nameF) , CGRectGetMinY(statusFrame.nameF), newSize.width, newSize.height);

        //重新加载该行数据

        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationRight];

    }];

    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {

    }];

    [alert addAction:modify];

    [alert addAction:cancel];

    [self presentViewController:alert animated:YES completion:nil];

}


推荐阅读
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
author-avatar
手机用户2502925587
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有