PART 2

自定义UITableViewCell的编辑按钮

当我们将QQ中的某条消息向左滑动时,会发现一些编辑按钮,诸如置顶、标记为已读、删除之类的。但是在iOS中,默认UITableViewCell的左滑的编辑行为就只有删除这一项,所以我们想要实现这个编辑功能可能还需要费一些功夫。不过这一切在iOS8后就迎来了终结,UIKit的API已经支持自定义UITableViewCell的编辑按钮,我们可以在UITableViewDelegate找到它:

- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;

UITableViewRowAction就是我们需要操作的类,关于它的接口,大致是这样:

NS_CLASS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED 
@interface UITableViewRowAction : NSObject <NSCopying>

+ (instancetype)rowActionWithStyle:(UITableViewRowActionStyle)style title:(nullable NSString *)title handler:(void (^)(UITableViewRowAction *action, NSIndexPath *indexPath))handler;

@property (nonatomic, readonly) UITableViewRowActionStyle style;
@property (nonatomic, copy, nullable) NSString *title;
@property (nonatomic, copy, nullable) UIColor *backgroundColor; // default background color is dependent on style
@property (nonatomic, copy, nullable) UIVisualEffect* backgroundEffect;

@end

所以我们想添加一些编辑按钮就很容易了:

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"删除" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        NSLog(@"点击了删除");
    }];
    //deleteAction.backgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];

    UITableViewRowAction *topAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"置顶" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
        NSLog(@"点击了置顶");
    }];
    topAction.backgroundColor = [UIColor orangeColor];

    return @[deleteAction, topAction];
}

当然我们需要将UITableViewCell的编辑功能开启:

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

}

改变导航栏的外观

就像标题说的这样,我们并不通过继承来自定义导航栏,而仅仅是以系统给我们提供API来达到更改导航栏外观的目的,并且它们几乎能满足我们所有的需求了,所以何必舍近求远呢?

标题颜色

[[UINavigationBar appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor]}];// the other title text attributes follow the same principle

// or

self.navigationController.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName: [UIColor whiteColor]}

返回按钮颜色(同时作用于图片)

[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];

//...

背景颜色或图片

[[UINavigationBar appearance] setBarTintColor:[UIColor colorWithRed:20 / 255.0f green:155 / 255.0f blue:213 / 255.0f alpha:1.0f]];

[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"nav2"] forBarMetrics:UIBarMetricsDefault];

//....

返回按钮

//action scope just for current view controller.if you want to leave out return title, please let title nil
UIBarButtonItem *returnItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = returnItem;

