OSX开发之如何实现拖入文件

如何在app中实现将文件拖入的功能? Drag & Drop

NSViewregisterForDraggedTypes 方法,用于声明Drag and Drop响应的文件类型

self.registerForDraggedTypes([NSFilenamesPboardType])

当有文件拖入时就会调用draggingEntered方法,该方法中判断是不是要对拖动进行响应,
如果响应则继续进入performDragOperation方法,完成处理

override func draggingEntered(sender: NSDraggingInfo) -> NSDragOperation {
    let pasteboard = sender.draggingPasteboard()
        // 在这可以判断是否是需要的文件类型 然后根据需要返回对应的值
    return NSDragOperation.Copy
}

override func prepareForDragOperation(sender: NSDraggingInfo) -> Bool {
    let pasteboard = sender.draggingPasteboard()
    if let list = pasteboard.propertyListForType(NSFilenamesPboardType) {
        // 这里会获取文件路径列表
        NSLog("list ==\n\(list)")
    }
    return true
}

ok 拖动文件功能实现了

但是!!!如果你需要用到 mouseEntered & mouseExited 或者其他的方法
你会发现响应会出现一些异常

这时候 你需要重写 updateTrackingAreas 方法

override func updateTrackingAreas() {
    let trackings = self.trackingAreas
    for tracking in trackings {
        self.removeTrackingArea(tracking)
    }

    let trackingArea = NSTrackingArea(rect: bounds, options:[.MouseEnteredAndExited, .ActiveAlways, .MouseMoved], owner: self, userInfo: nil)
    self.addTrackingArea(trackingArea)
}

就像这样~

CentOS 6.x 一键安装PPTP VPN脚本

环境

CentOS 6.x 32位/64位

XEN/KVM/OpenVZ

步骤

依次运行下列命令

#wget http://www.hi-vps.com/shell/vpn_centos6.sh
#chmod a+x vpn_centos6.sh

安装Centos6.2PPTPVPN脚本

#bash vpn_centos6.sh

执行完后有1、2、3种英文,对应如下中文意思。

  1. 安装VPN服务
  2. 修复VPN
  3. 添加VPN用户

我们要安装PPTP vpn,当然输入1,然后enter键了。等待安装完成,就会出现账号和密码啦,默认账号是vpn,密码是一串随机数字,自己用的话就不用加账号和密码了,复制下来备用吧。

安装完成如下:

DKMS: add Completed.
Module build for the currently running kernel was skipped
since the kernel source for this kernel does not seem to be
installed.
kernel_ppp_mppe-1.0.2-3dkms.noarch
warning: ppp-2.4.5-17.0.rhel6.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 862acc42: NOKEY
Preparing...                ########################################### [100%]
   1:ppp                    ########################################### [100%]
warning: pptpd-1.3.4-2.el6.x86_64.rpm: Header V3 DSA/SHA1 Signature, key ID 862acc42: NOKEY
Preparing...                ########################################### [100%]
   1:pptpd                  ########################################### [100%]
mknod: "/dev/ppp": 文件已存在
iptables: Saving firewall rules to /etc/sysconfig/iptables:[  OK  ]
Starting pptpd:                                            [  OK  ]
VPN service is installed, your VPN username is vpn, VPN password is 7OXoJ0V1

iOS 低电量模式检测监听

监听低电量的变化

OBJECTIVE-C

[[NSNotificationCenter defaultCenter] addObserver:self
   selector: @selector(yourMethodName:)
   name: NSProcessInfoPowerStateDidChangeNotification
   object: nil];

SWIFT

NSNotificationCenter.defaultCenter().addObserver(
    self,
    selector: “yourMethodName:”,
    name: NSProcessInfoPowerStateDidChangeNotification,
    object: nil
)

获取低电量状态

OBJECTIVE-C

if ([[NSProcessInfo processInfo] isLowPowerModeEnabled]) {
    // Low Power Mode is enabled. Start reducing activity to conserve energy.
} else {
    // Low Power Mode is not enabled.
};

SWIFT

if NSProcessInfo.processInfo().lowPowerModeEnabled {
    // Low Power Mode is enabled. Start reducing activity to conserve energy.
} else {
    // Low Power Mode is not enabled.
}

CentOS安装ShadowSocks服务端

1.查看系统

1
2
3
4
[root@localhost ~]# cat /etc/issue
CentOS release 6.6 (Final)
[root@localhost ~]# uname -a
Linux localhost.localdomain 2.6.32-042stab106.6 #1 SMP Mon Apr 20 14:48:47 MSK 2015 x86_64 x86_64 x86_64 GNU/Linux

2.安装ShadowSocks

1
2
# yum install python-setuptools && easy_install pip
# pip install shadowsocks

3.创建配置文件/etc/shadowsocks.json

