叶焕文

技术博客


  • 首页

  • 归档

  • 分类

  • 标签

  • 搜索
close

设置UIActivityViewController分享的开始和结束回调

发表于 2017-01-10   |   分类于 Swift   |  

UIActivityViewController 可以用来做社交化分享,系统内置了许多服务,例如国内的WeChat、QQ、Weibo,国外的Facebook、Twitter等。采用这种分享方式,很容易就可以提供社交化分享功能,而且不需要去各个社交化平台申请 Key 和集成 SDK。

简单的使用

1
2
3
4
let text = "Google"
let url = NSURL(string: "https://www.google.com")
let activityViewController: UIActivityViewController = UIActivityViewController(activityItems: [text, url], applicationActivities: nil)
self.present(activityViewController, animated: true, completion: nil)

设置分享的开始回调

如果要为不同平台提供不同的分享内容,可以通过继承 UIActivityItemProvider 并且实现必要的协议方法:

1
2
3
4
5
6
7
8
9
10
override func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivityType) -> Any? {
print("=====share url start=====")
if activityType.rawValue == "com.tencent.xin.sharetimeline" {// WeChat
return NSURL(string: "https://weixin.qq.com")
}
let shareUrl = NSURL(string: "https://www.google.com")
return shareUrl
}

设置分享的结束回调

1
2
3
activityViewController.completionWithItemsHandler = { (activityType, completed, returnedItems, activityError) in
print("=====share \(activityType) end=====")
}

具体的使用

1
2
3
4
5
6
let url = UrlActivityItemProvider(placeholderItem: "placeholder")
let activityViewController: UIActivityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
activityViewController.completionWithItemsHandler = { (activityType, completed, returnedItems, activityError) in
print("=====share \(activityType) end=====")
}
self.present(activityViewController, animated: true, completion: nil)

如果需要分享除了url之外的内容,可以继续通过继承 UIActivityItemProvider 并且实现必要的协议方法,返回需要的数据类型,例如 String、Image等,每一个子类处理一种类型的数据,具体见 Demo。

遇到的问题

WeChat 必须提供 URL 分享内容,否则会报错“抱歉,暂时不支持此类型内容的分享”。

Demo地址: Setup UIActivityViewController share start and end callback

使用Vapor构建Web app并且部署在Heroku

发表于 2016-11-01   |  

Vapor,一个使用Swift进行Web服务器开发的框架,用法和Node.js的Web框架Express类似。

参考教程

  • Building Your First Web App in Swift Using Vapor(中文翻译)

安装Vapor

  • Vapor安装文档

部署Heroku

  • 使用Heroku Vapor 模板在Heroku创建App

利用 NSProxy 实现弱引用和延迟初始化

发表于 2016-10-18   |   分类于 Objective-C   |  

NSProxy 作为 Objective-C 的一个根类,本身只是提供了少量的几个方法和实现了 NSObject 协议的方法,很多方法的调用都找不到实现,从而触发消息转发的动作,因此适合作为消息转发的代理类。利用 NSProxy 适合做消息转发的特性,可以实现对象之间的弱引用和对象的延迟初始化。

实现弱引用(Weak Reference)

使用场景:在 View Controller 里面使用 NSTimer 每隔一定时间执行指定事件,由于 RunLoop 强引用 NSTimer,而 NSTimer 通过 Target 强引用 View Controller,导致 View Controller 释放不了,造成内存泄露。

1
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:[[WeakProxy alloc] initWithTarget:self] selector:@selector(timerFire:) userInfo:nil repeats:YES];

这样子就可以打破 RunLoop 和 View Controller 之间的强引用了。

具体实现:

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
#import <Foundation/Foundation.h>
@interface WeakProxy : NSProxy
- (instancetype)initWithTarget:(id)target;
@end
@implementation WeakProxy {
__weak id _target;
}
- (instancetype)initWithTarget:(id)target {
_target = target;
return self;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
return [_target methodSignatureForSelector:sel];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL sel = invocation.selector;
if ([_target respondsToSelector:sel]) {
[invocation invokeWithTarget:_target];
}
}
- (BOOL)respondsToSelector:(SEL)aSelector {
return [_target respondsToSelector:aSelector];
}
@end

实现延迟初始化(Lazy Initialization)

使用场景:

  • 第一种情况,在 [SomeClass lazy] 之后调用 doSomthing,首先进入 forwardingTargetForSelector,_object 为 nil 并且不是 init 开头的方法的时候会调用 init 初始化对象,然后将消息转发给代理对象 _object;
  • 第二种情况,在 [SomeClass lazy] 之后调用 initWithXXX:,首先进入 forwardingTargetForSelector 返回 nil,然后进入 methodSignatureForSelector: 和 forwardInvocation: 保存自定义初始化方法的调用,最后调用 doSomthing,进入 forwardingTargetForSelector,_object 为 nil 并且不是 init 开头的方法的时候会调用自定义初始化方法,然后将消息转发给代理对象 _object;
1
2
3
4
5
SomeClass *object = [SomeClass lazy];
// other thing ...
[object doSomething];// 在这里,object 才会调用初始化方法,然后调用 doSomething

具体实现(代码来源:Lazy Initialization for Objective-C):

LazyInitialization.h

1
2
3
4
5
#import <Foundation/Foundation.h>
@interface NSObject (LazyInitialization)
+ (instancetype)lazy;
@end