//set back button background image
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:[UIImage imageNamed:@"nav2"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

标题视图

设置self.navigationController.navigationItem.titleView,笔者网上搜索的教程皆是使用此方法改变标题视图,但笔者测试发现并无任何效果。请知道原因的朋友能在评论区给出答案,谢谢!

关于API的一些说明

从上面的代码中可以看到一些外观的设定可以使用两种方式来完成,关于appearance可能需要啰嗦几句。

这个方法是定义在UIAppearance协议中的,一如Apple的命名风格——见文知义,它表示的是一个外观协议,想要改变外观就需要实现此协议。比如UIView等均是实现了此协议,而依次为媒介我们就可以给一个具体的对象发送一些更改外观的消息来完成相应的改变。

我们可能之前使用过下面这样的代码来改变导航栏的背景:

self.navigationController.navigationBar.backgroundColor = [UIColor redColor];

它所带来的效果就像是“蒙尘”的颜色:

这里写图片描述

不过当我们使用Xcode的Debug View Hierarchy就可以知道事情的原委了,也就是运行程序后点击这个:

这里写图片描述

在视图层级展示窗口中可以看到这个:

这里写图片描述

在左边的视图层级列表中是如下的样子:

这里写图片描述

以上大致可这样描述:

UINavigationBar的上面添加了一个叫做_UINavigationBarBackgroundUIImageView,它覆盖了整个导航栏。因为它是私有的成员变量,不能直接访问。而当改变导航栏的背景色或者设置自定义的图片时,本质上就是对这个UIImageView做出相应的处理。

Swift3中的权限访问控制符

private:其修饰的函数或属性只能在当前类里访问;

fileprivate:其修饰的函数或属性只能在当前Swift源文件里访问,Swift3新增;

internal:默认修饰符,其修饰的函数或属性在源代码所属的整个module(模块)都可以访问;

public:其修饰的函数或属性能被所有module访问,但只能在当前的module内被重载和继承;

open:其修饰的函数或属性能被所有module访问,包括重载和继承,Swift3新增。

权限高低排序:

open > public > internal > fileprivate > private

TCP中的三次握手与四次挥手

用一个已有的形象的例子来阐述三次握手(实际作用是建立TCP链路):

  1. 小明(Client)喜欢上了(要发数据给)一个女孩小丽(Server);

  2. 按照惯有的套路,他就想约小丽在某时某地(数据)吃饭;

  3. 但是小明并不确定小丽是否会答应他,所以他就忐忑地发了一条消息给小丽说:“我能约你出去吃饭吗?”(第一次握手:ClientServer发送一条信息表达想要发送数据的愿望,即连接请求报文SYN。);

  4. 事实上小丽对小明早已芳心暗许,因此当看到这条消息的时候很开心,毫不犹豫的就答应了小明的约会(Server能够完成Client服务请求);

  5. 这时,她就需要回信息给小明表明自己愿意的态度,同时也说明了自己已经收到了该信息(第二次握手:Server回复确认(ACK + SYN)报文,并为这次连接分配资源(小丽要陪着小明吃饭));

  6. 小明收到消息时那是相当的高兴,但是想到请心仪的女生吃饭绝对要找好地方,免得唐突了佳人;

  7. 于是小明可能就会回复这样一条消息给小丽:“那真是太好了,到时我给你打电话!^_^”(第三次握手:Client发送确认(ACK)信息给Server作为响应。至此ClientServer之间就建立起了可靠的TCP连接);

  8. 最后,小明在深思熟虑之后只需要把时间以及地点(数据)告诉(发送给)小丽,两人就可以开启浪漫的Table For Two(二人约会)。

且不说这两人在这一天中交流沟通了什么(收发数据),也不必说这两人彼此间又增加了哪些新的印象(存储数据),就简单说说两人在愉快之后的分别过程。按照上面的例子继续说明断开连接的四次挥手:

1.晚上两人在一家餐厅吃着饭。小明看天色已经很晚了,便想着该送小丽回家了,就对小丽说:“你看已经这么晚了,等你吃完饭我送你回家好吗?”(第一次挥手:Client发起中断连接的请求,即FIN报文,表明Client已经没有数据要发给Server了。);

2 . 小丽经过一天的了解发现小明正是自己理想中的男友,理所当然的就答应了他。但是为了能有更多两人独处的时间,所以小丽吃饭就吃得很慢也很优雅。小明也乐意等待一段时间,毕竟现在彼此都知道自己不是在单恋(第二次挥手:Server告诉Client,你的请求我已经收到,但是我还没准备好(还有Client请求的数据没有发完),请继续等待我的消息。这个时候Client就进入了FIN_WAIT状态,继续等待ServerFIN报文。);

3.最终小丽吃完了晚餐,就温柔的告诉小明:“我们走吧!”(第三次挥手:Server发送完数据,向Client发送FIN报文,表明“我”已经发完数据,准备好关闭连接);

4.小明结账,两人离开餐厅。走啊走啊走,及至小丽家楼下,两人温情告别,小明目送小丽上楼。过一会儿后,小明知道两人的今天的约会到此就结束了,但他不确定小丽是否已经到家中,便打了一个电话询问:“到了吗?”(第四次挥手:Client收到Server的FIN报文后,但是Client并不相信网络,怕Server不知道要关闭连接,随即发送确认报文(ACK)给Server,并进入TIME_WAIT状态。Server收到ACK就知道可以断开连接了,于是断开连接。Client在2MSL后依然没有收到回复,则证明Server已经关闭,那Client也随即关闭。至此,TCP连接断开。);

5.于现实中,小丽接到电话后,就跑到窗户旁,打开窗户,向楼下的小明招手。小明也招手回应。“明天见!”,两人告别之后,这一天两人的共处时间(ClientServer的一次通信)结束。

参考:TCP协议中的三次握手和四次挥手(图解)

最大子序列的最佳算法

越来越有感触的是美好的生活离不开革命老前辈的血汗啊!在计算机的世界里同样不会例外。当需要某个模块功能又没有足够的时间去琢磨如何“造轮子”时,github简直就是“奉命于危难之间,受任于败军之际”的孔明。当拿到笔试题时,看到某题的最优算法已经成竹在胸时的那份窃喜,离不开的是巨人的肩膀。也所幸有他们的存在,才能在文章中看到最好或最优相关的字眼(ps:指到目前为止),不然笔者的标题岂敢“包养”最佳二字!

如果让我来“操键盘”解决这个问题,不假思索地就写了下面这样的程式:

int maxSubSumWithForCycle(const vector<int> &a) {
    int maxSum = 0;
    for (int i = 0; i < a.size(); i ++) {
        int thisSum = 0;
        for (int j = i; j < a.size(); j ++) {
            thisSum += a[j];

            if (thisSum > maxSum) {
                maxSum = thisSum;
            }
        }
    }

    return maxSum;
}

然后我就很不幸地被告知你设计的程序运行时间T(N) = O(N ^ 2),然后就没有然后了……

一个优秀算法之所以能够经得起时间的考验是因为它的诞生就是经过多番的磨砺的,要是你在第一反应就能以最优方案解决问题,那么只有两种情况:你是天才或你想多了。天才有但极少,所以才有一大帮科学家去专研算法,完后,我们就坐着等“吃”(理解算法的思路)。就像下面这个解决最大子序列的高效算法一样:

int bestMethodToGetMaxSubSum(const vector<int> &a) {
    int thisSum = 0, maxSum = 0;
    for (int i = 0; i < a.size(); i ++) {
        thisSum += a[i];
        if (thisSum > maxSum) {
            maxSum = thisSum;
        } else if (thisSum < 0) {
            thisSum = 0;
        }
    }

    return maxSum;
}

无疑,它的运行时间T(N) = O(N),然后就把它记在脑袋里,下次要是在笔试题里碰到了就可以“抄”了,因为经典的算法是需要理解并记忆滴!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值