1
2
3
4
5
6
7
8
9
10
11
[root@localhost /]# touch /etc/shadowsocks.json
[root@localhost /]# vi /etc/shadowsocks.json
{
"server":"你的服务器ip",
"server_port":443,
"local_address": "127.0.0.1",
"local_port":1080,
"password":"登陆密码",
"timeout":600,
"method":"rc4-md5"
}

如果需要多账号的话 可以使用这个格式

1
2
3
4
5
6
7
8
9
10
{
"timeout": 600,
"method": "aes-256-cfb",
"port_password":
{
"40001": "password1",
"40002": "password2",
"40003": "password3"
}
}

备注:加密方式官方默认使用aes-256-cfb,推荐使用rc4-md5,因为 RC4比AES速度快好几倍。

各字段说明:

 server:服务器IP
 server_port:服务器端口
 local_port:本地端端口
password:用来加密的密码
 timeout:超时时间(秒)
 method:加密方法,可选择 “bf-cfb”, “aes-256-cfb”, “des-cfb”, “rc4″等

4.使用配置文件在后台运行shadowsocks服务

1
[root@localhost /]# ssserver -c /etc/shadowsocks.json -d start

备注:若无配置文件,在后台可以使用一下命令运行:

[root@localhost /]# ssserver -p 443 -k MyPass -m rc4-md5 -d start

5.停止服务

1
[root@localhost /]# ssserver -c /etc/shadowsocks.json -d stop

swift 遍历enum

func iterateEnum<T: Hashable>(_: T.Type) -> AnyGenerator<T> {
    var i = 0
    return anyGenerator {
        let next = withUnsafePointer(&i) { UnsafePointer<T>($0).memory }
        return next.hashValue == i++ ? next : nil
    }
}

enum Enum {
    case 🍉
    case 🍊
    case 🍌
}


for f in iterateEnum(Enum) {
    print(f)
}

iOS 定位服务、通讯录、日历、提醒事项、照片、蓝牙共享、麦克风、相机等授权检测

1、定位服务

相关框架

1
#import <CoreLocation/CoreLocation>

检测方法

1
+ (CLAuthorizationStatus)authorizationStatus

相关返回参数

1
2
3
4
5
6
7
8
9
10
11
12
//用户尚未做出选择
kCLAuthorizationStatusNotDetermined = 0,
// 未授权,且用户无法更新,如家长控制情况下
kCLAuthorizationStatusRestricted,
// 用户拒绝App使用
kCLAuthorizationStatusDenied,
// 总是使用
kCLAuthorizationStatusAuthorizedAlways NS_ENUM_AVAILABLE(NA, 8_0),
// 按需使用
kCLAuthorizationStatusAuthorizedWhenInUse NS_ENUM_AVAILABLE(NA, 8_0),
// 已授权
kCLAuthorizationStatusAuthorized

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
__block void (^checkLocationAuth)(void) = ^{
CLAuthorizationStatus authStatus = [CLLocationManager authorizationStatus];

if (CLAuthorizationStatusAuthorized == authStatus) {
//授权成功,执行后续操作
}else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
checkLocationAuth();
});
}
};
checkLocationAuth();

2、通讯录

1
#import <AddressBook/AddressBook.h>

检测方法

1
ABAuthorizationStatus ABAddressBookGetAuthorizationStatus(void)

授权状态

1
2
3
4
kABAuthorizationStatusNotDetermined = 0,    // 未进行授权选择<br>
kABAuthorizationStatusRestricted, // 未授权,且用户无法更新,如家长控制情况下<br>
kABAuthorizationStatusDenied, // 用户拒绝App使用<br>
kABAuthorizationStatusAuthorized // 已授权,可使用<br>

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
__block void (^checkAddressBookAuth)(void) = ^{
ABAuthorizationStatus authStatus = ABAddressBookGetAuthorizationStatus();

if (kABAuthorizationStatusAuthorized == authStatus) {
//授权成功,执行后续操作
}else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
checkAddressBookAuth();
});
}
};
checkAddressBookAuth();

3、日历/提醒事项授权

1
#import <EventKit/EventKit.h>

检测方法

1
+ (EKAuthorizationStatus)authorizationStatusForEntityType:(EKEntityType)entityType

参数类型

1
2
EKEntityTypeEvent,  //事件
EKEntityTypeReminder//提醒

授权状态

1
2
3
4
EKAuthorizationStatusNotDetermined = 0,// 未进行授权选择
EKAuthorizationStatusRestricted,    // 未授权,且用户无法更新,如家长控制情况下
EKAuthorizationStatusDenied,       // 用户拒绝App使用
EKAuthorizationStatusAuthorized,    // 已授权,可使用

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
__block void (^checkCalanderAuth)(void) = ^{
EKAuthorizationStatus authStatus = [EKAuthorizationStatus authorizationStatusForEntityType:EKEntityTypeEvent];

if (EKAuthorizationStatusAuthorized == authStatus) {
//授权成功,执行后续操作
}else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
checkCalanderAuth();
});
}
};
checkCalanderAuth();

