macOS开发-如何实现自定义文件后缀的关联

在mac APP开发中,有时候需要定义一个自己的文件后缀名(比如开发编辑器,就需要一个自己的文件格式),方便用户能够双击文件就能打开程序,接下来就讲解下,如何实现文件关联,实现文件图标的修改


1. 在Info.plist中添加下面的文件

<key>CFBundleDocumentTypes</key>
<array>
    <dict>
        <!-- 文件后缀名 -->
        <key>CFBundleTypeExtensions</key>
        <array>
            <string>ssa</string>
        </array>
        <!-- 文件图标 -->
        <key>CFBundleTypeIconFile</key>
        <string>fileIcon</string>
        <!-- 文件右击显示简介中的种类 -->
        <key>CFBundleTypeName</key>
        <string>ShotBuilder</string>
        <!-- 申明文件和程序的关系 -->
        <key>CFBundleTypeRole</key>
        <string>Editor</string>
        <!-- 暂时没查到用处 -->
        <key>LSIsAppleDefaultForType</key>
        <true/>
    </dict>
</array>

2. 文件图标

之前一直绕在png图标上,然后一直不显示,后来把png转成icns格式后,就实现了

点我在线转换icns

3. 重启Finder

由于缓存的关系,可能在更改CFBundleDocumentTypes字段内容后,没有变化,所以需要重启下Finder

sudo killall Finder

如何在方校长的脚下节约时间来进行开发

在开发过程中,如果卡在下载,可以尝试开vpn
或者配合shadowsocks进行翻墙

1.github项目在git clone时特别慢的解决办法(同时能够解决ios开发中 cocoapods执行慢的问题):

点我查看

2.brew install 安装慢的解决办法:

点我查看

3.android studio shadowsocks代理设置方法:

点我查看

4.ruby慢可以用ruby china

gem source -a https://gems.ruby-china.org

5. nodejs慢可以用淘宝源

点我查看


shadowsocks购买地址(购买【Shadowsocks网页、视频加速 50GB】,其他的网速比较差)

点我购买shadowsocks

点我下载shadowsocks


用socks5 代理服务器 加速git clone

Git 平常使用最多的是 SSH 协议和 HTTP(S) 协议,

假设本地 1080 端口有一个 socks5 代理服务器,就要为这两个协议分别设置代理。

最常用的socks5代理就是 大名鼎鼎的shadowsocks

下面的讲解都建立在 socks5端口为 1080 的情况下

HTTP(S)协议

全局代理

git config --global http.proxy socks5://127.0.0.1:1080

只对特定 URL 设置代理:

git config --global http.<要设置代理的URL>.proxy socks5://127.0.0.1:1080

# 对 https://github.com 进行设置代理
git config --global http.https://github.com.proxy socks5://127.0.0.1:1080

SSH 协议

修改 ~/.ssh/config

全局代理

ProxyCommand nc -x 127.0.0.1:1080 %h %p

只对特定域名进行代理

   Host 域名
          ProxyCommand nc -x 127.0.0.1:1080 %h %p

# 对 github.com 进行设置代理
   Host github.com
          ProxyCommand nc -x 127.0.0.1:1080 %h %p

用shadowsocks加速brew下载

伟大祖国屏蔽了Google系网站这就包括了托管代码和软件包的Google Code,

当我们使用homebrew为mac安装几个小工具的时候有可能碰见连接超时而失败的情况。

解决办法就是要有代理了,我们这使用shadowsocks.

要使命令行中的软件通过代理访问Google Code,设置一个环境变量是“可能”有效的。

编辑~/.bashrc加入一行,然后执行source ~/.bashrc

export HTTP_PROXY=socks5://127.0.0.1:1080

这对于brew调用的curl可能是无效的,那么我们需要为curl创建一个初始化文件,编辑 ~/.curlrc 写入你的代理地址

--socks5 127.0.0.1:1080

Xcode如何快速下载模拟器

1. 在 Mac 下, 打开 Xcode, 进入 Preference 中的 Downloads 面板
2. 点击任意的下载按钮
3. 打开系统帮助工具 Console
4. 稍等一会儿, 在 Xcode 里取消下载, 然后你会在 Console 里面看到对应的下载地址
     DVTDownloadable: Download Cancelled. Downloadable: https://devimages.apple.com.edgekey.net/downloads/xcode/simulators/com.apple.pkg.iPhoneSimulatorSDK9_3-9.3.1.1460411551.dmg
5. 复制对应的链接地址, 到某雷或者任何比 Xcode 下载快的工具里
6. 等待下载完成, 进入 ~/Library/Caches/com.apple.dt.Xcode/Downloads
7. 将下载好的文件移动到 Downloads 目录 (最好不要改动文件名)
8. 重启 Xcode, 回到 Downloads 面板, 点击对应下载好的 Simulator 或者 Doc