LazyInitialization.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
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#import "LazyInitialization.h"
@interface LazyProxy : NSProxy
- (instancetype)initWithClass:(Class)class;
@end
@implementation NSObject (LazyInitialization)
+ (instancetype)lazy {
return (id)[[LazyProxy alloc] initWithClass:[self class]];
}
@end
@implementation LazyProxy {
id _object;// 代理对象
Class _objectClass;// 代理类
NSInvocation *_initInvocation;// 自定义 init 调用
}
- (instancetype)initWithClass:(Class)cls {
_objectClass = cls;
return self;
}
- (void)instantiateObject {
_object = [_objectClass alloc];
if (_initInvocation == nil) {// 允许一些类 [SomeClass lazy] (没有调用 init)
_object = [_object init];
} else {// 调用自定义 init 方法
[_initInvocation invokeWithTarget:_object];
[_initInvocation getReturnValue:&_object];
_initInvocation = nil;
}
}
- (id)forwardingTargetForSelector:(SEL)selector {
if (_object == nil) {// _object 没有初始化
if (![NSStringFromSelector(selector) hasPrefix:@"init"]) {// 调用 init 开头之外的方法前进行 _object 初始化
[self instantiateObject];
}
}
return _object;// 将消息转发给 _object
}
// 调用自定义 init 方法会进入这个方法
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
NSMethodSignature *signature = [_objectClass instanceMethodSignatureForSelector:selector];
return signature;
}
// 保存自定义 init 方法的调用
- (void)forwardInvocation:(NSInvocation *)invocation {
_initInvocation = invocation;
}
//----------------------------------------------------------------------------
// 手工转发 NSProxy 提供的实现
//----------------------------------------------------------------------------
- (Class)class {
if (_object == nil) {
[self instantiateObject];
}
return [_object class];
}
- (Class)superclass {
if (_object == nil) {
[self instantiateObject];
}
return [_object superclass];
}
- (BOOL)conformsToProtocol:(Protocol *)aProtocol {
if (self->_object == nil) {
[self instantiateObject];
}
return [self->_object conformsToProtocol:aProtocol];
}
- (NSString *)description {
if (self->_object == nil) {
[self instantiateObject];
}
return [self->_object description];
}
- (NSUInteger)hash {
if (self->_object == nil) {
[self instantiateObject];
}
return [self->_object hash];
}
- (BOOL)isEqual:(id)obj {
if (self->_object == nil) {
[self instantiateObject];
}
return [self->_object isEqual:obj];
}
- (BOOL)isKindOfClass:(Class)aClass {
if (self->_object == nil) {
[self instantiateObject];
}
return [self->_object isKindOfClass:aClass];
}
- (BOOL)isMemberOfClass:(Class)aClass {
if (self->_object == nil) {
[self instantiateObject];
}
return [self->_object isMemberOfClass:aClass];
}
- (BOOL)respondsToSelector:(SEL)selector {
if (self->_object == nil) {
[self instantiateObject];
}
return [self->_object respondsToSelector:selector];
}
@end

使用 Hexo 搭建博客并且部署到 Heroku

发表于 2016-09-13   |   分类于 Tutorial   |  

Hexo 基于 Node.js ,运行速度快,支持 Markdown ,支持插件扩展,可以方便地部署到 Heroku 。

  • 搭建参考:Hexo 文档
  • 部署参考:Heroku 文档

快速开始

如果电脑已经具备安装条件,可以使用以下命令快速安装并且通过本地地址访问博客。

1
2
3
4
5
$ npm install hexo-cli -g
$ hexo init blog
$ cd blog
$ npm install
$ hexo server

安装前提

安装 Hexo 之前需要安装 Node.js 和 Git 。如果是 Mac 用户,还需要到 App Store 安装 Xcode,安装完毕打开 Xcode 并且去到 Preferences -> Download -> Command Line Tools -> Install 位置安装 command line tools 。

安装

首先使用命令安装 Hexo :

1
$ npm install hexo-cli -g

配置

接着创建一个新的博客目录:

1
2
3
$ hexo init blog
$ cd blog
$ npm install

运行以上命令之后,生成以下的目录结构:

1
2
3
4
5
6
7
8
.
├── _config.yml
├── package.json
├── scaffolds
├── source
| ├── _drafts
| └── _posts
└── themes
  • _config.yml 配置文件
  • package.json 项目配置信息和依赖模块
  • scaffolds 文章模板
  • source 文章源文件
  • themes 主题文件

部署

  • 登录 Heroku
  • 创建新应用
  • 在 Settings -> Info 里面找到 Git URL ,就是下面将要用到的 repository url
  • 安装 hexo-deployer-heroku
1
$ npm install hexo-deployer-heroku --save
  • 修改 _config.yml 配置文件,将 repository url 替换为上面说到的 Git URL:
1
2
3
deploy:
type: heroku
repo: <repository url>

写博客

  • 创建文章:
1
$ hexo new "New Post"
  • 本地运行:
1
$ hexo server
  • 生成静态文件:
1
$ hexo generate
  • 部署到 Hero:
1
$ hexo deploy

Hello World

发表于 2016-09-13   |  

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

叶焕文

叶焕文

5 日志
3 分类
3 标签
© 2017 叶焕文
由 Hexo 强力驱动
主题 - NexT.Muse