4、照片库授权

1
#import <ALAssetsLibrary/ALAssetsLibrary.h>

检测方法

1
+ (ALAuthorizationStatus)authorizationStatus;

授权状态

1
2
3
4
ALAuthorizationStatusNotDetermined = 0,// 未进行授权选择
ALAuthorizationStatusRestricted,    // 未授权,且用户无法更新,如家长控制情况下
ALAuthorizationStatusDenied,       // 用户拒绝App使用
ALAuthorizationStatusAuthorized,    // 已授权,可使用

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
__block void (^checkAssetLibraryAuth)(void) = ^{
ALAuthorizationStatus authStatus = [ALAuthorizationStatus authorizationStatus];

if (ALAuthorizationStatusAuthorized == authStatus) {
//授权成功,执行后续操作
}else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
checkAssetLibraryAuth();
});
}
};
checkAssetLibraryAuth();

5、蓝牙授权状态检测

1
#import <CoreBluetooth/CoreBluetooth.h>

检测方法

1
+ (CBPeripheralManagerAuthorizationStatus)authorizationStatus;

授权状态

1
2
3
4
CBPeripheralManagerAuthorizationStatusNotDetermined = 0,// 未进行授权选择
CBPeripheralManagerAuthorizationStatusRestricted,    // 未授权,且用户无法更新,如家长控制情况下
CBPeripheralManagerAuthorizationStatusDenied,       // 用户拒绝App使用
CBPeripheralManagerAuthorizationStatusAuthorized,    // 已授权,可使用

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
__block void (^checkPeripheralAuth)(void) = ^{
CBPeripheralManagerAuthorizationStatus authStatus = [CBPeripheralManagerAuthorizationStatus authorizationStatus];

if (CBPeripheralManagerAuthorizationStatusAuthorized == authStatus) {
//授权成功,执行后续操作
}else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
checkPeripheralAuth();
});
}
};
checkPeripheralAuth();

6、摄像头授权状态检测

1
#import <AVFoundation/AVFoundation.h>

检测方法

1
+ (AVAuthorizationStatus)authorizationStatusForMediaType:(NSString *)mediaType;

授权状态

1
2
3
4
AVAuthorizationStatusNotDetermined = 0,// 未进行授权选择
AVAuthorizationStatusRestricted,    // 未授权,且用户无法更新,如家长控制情况下
AVAuthorizationStatusDenied,       // 用户拒绝App使用
AVAuthorizationStatusAuthorized,    // 已授权,可使用

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
__block void (^checkCameraAuth)(void) = ^{
AVAuthorizationStatus authStatus = [AVAuthorizationStatus authorizationStatusForMediaType:AVMediaTypeVideo];

if (AVAuthorizationStatusAuthorized == authStatus) {
//授权成功,执行后续操作
}else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
checkCameraAuth();
});
}
};
checkCameraAuth();

7、麦克风授权状态检测

1
#import <AVFoundation/AVFoundation.h

检测方法

1
- (AVAudioSessionRecordPermission)recordPermission;

授权状态

1
2
3
AVAudioSessionRecordPermissionUndetermined,    // 用户尚未被请求许可。
AVAudioSessionRecordPermissionDenied,       // 用户已被要求并已拒绝许可。
AVAudioSessionRecordPermissionGranted,    // 用户已被要求并已授予权限。

参考代码

1
2
3
4
5
6
7
8
9
10
11
12
__block void (^checkRecordPermission)(void) = ^{
AVAudioSessionRecordPermission authStatus = [[AVAudioSession sharedInstance] recordPermission];

if (AVAudioSessionRecordPermissionGranted == authStatus) {
//授权成功,执行后续操作
}else {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
checkRecordPermission();
});
}
};
checkRecordPermission();

在Swift中使用DEBUG宏的方法

来源于: Qiita

在Objective-C开发中 我们可以使用下面的方法来区分Debug和Release方法

1
2
3
#if DEBUG
// ...
#endif

但是到了swift之后 却不生效了
so 找了好几个文章 找到解决办法

Xcode -> Build Settings -> Swift Compiler - Custom Flags -> Other Swift Flags

选择Debug 添加

1
-D DEBUG

so 你就可以愉快的在swift中使用

1
#if DEBUG


提升效率的Android开源库推荐

FlycoTabLayout