Swiftlint 安装

1. 安装支持3.0的swiftlint

brew install --HEAD swiftlint

2. 添加XCode Scripte

在 XCode 中添加一个新的”Run Script Phase”并且包含如下代码即可:

if which swiftlint >/dev/null; then
  swiftlint
else
  echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi

3. 添加配置文件

a. 创建配置文件

// 进入项目根目录
cd [project path]
// 创建配置文件
touch .swiftlint.yml 
// 编译配置文件
nano .swiftlint.yml

b. 将下面的配置复制到新建的文件中

disabled_rules:
  # - trailing_whitespace

comma: error
colon: error
# 大括号问题
opening_brace: error
closing_brace: error

control_statement: error
leading_whitespace: error
vertical_whitespace: error
# 行结尾空行
trailing_newline: error
# 行结尾分号
trailing_semicolon: error
# 行结尾的空格
trailing_whitespace:
  ignores_empty_lines: true
  severity: error

return_arrow_whitespace: error

# 行长 超过160个字符,报错
line_length: 
  warning: 160
  error: 160

# 文件长度 超出1500行报警,超出3000行报错
file_length:
  warning: 1500
  error: 3000

## 不需要检测的文件夹
excluded: 
  - Pods

# 属性名
variable_name:
  # 属性名最小长度
  min_length:
    warning: 0
    error: 0

# 方法最大行数
function_body_length:
  warning: 300
  error: 400

type_body_length:
  warning: 1000
  error: 2000
# 方法参数个数限制 
function_parameter_count: 10

cyclomatic_complexity: 100

树莓派搭建一个DLNA多媒体下载机

配置表

  • 树莓派一台
  • TF卡一张
  • 1T硬盘一个
  • 硬盘供电一个

1. 安装系统

我们选择原生系统 RaspBian

RaspBian下载地址: 点击下载

将下载的img写入到TF卡

Windows

Windows下直接使用 win32diskimager 工具

win32diskimager下载地址: 戳我下载

Mac

前往我的另外一篇博客: 点我前往

2. 启动树莓派

系统准备就绪,接上电源,接上网线,启动PI

启动后使用SSH登录(将下面的IP改为你的树莓派地址)

ssh pi@192.168.1.1

默认账户 pi

默认密码 raspberry

3. 启用root账户

为什么要启用? 因为我懒的一直用sudo

设置root账户密码

pi@raspberrypi:~$ sudo passwd root
Enter new UNIX password:   #输入第一遍密码
Retype new UNIX password:  #输入第二遍密码

启用root账户登录

pi@raspberrypi:~$ sudo passwd --unlock root
passwd: password expiry information changed.

输入上面第一行代码 第二行是提示错误的代码

原因是 新版本ssh默认关闭root登陆 你可以修改一下ssh的配置文件

编辑配置文件 启动

pi@raspberrypi:~$ sudo nano /etc/ssh/sshd_config

Ctrl + W 快捷键 搜索 PermitRootLogin without-password

修改 PermitRootLogin without-password 为 PermitRootLogin yes

Ctrl + O 快捷键 保存

Ctrl + O 快捷键 退出 Nano 编辑器

执行完之后,用 reboot 命令重启,这样就可以解锁root账户。

使用root账户登录

ssh root@192.168.1.1

4.准备硬盘

准备硬盘格式

安装程序 支持硬盘格式

apt-get install ntfs-3g
apt-get install exfat-nofuse

装上这两个模块后,就可以支持 NTFS 和 exFAT 了

查看硬盘

root@raspberrypi:~# fdisk -l
Device     Boot Start        End    Sectors  Size Id Type
/dev/sda1        2048 3907026943 3907024896  1.8T  7 HPFS/NTFS/exFAT

上面的/dev/sda1 就是需要用到的

为了性能问题,格式化硬盘为ext4

mkfs.ext4 /dev/sda1

挂载硬盘

新建一个文件夹用来挂载硬盘

mkdir -p /mnt/disk

编辑/etc/fstab文件,就可以进行开机自动挂在配置了

/dev/sda1       /mnt/disk      ext4    defaults,noatime        0       0
/dev/sda1       /mnt/disk      ntfs    defaults,noatime,uid=1000,gid=1000        0       0
/dev/sda1       /mnt/disk      exfat    defaults,noatime,uid=1000,gid=1000        0       0

执行命令 让配置生效

mount -a

5.安装迅雷远程下载

下载安装迅雷

前往下载迅雷固件 点我下载

选择 armel_v5te_glibc 版本

将程序下载到目录 /mnt/xunlei (你可以选择其他目录)

启动迅雷程序

./portal

启动成功后会出现一串激活码, 类似于 H2DS72

将激活码填入 迅雷远程下载

