IOS开发笔记(三)——视图跳转,绑定button事件,UITableView使用方法,文件浏览器demo

版权声明: https://blog.csdn.net/dickdick111/article/details/88982619

中山大学数据科学与计算机学院本科生实验报告

(2019年春季学期)

课程名称 IOS开发 任课老师 郑贵锋
年级 16 专业(方向) 软件工程(计算机应用方向)
学号 16340132 姓名 梁颖霖
电话 13680473185 Email [email protected]
开始日期 2019/3/30 完成日期 2019/4/2

一、实验题目

IOS UI编程

IOS 网络访问

IOS 本地存储

二、实现内容

  • 练习UI编程demo
  • 实现网络访问、文件访问demo
  • 总结练习过程的问题

三、实验结果

1.视图跳转三种方式

  1. [self.view addSubView:view];和[self.window addSubView:view];
    • 此方法只是把页面(view)加在当前页面(view)上,控制器(viewController)还是原来那个控制器。
    • 要想使用pushViewController和popViewController进行视图间的切换,就必须要求当前视图是个NavigationController。
  2. 有NavigationController导航栏
    • 使用[self.navigationColler pushViewController:animated:];和[self.navigationController popViewControllerAnimated:];来进行视图切换。
    • pushViewController是进入到下一个视图,popViewController是返回到上一视图。
  3. 没有NavigationController导航栏
    • 使用[self presentViewController:animated:completion:];和[self dismissViewControllerAnimated:completion:];

注意:

要想使用pushViewController和popViewController来进行视图切换,首先要确保根视图是NavigationController,不然是不可以用的。

如何让该视图或者根视图是NavigationController。

  • 自己定义个子类继承UINavigationController,然后将要展现的视图包装到这个子类中,这样就可以使NavigationController了。提供的这个方法有很好的好处,就是可以统一的控制各个视图的屏幕旋转。将一个控制器(UIViewController)包装成一个导航控制器(UINavigationController):
  • 在上部的 Editor -> Embled in -> NavigationController 选中为你的页面添加一个,此时选中的是Main.storyboard中的页面

2

这样既可以使用navigationcontroller的导航栏,使用的优点是可以自定义返回或功能,让页面显示返回键,效果如下图所示

1

2.巧妙利用宏定义显示特定代码

#if 1
    do sthA;
#endif

#if 0
	do sthB;
#endif

如上图代码可以只显示do sthA部分,而do sthB部分暂时不会显示。

注意if 0 与 if 1的相互切换

利用这个小技巧可以使代码调试更加方便,模块化编程

3.导入图片到项目

错误的做法:直接将图片拉入文件夹中,代码运行时无法显示图片

正确的做法:在上部 File -> add File -> 选择图片

只有这样才能识别到你图片的位置

3

4.绑定button点击事件

设置好button的参数,如背景大小,字体后,利用addTarger函数来为该button添加一个事件。

  • action中所填的参数就是事件执行的内容
  • forControlEvents中的是关于这个按键何时触发事件
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

// 添加事件
[button addTarget:self action:@selector(onButtonClick:) 
 				forControlEvents:UIControlEventTouchUpInside];

[self.view addSubview:button];

事件执行onButtonClick函数

- (void)onButtonClick:(UIButton*)sender {
    NSLog(@"button click");
}

然后通过button的例子类比到UISwitch,操作与button类似,触发与添加事件相同。

5.输入框TextField与TextView

  • TextField是针对一行文字输入,例如密码用户名之类的输入
  • TextView是针对多行文字输入,例如文本日记博客之类的输入

两者相同的地方在于可以设置文字的大小颜色行距之类。

TextField可以选择输入键盘的样式,是纯数字或者纯字母

TextView可以选择文本框是否可以滚动

6.UITableView相关练习

​ 在Android中,ListView中有一种机制,就是复用view来做优化。而IOS的UITableView中其实已经自我实现了这种机制,也就是将当前没有显示的Cell重新显示在将要显示的Cell的位置然后更新其内容。

​ 在UITableView内部有一个缓存池,初始化时使用initWithStyle:(UITableViewCellStyle) reuseIdentifier:(NSString *)方法指定一个可重用标识,就可以将这个cell放到缓存池。然后在使用时使用指定的标识去缓存池中取得对应的cell然后修改cell内容即可。

  • UITableViewDataSource
    • 群组个数
    • 一个群组里面有多少个item
    • 根据数据源展示界面
//有几个群组
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
    return 1;
}
//一个群组有几个item(cell)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return _persons.count;
}
//根据数据源展示界面实现
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
      Person *person=_persons[indexPath.row];
    UITableViewCell *cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
    cell.textLabel.text=[person name];
    cell.detailTextLabel.text=person.sex;
    return cell;
}
  • UITableViewDelegate处理点击事件
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
     Person *person=_persons[indexPath.row];
    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"title" message:person.age delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"ok", nil];
    [alert show];
}

实现文件浏览器应用

  • 运用IOS自带的NSFileManager来读取文件目录
  • 使用UITableView来显示目录,并处理点击跳转至下一级目录的情况
  • 点击文件可以显示文件的详情
1.定义属性

包括tableview显示组件,directoryList,fileList这两个可变数组用来装当前目录下的文件内容,分为两个section来显示,directory就是当前目录

@interface FileExploreViewController ()<UITableViewDelegate, UITableViewDataSource>

@property(nonatomic, strong) UITableView *tableView;
@property(nonatomic, strong) NSMutableArray<NSString*> *directoryList;
@property(nonatomic, strong) NSMutableArray<NSString*> *fileList;
@property(nonatomic, strong) NSString *directory;