一个Android TabLayout库,目前有两个TabLayout

  • SlidingTabLayout: 参照PagerSlidingTabStrip进行大量修改
  • CommonTabLayout: 不同于SlidingTabLayout对ViewPager依赖,它是一个不依赖ViewPager可以与其他控件自由搭配使用的TabLayout



sweet-alert-dialog

Android版的SweetAlert,清新文艺,快意灵动的甜心弹框

灵感来源于JS版SweetAlert


CircleImageView

Android上快速实现圆形图片


SwitchButton

状态切换的 Button,类似 iOS,拥有良好的用户界面


Cube

一个Android开发包, 可极大提高你的开发效率。

  • 图片加载
  • 简化接口请求
  • 等等等等功能

android-Ultra-Pull-To-Refresh

纯粹的一个下拉刷新库



GridViewWithHeaderAndFooter

可以addFooterView() 和 addHeaderView() 的 GridView

AndroidStudio小技巧--依赖库

配置依赖项目

有时候我们会开发一些平台库项目,我自己写了一个Library的Android库,用于后面不需要重复造轮子,现在我有另外一个项目Demo,也想开始依赖于Library,怎么做比较合适。

先来看以一下目录结构:

1
2
3
4
5
Library
|-library
DemoProject
|-app
|-library

直接copy一份到Demo肯定是不行的,因为这样就存在两个副本要维护。

解决办法就是手动配置依赖库的位置:

1
2
include ':app', ':library'
project(':library').projectDir = new File(rootDir, "../Library/library")

打开setting.gradle,包含Library,然后指定其项目位置,我这里用的是相对路径。
剩下的就是在app的build.gradle里配置依赖了

1
compile project(':library')

最后同步一下gradle,Library会出现在左侧的导航面板中,就可以正常使用Library中的资源了。


小结
这个方法相对来说既简单又实用,关键在于配置Library的路径,这和Eclipse中的操作其实是类似的,只不过AndroidStudio目前并有有可视化的方法来添加目录并不在项目之内的库,所以需要自己手动配置。

OSX下给树莓派安装Raspbian系统

树莓派官网下载镜像

插入SD卡,用df命令查看当前已挂载的卷

1
2
3
4
5
6
7
JiaWeiGedeMBP:book gejw$ df -h
Filesystem Size Used Avail Capacity iused ifree %iused Mounted on
/dev/disk1 112Gi 80Gi 31Gi 72% 21068699 8254563 72% /
devfs 187Ki 187Ki 0Bi 100% 646 0 100% /dev
map -hosts 0Bi 0Bi 0Bi 100% 0 0 100% /net
map auto_home 0Bi 0Bi 0Bi 100% 0 0 100% /home
/dev/disk2s1 56Mi 19Mi 37Mi 34% 512 0 100% /Volumes/boot

对比Size和Name可以找到SD卡的分区在系统里对应的设备文件(这里是/dev/disk2s1),如果你有多个分区,可能还会有disk1s2之类的。

使用diskutil unmount将这些分区卸载:

1
2
JiaWeiGedeMBP:book gejw$ diskutil unmount /dev/disk2s1
Volume boot on disk2s1 unmounted

通过diskutil list来确认设备:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
JiaWeiGedeMBP:book gejw$ diskutil list
/dev/disk0
#: TYPE NAME SIZE IDENTIFIER
0: GUID_partition_scheme *121.3 GB disk0
1: EFI EFI 209.7 MB disk0s1
2: Apple_CoreStorage 120.5 GB disk0s2
3: Apple_Boot Recovery HD 650.0 MB disk0s3
/dev/disk1
#: TYPE NAME SIZE IDENTIFIER
0: Apple_HFS Macintosh HD *120.1 GB disk1
Logical Volume on disk0s2
90141AB8-C189-4966-AC2F-D97481F904DD
Unlocked Encrypted
/dev/disk2
#: TYPE NAME SIZE IDENTIFIER
0: FDisk_partition_scheme *7.9 GB disk2
1: Windows_FAT_32 boot 58.7 MB disk2s1
2: Linux 7.9 GB disk2s2

使用dd命令将系统镜像写入,需要特别特别注意disk后的数字,不能搞错!

(说明:/dev/disk2s1是分区,/dev/disk2是块设备)

1
JiaWeiGedeMBP:Downloads gejw$ sudo dd bs=4m if=2015-05-05-raspbian-wheezy.img of=/dev/disk2

经过几分钟的等待,出现下面的提示,说明SD卡刷好了:

1
2
3
462+1 records in
462+1 records out
1939865600 bytes transferred in 163.133220 secs (11891297 bytes/sec)

用diskutil unmountDisk卸载设备:

1
2
JiaWeiGedeMBP:Downloads gejw$ diskutil unmountDisk /dev/disk2
Unmount of all volumes on disk1 was successful

现在就可以拔下SD卡,插到树莓派上启动系统了。