用 iPhone 轻松下载微博小视频

我经常喜欢看一些比较污的视频,这些视频基本上来自于微博。iPhone和Android有一个很大的不同,就是下载视频比较难。之前使用Pro recorder,但是这个APP有数量限制,一旦到了规定的数量,需要购买会员。下面和大家分享一下如何使用iPhone下载微博上面的小视频另一种方法。

下载Wordflow

打开App Store,搜索workflow,并进行下载

下载workflow插件

使用iPhone的自带浏览器Safari 打开连接 http://workflow.sspai.com/#/main/workflow ,然后找到插件,进行下载

点击获取该workflow,这个时候会询问是否打开workflow,然后选择确认。

选择get workflow 进行安装。

下载小视频准备

打开微博你想要下载的小视频,拷贝连接

返回workflow的主界面,点击刚刚下载的插件。

这个时候,复制的链接已经自动粘贴到了workflow里面。

开始下载

点击开始进行下载,这个时候会有一系列的操作自动运行。

选择Save Video进行保存操作。

查看视频

进行iPhone相册,查看下载的小视频。

workflow中文推荐站

PHP设计模式-原型模式

原型模式

原型设计模式是通过使用一种克隆技术复制实例化的对象。新对象是通过复制原型而进行创建的。原型设计模式的目的是通过克隆以减少实例化对象的开销。

何时使用原型模式

原型模式要求你创建某个原型对象的多个实例,这个时候就可以使用原型模式。比如,在关于进化的研究,通常使用果蝇作为研究对象。果蝇很快繁殖,基本上一个小时就能进行产卵,和其他的生物相比,找到和记录变异的几率更大。如果换做大象的话(比如大象的孕育期长达22个月),那么整个研究过程将会消耗很长的时间。因此,只需要完成两个实例化(一个雄性和一个雌性),然后就可以跟进克隆多个变异,而不需要由具体类另外创建实例。

克隆函数

使用原型模式,首先就要了解如何使用PHP的__clone()。

abstract class CloneMe {
    public $name;
    abstract function __clone();
}

class Person extends CloneMe {

    public function __construct() {
        $this->name = "Original";
        echo 'hello';
    }

    public function display() {
        echo "\n$this->name\n";
    }

    public function __clone() {}

}
$worker = new Person();
$worker->display();

$slacker = clone $worker;
$slacker->display();

定义了一个抽象类CloneMe,然后定义一个Person类进行实现。定义一个变量$worker进行实例化,然后使用关键字clone进行对象的克隆。

输出结果:
hello
Original

Original

不过需要注意的是,__clone()不能直接调用,会出现报错Fatal error: Cannot call __clone() method on objects - use 'clone $obj' instead

克隆不会启动构造函数

上面的输出结果可能已经见到了,clone是不会启动构造函数的。其实这个也是比较理解的。举个例子,现在有一个人A,那么这个人肯定会有手脚,那么手脚就算是默认构造函数进行的初始化,如果要根据A克隆一个人B,那么B不用再造手脚,而是克隆之后,就自带了A的手脚,当然,你也可以把B的手脚砍掉(比如$slacker->name=”Tyler Teng”)。

abstract class CloneMe {
    public $name;
    abstract function __clone();
}

class Person extends CloneMe {

    public function __construct() {
        $this->name = "Original";
        echo 'hello';
    }

    public function display() {
        echo "\n$this->name\n";
    }

    public function __clone() {
    }

}
$worker = new Person();
$worker->display();

$slacker = clone $worker;
$slacker->name = "Tyler Teng";
$slacker->display();

输出结果
hello
Original

Tyler Teng

研究果蝇

抽象类和具体实现

简单定义三个属性:眼睛的颜色,翅膀震动次数,眼睛个数

abstract class IPrototype {
    public $eyeColor;
    public $wingBeat;
    public $uniyEyes;
    abstract function __clone();
}

除了一些基本的属性,还需要区别雄性和雌性

include_once 'IPrototype.php';
class FemaleProto extends IProtoType {

    const gender = "FEMALE";
    public $fecundity;

    public function __construct() {
        $this->eyeColor = "red";
        $this->wingBeat = "220";
        $this->unitEyes = "760";
    }

    public function __clone() {}

}
include_once "IPrototype.php";
class MaleProto extends IPrototype {

    const gender = "MALE";

    public $mated;

    public function __construct() {
        $this->eyeColor = "red";
        $this->wingBeat = "220";
        $this->unitEyes = "760";
    }

    public function __clone() {}

}
客户端

我们定义一个Client类,首先从具体类中实例化$fly1和$fly2,$c1Fly、$c2Fly和$updateCloneFly则分别是这两个类实例的克隆

function __autoload($class_name) {
    include_once realpath(__DIR__) . '/' .  $class_name . '.php';
}
class Client {
    private $fly1;
    private $fly2;

    private $c1Fly;
    private $c2Fly;
    private $upDatadCloneFly;