将迅雷程序添加到开启启动项

编辑 /etc/rc.local 文件

在 exit 0 之前添加执行代码

./mnt/xunlei/portal

迅雷安装完成,随时随地 看见喜欢的电影 可以直接到迅雷远程下载进行下载

6.安装minidlna

我们可以直接使用 apt-get install minidlna 安装

但是安装之后的dlna协议,不支持rmvb格式 所以我们要下载源码 进行修改后编译

添加源:

echo "deb-src http://archive.raspbian.org/raspbian wheezy main contrib non-free" | sudo tee -a /etc/apt/sources.list

更新源:

apt-get update

安装编译环境依赖包:

apt-get build-dep minidlna -y

下载minidlna1.1.4源码:

wget http://sourceforge.net/projects/minidlna/files/minidlna/1.1.4/minidlna-1.1.4.tar.gz

解压

tar -xvf minidlna-1.1.4.tar.gz

修改源码

metadata.c (840行左右)

else if( strncmp(ctx->iformatctx->name, "matroska", 8) == 0 )  
    xasprintf(&m.mime, "video/x-matroska");  
else if( strcmp(ctx->iformatctx->name, "flv") == 0 )  
    xasprintf(&m.mime, "video/x-flv");  

/* 添加下面的代码 */ 
else if( strcmp(ctx->iformat->name, "rm") == 0 )  
    xasprintf(&m.mime, "video/x-pn-realvideo");  
else if( strcmp(ctx->iformat->name, "rmvb") == 0 )  
    xasprintf(&m.mime, "video/x-pn-realvideo");  
/* 添加上面的代码 */ 

if( m.mime )  
    goto video_nodlna;  

upnpglobalvars.h(169行左右)

⚠️ 在 “http-get::application/ogg:,” 后 添加一个反斜杠

"http-get:*:audio/mp4:*," \  
"http-get:*:audio/x-wav:*," \  
"http-get:*:audio/x-flac:*," \  
"http-get:*:application/ogg:*," \  

/* 添加下面的代码 */ 
"http-get:*:video/x-pn-realvideo:*"  
/* 添加上面的代码 */ 

#define DLNA_FLAG_DLNA_V1_5      0x00100000  
#define DLNA_FLAG_HTTP_STALLING  0x00200000 

utils.c (381行左右)

ends_with(file, ".m2t") || ends_with(file, ".mkv")   ||  
ends_with(file, ".vob") || ends_with(file, ".ts")    ||  
ends_with(file, ".flv") || ends_with(file, ".xvid")  ||  

/* 添加下面的代码 */ 
ends_with(file, ".rm")  || ends_with(file, ".rmvb")  ||  
/* 添加上面的代码 */ 

#ifdef TIVO_SUPPORT  
    ends_with(file, ".TiVo") ||  
#endif
    ends_with(file, ".mov") || ends_with(file, ".3gp"));  

安装编译环境

执行命令

apt-get install autoconf automake autopoint
./autogen.sh
./configure

编译并安装

make
make install

移动配置文件并编辑

cp minidlna.conf /etc/
nano /etc/minidlna.conf

修改media_dir字段, 将media_dir字段修改为你的硬盘挂载目录

media_dir=/mnt/disk

测试minidlna

/usr/local/sbin/minidlnad -d -v  

没出错就ctrl+c 结束进程

添加到开机启动

cp linux/minidlna.init.d.script /etc/init.d/minidlna
chmod 755 /etc/init.d/minidlna
update-rc.d minidlna defaults

所有配置完成, 开启你的设备 看看能不能查找到

Swift利用协议优化NSNotificationCenter之添加Block

代码参考! 下面的源码基于这个 添加了Block模式,方便调用

源码

private class STObserversManager: NSObject {

    static let sharedInstance = STObserversManager()

    private var _observers = [(AnyObject, String, NSObjectProtocol)]()

    func add(observer: AnyObject, name: String, obj: NSObjectProtocol) {
        let arr = _observers.filter({$0.0 === observer && $0.1 == name})
        if arr.count > 0 {
            return
        }
        _observers.append((observer, name, obj))
    }

    func exist(observer: AnyObject, name: String? = nil) -> Bool {
        return observers(observer, name: name).count > 0
    }

    func observers(observer: AnyObject, name: String? = nil) -> [(AnyObject, String, NSObjectProtocol)] {
        return _observers.filter({name != nil ? $0.0 === observer && $0.1 == name : $0.0 === observer})
    }

    func removeAll(observer: AnyObject) {
        for i in (0..<_observers.count).reverse() {
            if _observers[i].0 === observer {
                _observers.removeAtIndex(i)
            }
        }
    }

}

public protocol STNotifier {

    associatedtype NotificationKey: RawRepresentable

}