@end
2.初始化
- (instancetype)initWithDirectory:(NSString*)directory {
    if (self = [super init]) {
        self.directory = directory;
    }
    
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    if (self.directory == nil) {
        self.directory = @"/Users/zhangtianfu";
    }
    
    self.navigationItem.title = self.directory;
    
    self.tableView = ({
        UITableView *tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
        tableView.delegate = self;
        tableView.dataSource = self;
        tableView;
    });
    [self.view addSubview:self.tableView];
    
    [self loadData];
}

3.加载数据

这里利用NSFileManager来读取文件目录,并放入可变数组中

- (void)loadData {
    NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.directory error:nil];
    
    self.directoryList = [NSMutableArray array];
    self.fileList = [NSMutableArray array];
    
    for (NSString *name in contents) {
        if ([name hasPrefix:@"."]) {
            continue;// 过滤隐藏文件
        }
        
        NSString *path = [self.directory stringByAppendingPathComponent:name];
        BOOL isDirectory = NO;
        if ([[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory]) {
            if (isDirectory) {
                [self.directoryList addObject:name];
            } else {
                [self.fileList addObject:name];
            }
        }
    }
}
4.设置UITableViewDataSource
  • 设置两个section
  • 设置每个section中的item数量
  • 设置每个item的显示

判断是目录还是文件,利用section的下标来进行判断

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    BOOL isDirectory = (section == 0);
    if (isDirectory) {
        return self.directoryList.count;
    } else {
        return self.fileList.count;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSString *cellID = [NSString stringWithFormat:@"cellID:%zd", indexPath.section];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
    if (nil == cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
    }
    
    BOOL isDirectory = (indexPath.section == 0);
    if (isDirectory) {
        cell.imageView.image = [UIImage imageNamed:@"icon_directory.jpg"];
        cell.textLabel.text = self.directoryList[indexPath.row];
        cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    } else {
        cell.textLabel.text = self.fileList[indexPath.row];
    }
    
    return cell;
}
5.处理UITableViewDelegate跳转事件
  • 对于目录,跳转至目录类
  • 对于文件,跳转至详情类

这里的跳转用到了我第一个知识点所说的navigationController,通过push与pop来处理显示页面的情况。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    
    BOOL isDirectory = (indexPath.section == 0);
    if (isDirectory) {
        NSString *path = [self.directory stringByAppendingPathComponent:self.directoryList[indexPath.row]];
        FileExploreViewController *controller = [[FileExploreViewController alloc] initWithDirectory:path];
        controller.hidesBottomBarWhenPushed = YES;
        [self.navigationController pushViewController:controller animated:YES];
    } else {
        NSString *path = [self.directory stringByAppendingPathComponent:self.fileList[indexPath.row]];
        FileInfoViewController *controller = [[FileInfoViewController alloc] initWithFilePath:path];
        UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:controller];
        [self presentViewController:navController animated:YES completion:nil];
    }
}

文件详情类与这里类似,就不重复说明。唯一的区别在于所显示的是文件里面的内容,而不是显示目录。同样是需要利用NSFileManager来进行目录读取,获取文件信息显示。

7. Objective函数表示

在Objective-C编程的方法定义的一般形式如下:

- (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgumentn:( argumentTypen )argumentNamen 
{
   body of the function
}

在Objective-C编程语言定义的方法的方法头和方法体。下面是所有部分的方法:

  • return_type 返回类型: 方法可以返回一个值。 return_type是函数返回值的数据类型。有些方法执行所需的操作,不返回值。在这种情况下,return_type关键字是void。
  • method_name 方法名称: 这是实际的方法名。方法名和参数表共同构成的方法签名。
  • argumentType 参数类型
  • argumentName 参数: 一个参数像一个占位符。当函数被调用时,你传递一个值的参数。这个值被称为实际参数或参数。参数列表是指的类型,顺序和数量的参数的方法。参数是可选的,方法可能不包含任何参数。
  • joiningArgument 链接参数: 连接的参数,使其更易于阅读和同时调用明确。
  • 方法体: 该方法的主体包含语句定义的方法用于做什么的集合。

8.读取与写入document

普通的写入包括字符串,数组之类,这里我想记录一下写入一个类对象,其中的操作包括了其他的写入或者读取。

  • 获取document的目录
  • 添加文件名在目录后面
  • 写入
    • 准备类的对象初始化,填充数据
    • 将对象转化为NSData对象
    • NSData对象写入之前的目录
  • 读取
    • 从之前的目录读取到NSData对象
    • NSData对象转为你所需要的对象

写入的代码

- (IBAction)writeCustomType:(id)sender {
    NSString *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;

    NSString *filePath = [document stringByAppendingPathComponent:@"user"];

    User *user = [[User alloc] init];
    user.userId = 123;
    user.nickname = @"Tom";
    user.isVip = YES;

    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:user requiringSecureCoding:YES error:nil];
    [data writeToFile:filePath atomically:YES];
}

读取的代码:

- (IBAction)readCustomType:(id)sender {
    NSString *document = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;

    NSString *filePath = [document stringByAppendingPathComponent:@"user"];

    NSData *data = [NSData dataWithContentsOfFile:filePath];

    NSError *error;
    User *user = [NSKeyedUnarchiver unarchivedObjectOfClass:[User class] fromData:data error:&error];
    NSLog(@"user %ld %@ %d", user.userId, user.nickname, user.isVip);
}

猜你喜欢

转载自blog.csdn.net/dickdick111/article/details/88982619
今日推荐