    public function __construct() {
        $this->fly1 = new MaleProto();
        $this->fly2 = new FemaleProto();

        $this->c1Fly = clone $this->fly1;
        $this->c2Fly = clone $this->fly2;

        $this->upDatadCloneFly = clone $this->fly2;
        $this->c1Fly->mated = "true";
        $this->c2Fly->fecundity = "186";
        $this->upDatadCloneFly->eyeColor = "purple";
        $this->upDatadCloneFly->wingBeat = "220";
        $this->upDatadCloneFly->unitEyes = "750";
        $this->upDatadCloneFly->fecundity = "92";

        $this->showFly($this->c1Fly);
        $this->showFly($this->c2Fly);
        $this->showFly($this->upDatadCloneFly);
    }

    public function showFly(IProtoType $fly) {
        echo "Eye color : " . $fly->eyeColor . "\n";
        echo "Wing Beats/second : " . $fly->wingBeat . "\n";
        echo "Eye units : " . $fly->unitEyes . "\n";
        $genderNow = $fly::gender;
        echo "Gender : " . $genderNow . "\n";
        if ($genderNow == "FEMALE") {
            echo "Numbers of eges : " . $fly->fecundity .  "\n";
        } else {
            echo "Mate : " . $fly->mated . "\n";
        }
    }
}

$woker = new Client();

输出
Eye color : red
Wing Beats/second : 220
Eye units : 760
Gender : MALE
Mate : true
Eye color : red
Wing Beats/second : 220
Eye units : 760
Gender : FEMALE
Numbers of eges : 186
Eye color : purple
Wing Beats/second : 220
Eye units : 750
Gender : FEMALE
Numbers of eges : 92

总结

作为被克隆的类,默认构造函数不应该做太多的初始化,否则结果往往不灵活,而且是过度的耦合设计。构造函数不应完成具体的工作,一种做法是忽略模式类中的构造函数,除非你有充分的理由包含这些构造函数;另外一种做法是,允许在需要的时间调用,让客户端负责实例化和克隆的有关事务。

参考文献

  • Learning PHP设计模式

附件

PHP7内存管理之垃圾回收

回收过程

在自动GC机制中,在zval断开value指向的时候如果发现refcount=0的时候,则会直接释放value,这就是自动回收GC的过程。发生断开的两种情况为修改变量与函数返回的时候,修改变量的时候,会断开原有的value指向,函数返回的时候,则会释放局部变量,也就是把所有局部变量的refcount计数-1。
此外,当使用unset函数的时候,也会主动销毁这个变量。

垃圾回收

虽然有了自动GC机制,但是有一种情况是没办法解决的,那就是因为变量因为循环引用而无法回收造成的内存泄露,这种情况通常是循环引用。简单来讲,循环引用就是引用自身,这种情况一般只会发生在数组或者对象的身上。比如定义了$a = array() ,插入一个新元素,这个元素对数组自身进行引用$a[] = &$a,当所有的外部引用都断开了,但是数据的refcount仍然大于0而得不到释放,但是事实上,这个变量没有在使用的价值了。

<?php
$a = array();
$a[] = &$a;
unset($a);
?>

在unset之前,变量a是有两次引用的,一个来自$a,一个来自$a[1]

unset($a)之后,减少了一次引用的recount,这个时候,已经没有了外部的引用,但是还有一个内部还有一个元素指向该引用。

像这种因为循环指向没办法释放的变量称之为垃圾。PHP引入了另外的一种机制来进行垃圾回收。
– 如果一个变量的value的refcount减少到0,说明这个value可以释放,那么这就不属于垃圾
– 如果一个变量的value减少之后大于0,那么这个value还不能被释放,那么这个value就是垃圾。
所以,判断一个变量是不是垃圾,要看value的refcount是否减少到了0。

目前垃圾回收只会出现在array和object两种类型中,当一个value被视为垃圾的时候,PHP会将这个value收集起来,等到打到了规定的数量,启动垃圾回收机制,进行统一的释放。

回收的时机

前面说了,PHP垃圾回收并不是产生一个垃圾value,就进行释放,而是把value收集起来统一释放,以为value的分析和释放,也是有性能消耗的。
在php.ini中,zend.enable_gc用来设置是否启动垃圾回收机制。绝大多数都是默认开启的,因为每个都有可能在写程序的时候,出现内存垃圾,如果把这个配置关闭了,那么就有可能造成所谓的垃圾泄露。
除了zend.enable_gc以为,还会配合zend/zend_gc.c里面的变量GC_ROOT_BUFFER_MAX_ENTRIES实现垃圾回收,默认GC_ROOT_BUFFER_MAX_ENTRIES的值是10001,GC_ROOT_BUFFER_MAX_ENTRIES[0]是用来保存一些header的数据,GC_ROOT_BUFFER_MAX_ENTRIES[1]~GC_ROOT_BUFFER_MAX_ENTRIES[10000]用来收集垃圾的数据。如果你想强制执行垃圾回收,也可使用函数gc_collect_cycles()实现。

参考文献

  • PHP7内核剖析
  • PHP手册