// MARK: - 定义MTNotifier的方法
public extension STNotifier where NotificationKey.RawValue == String {

    private static func nameFor(notification: NotificationKey) -> String {
        return "\(self).\(notification.rawValue)"
    }

    func postNotification(notification: NotificationKey, object: AnyObject? = nil) {
        Self.postNotification(notification, object: object)
    }

    func postNotification(notification: NotificationKey, object: AnyObject? = nil, userInfo: [String : AnyObject]? = nil) {
        Self.postNotification(notification, object: object, userInfo: userInfo)
    }

    static func postNotification(notification: NotificationKey, object: AnyObject? = nil, userInfo: [String : AnyObject]? = nil) {
        let name = nameFor(notification)

        NSNotificationCenter.defaultCenter()
            .postNotificationName(name, object: object, userInfo: userInfo)
    }

    static func addObserver(observer: AnyObject, notification: NotificationKey, block: (notification: NSNotification) -> Void) {
        let name = nameFor(notification)
        if STObserversManager.sharedInstance.exist(observer, name: name) {
            NSLog("observer is exist")
        } else {
            let obj = NSNotificationCenter.defaultCenter()
                .addObserverForName(name, object: nil, queue: NSOperationQueue.mainQueue(), usingBlock: block)
            STObserversManager.sharedInstance.add(observer, name: name, obj: obj)
        }
    }

    static func addObserver(observer: AnyObject, selector: Selector, notification: NotificationKey) {
        let name = nameFor(notification)

        NSNotificationCenter.defaultCenter()
            .addObserver(observer, selector: selector, name: name, object: nil)
    }

    static func removeObserver(observer: AnyObject, notification: NotificationKey, object: AnyObject? = nil) {
        let name = nameFor(notification)

        NSNotificationCenter.defaultCenter()
            .removeObserver(observer, name: name, object: object)
    }

    static func removeObservers(observer: AnyObject?) {
        if let observer = observer {
            for observer in STObserversManager.sharedInstance.observers(observer) {
                NSNotificationCenter.defaultCenter().removeObserver(observer.2)
            }
            STObserversManager.sharedInstance.removeAll(observer)
        }
    }

}

##如何调用

创建对象

首先继承STNotifier

class MTMYNTNotifier: STNotifier {

    enum NotificationKey: String {
        case aaa
        case bbb
    }

}

添加监听

MTMYNTNotifier.addObserver(self, notification: .aaa) { (notification) in
  NSLog("....notification...aaa...")
}

发送消息

MTMYNTNotifier.postNotification(.aaa)

移除监听

MTMYNTNotifier.removeObservers(self)

app store提交截图分辨率

iPhone

3.5

640 x 920 pixels for hi-res portrait (without status bar) minimum
640 x 960 pixels for hi-res portrait (full screen) maximum
960 x 600 pixels for hi-res landscape (without status bar) minimum
960 x 640 pixels for hi-res landscape (full screen) maximum

4.0

640 x 1096 pixels for portrait (without status bar) minimum
640 x 1136 pixels for portrait (full screen) maximum
1136 x 600 pixels for landscape (without status bar) minimum
1136 x 640 pixels for landscape (full screen) minimum

4.7

750 x 1334 pixels for hi-res portrait
1334 x 750 pixels for hi-res landscape

5.5

1242 x 2208 pixels for hi-res portrait
2208 x 1242 pixels for hi-res landscape

iPad

iPad

1024 x 748 pixels for landscape (without status bar) minimum
1024 x 768 pixels for landscape (full screen) maximum
2048 x 1496 pixels for hi-res (without status bar) minimum
2048 x 1536 pixels for hi-res landscape (full screen) maximum
768 x 1004 pixels for portrait (without status bar) minimum
768 x 1024 pixels for portrait (full screen) maximum
1536 x 2008 pixels for hi-res portrait (without status bar) minimum
1536 x 2048 pixels for hi-res portrait (full screen) maximum

iPad Pro

2048 x 2732 pixels for hi-res portrait
2732 x 2048 pixels for hi-res landscape

OSX

1280 x 800 pixels
1440 x 900 pixels
2560 x 1600 pixels
2880 x 1800 pixels

tvOS

1920 X 1080

Apple Watch

312 x 390

整理

原始 横向 纵向
5 Series 1136 x 640 (16:9) 1920 x 1080 or 1136 x 640 1080 x 1920 or 640 x 1136
iPad and iPad Pro 2048 x 1536 (4:3) 1200 x 900 900 x 1200
iPhone 6 1334 x 750 1334 x 750 750 x 1334
iPhone 6 Plus 2208 x 1242 (Rendered Pixels)
1920 x 1080 (Physical Pixels)
1920 x 1080 1920 x 1080
AppleTV 1920 x 1080 (16:9) 1920 x 1080 n / a