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

NSView上添加阴影

在mac开发中 如何在NSView上添加阴影? 我们可以使用NSShadow类 so easy!

NSShadow *shadow = [[NSShadow alloc] init];
//设置阴影为白色
[shadow setShadowColor:[NSColor whiteColor]];
//设置阴影为右下方
[shadow setShadowOffset:NSMakeSize(1, 1)];
//这一步不可少,设置NSView的任何与Layer有关的效果都需要
[textField setWantsLayer:YES];
//最后一步,完成
[textField setShadow:shadow];

如何让你的Pod库同时支持多个设备

如何让你的Pod库同时支持多个设备

Pod::Spec.new do |s|
  s.name     = 'AFNetworking'
  s.version  = '3.1.0'
  s.license  = 'MIT'
  s.summary  = 'A delightful iOS and OS X networking framework.'
  s.homepage = 'https://github.com/AFNetworking/AFNetworking'
  s.social_media_url = 'https://twitter.com/AFNetworking'
  s.authors  = { 'Mattt Thompson' => 'm@mattt.me' }
  s.source   = { :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => s.version, :submodules => true }
  s.requires_arc = true

  s.public_header_files = 'AFNetworking/AFNetworking.h'
  s.source_files = 'AFNetworking/AFNetworking.h'

  s.ios.deployment_target = '7.0'
  s.osx.deployment_target = '10.9'
  s.watchos.deployment_target = '2.0'
  s.tvos.deployment_target = '9.0'
end

参考AFNetworking

只需要添加需要的 deployment_target 就可以
比如需要同时支持ios和osx时 只需要添加

s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9'

即可

同理 比如需要各自支持

只需要这样写

s.ios.xx = ''
s.ios.xxx = ''

s.osx.xx = ''
s.osx.xxx = ''

ios检测是否越狱

var isJailbroken: Bool {
    let pathList = ["/Applications/Cydia.app",
                   "/Library/MobileSubstrate/MobileSubstrate.dylib",
                   "/bin/bash",
                   "/usr/sbin/sshd",  
                   "/etc/apt",
                   "/private/var/lib/apt/"]
    return pathList.filter({NSFileManager.defaultManager().fileExistsAtPath($0)}).count > 0
}

Swift代码规范--自用型

空行

不多空行 不少空行

下列情况应该总是使用一个空行:

 1·两个方法之间
 2·两个类之间
 3·方法内的局部变量和方法的第一条语句之间
 4·块注释或单行注释之前
 5·一个方法内的两个逻辑段之间,用以提高可读性
 6·文件结尾
 7·import上方和下方
 8· ......


/*------import上方空一行------*/
import UIKit
import CoreBluetooth
/*------import下方空一行------*/
class ClassName: ParentClass {
    /*------方法内部第一行空行------*/
    var property: propertyType?
    var property2: propertyType?
    /*------方法与属性之间空一行------*/
    func function() {

    } 
    /*------方法之间空一行------*/
    func function2() {

    } 
    /*------方法内部最后一行空行------*/
}
/*------文件结尾空一行------*/
class ClassName: ParentClass {

    func function() {

    } 

}
/*------文件结尾空一行------*/

冒号

冒号遵循靠左规则 (左侧无空格,右侧一个空格,不多空)

---------------定义类---------------
class ClassName: ParentClass {

}

---------------定义字典---------------
var dict = [String: String]()
---------------定义属性---------------
var property: String?
---------------方法的参数---------------
func function(param: String) {

}

空格

下列情况应该总是使用一个空格:

 1·花括号前 (类定义, 方法定义, for循环, if语句 等等 <花括号遵循同行规则时>)
 2·逗号之后 (元组, 多参数 等等情况下)
 3·所有的二元运算符,除了".",应该使用空格将之与操作数分开
 4.方法返回值
 5.冒号定义(遵循上面冒号)


class ClassName: ParentClass {

}
    class ClassName:[空格]ParentClass[空格]{

    }

// ==================================================

func function() {

}
    func function()[空格]{

    }

// ==================================================
for _ in {

}
    for _ in[空格]{

    }
// ==================================================
if a == 5 {

}

    if a[空格]==[空格]5[空格]{

    }

// ==================================================

func function(param: String, param2: Int) -> Int {
    for i in 0..<10 {

    }
    if param == "" {

    }
    return 0
}

    func function(param:[空格]String,[空格]param2:[空格]Int)[空格]->[空格]Int[空格]{
        for i in 0..<10[空格]{

        }
        if param[空格]==[空格]""[空格]{

        }
        return 0
    }

缩进

按照层级缩进 不允许出现超出层级

func function() {
    if a == 1 {
print("a == 1")    
    }
}

上面的格式肯定是错的 必须按照层级来  闭包同样道理

func function() {
    if a == 1 {
        print("a == 1")    
    }
}

闭包的例子 看下面的代码就可以一眼看出闭包内部有第二个闭包

dialog.setConformButton(NSLocalizedString("PUSH_CHECK", comment: ""), handler: { (dialog) -> Void in
    print("====第一个闭包====")

    dialog?.dismiss({ () -> Void in
        print("====第二个闭包====")
    })
})

其余的 慢慢补充

ios中计算两个经纬度的距离

源码 ->

extension CLLocationCoordinate2D {

    /**
     计算两个经纬度的距离 (使用ios自带算法)

     - parameter coor: 第二个经纬度

     - returns: 返回距离(m)
     */
    func distanceFromCoor(coor: CLLocationCoordinate2D) -> Double {
        let curLocation = CLLocation(latitude: latitude, longitude: longitude)
        let otherLocation = CLLocation(latitude: coor.latitude, longitude: coor.longitude)
        let distance = curLocation.distanceFromLocation(otherLocation)
        return distance;
    }

    /**
     计算两个经纬度的距离 (使用第三方算法)

     - parameter coor: 第二个经纬度

     - returns: 返回距离(m)
     */
    func distanceFromCoor2(coor: CLLocationCoordinate2D) -> Double {
        let PI: Double = 3.1415926
        let er: Double = 6378137 // 6378700.0f;
        //ave. radius = 6371.315 (someone said more accurate is 6366.707)
        //equatorial radius = 6378.388
        //nautical mile = 1.15078
        var radlat1 = PI * latitude / 180.0
        var radlat2 = PI * coor.latitude / 180.0
        //now long.
        var radlong1 = PI * longitude / 180.0
        var radlong2 = PI*coor.longitude / 180.0
        if( radlat1 < 0 ) {
            // south
            radlat1 = PI / 2 + fabs(radlat1)
        }
        if( radlat1 > 0 ) {
            // north
            radlat1 = PI / 2 - fabs(radlat1)
        }
        if( radlong1 < 0 ) {
            //west
            radlong1 = PI * 2 - fabs(radlong1)
        }
        if( radlat2 < 0 ) {
            // south
            radlat2 = PI / 2 + fabs(radlat2)
        }
        if( radlat2 > 0 ) {
            // north
            radlat2 = PI / 2 - fabs(radlat2)
        }
        if( radlong2 < 0 ) {
            // west
            radlong2 = PI * 2 - fabs(radlong2)
        }
        //spherical coordinates x=r*cos(ag)sin(at), y=r*sin(ag)*sin(at), z=r*cos(at)
        //zero ag is up so reverse lat
        let x1 = er * cos(radlong1) * sin(radlat1)
        let y1 = er * sin(radlong1) * sin(radlat1)
        let z1 = er * cos(radlat1)
        let x2 = er * cos(radlong2) * sin(radlat2)
        let y2 = er * sin(radlong2) * sin(radlat2)
        let z2 = er * cos(radlat2)

        let d = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2) + pow(z1 - z2, 2))
        //side, side, side, law of cosines and arccos
        let theta = acos((pow(er, 2) + pow(er, 2) - pow(d, 2)) / (2 * pow(er, 2)))
        let dist  = theta * er
        return dist
    }

}

测试执行 ->

let coor1 = CLLocationCoordinate2D(latitude: 31.4785977506, longitude: 120.3755036570)
let coor2 = CLLocationCoordinate2D(latitude: 31.4788786668, longitude: 120.3791247841)

print("\(coor1.distanceFromCoor(coor2))")
print("\(coor1.distanceFromCoor2(coor2))")

输出结果 ->

"345.50016065661\n"
"345.198446957566\n"

实地测试 误差可以接受

开始使用React Native

环境需求

  1. OS X - 本向导假设您的操作系统是OS X,因为这是开发iOS应用所必须的。
  2. 推荐使用Homebrew 来安装Watchman和Flow
  3. 安装Node.js 4.0或更高版本(译注:如果你并不使用Node.js开发网站,只是用于React Native的开发,那么请先安装homebrew,然后直接使用brew install node安装即可,不必按照下面的nvm的安装步骤)
    • 安装 nvm(安装向导在这里)。然后运行nvm install node && nvm alias default node,这将会默认安装最新版本的Node.js并且设置好命令行的环境变量,这样你可以输入node命令来启动Node.js环境。nvm使你可以同时安装多个版本的Node.js,并且在这些版本之间轻松切换。
    • 如果你从未接触过npm,推荐阅读npm的文档
  4. 在命令行中输入brew install watchman,我们推荐安装watchman,否则你可能会遇到一个Node.js监视文件系统的BUG。
  5. 如果你希望使用flow来为js代码加上类型检查,那么在命令行中输入brew install flow来安装flow。(译注:新手可以跳过这一步)

我们推荐您定期运行brew update && brew upgrade来保持上述几个程序为最新版本。

iOS开发环境准备

你需要安装Xcode 7.0或者更高版本。你可以在App Store中找到并安装Xcode。

译注:如果您选择从第三方网站/镜像下载Xcode,请务必从正规镜像网站下载验证文件Hash以防止类似XcodeGhost的安全风险发生,不要信任论坛、百度空间等分享渠道

Android开发环境准备

要使React Native应用支持Android,首先需要安装Android SDK (如果你不想连接安卓设备,那么还需要一个安卓模拟器)。

译注: Windows用户可以参考这个帖子来搭建环境。

快速开始

$ npm install -g react-native-cli
$ react-native init AwesomeProject

译注:由于众所周知的网络原因,react-native命令行从npm官方源拖代码时会遇上麻烦。请将npm仓库源替换为国内镜像:

npm config set registry https://registry.npm.taobao.org
npm config set disturl https://npm.taobao.org/dist

另,执行init时切记不要在前面加上sudo(否则新项目的目录所有者会变为root而不是当前用户,导致一系列权限问题,请使用chown修复)。
本站论坛区提供了完整的绿色纯净新项目包。完整打包全部iOS和Android的第三方依赖,只要环境配置正确,无需科学上网漫长等待,解压即可直接运行。

运行iOS应用

  • $ cd AwesomeProject
  • 用XCode打开ios/AwesomeProject.xcodeproj并点击Run按钮。
  • 使用你喜欢的文本编辑器打开index.ios.js并随便改上几行。
  • 在iOS Emulator中按下⌘-R就可以刷新APP并看到你的最新修改!

运行Android应用

  • $ cd AwesomeProject
  • $ react-native run-android
  • 使用你喜欢的文本编辑器打开index.android.js并随便改上几行
  • 按Menu键(通常是F2,在Genymotion模拟器中是⌘+M)然后选择 Reload JS 就可以看到你的最新修改。
  • 在终端下运行adb logcat *:S ReactNative:V ReactNativeJS:V可以看到你的应用的日志。

恭喜!现在你已经成功运行并修改了你的第一个React Native应用!

如果你在以上过程中遇到了任何问题,可以看看论坛里总结的常见问题

为已有的React Native工程添加Android支持

如果你已经有了一个只有iOS版本的React Native工程,并且希望添加Android支持,你需要在你的工程目录下运行以下命令:

  1. 打开package.json文件,在dependencies项中找到react-native,并将其后的版本号修改为最新版本
  2. $ npm install
  3. $ react-native android

swift-style-guide

转自 https://github.com/Artwalk/swift-style-guide

##原版 戳这里

哪里不对或者不准确的,若能指出(我把原文贴上来了,用来对照 2015-12-13)
感激不尽~~~

如果没能及时更新,可能比较忙,或者比较懒 →_→
可以 Email 或 翻译后,pull request


#Swift 编码规范

A guide to our Swift style and conventions.

This is an attempt to encourage patterns that accomplish the following goals (in
rough priority order):

  1. Increased rigor, and decreased likelihood of programmer error
  2. Increased clarity of intent
  3. Reduced verbosity
  4. Fewer debates about aesthetics

If you have suggestions, please see our contribution guidelines,
then open a pull request. :zap:

本文尝试做到以下几点 (大概的先后顺序):

  1. 增进精确,减少程序员犯错的可能
  2. 明确意图
  3. 减少冗余
  4. 少量关于美的讨论

如果你有什么建议,请看我们的 贡献导引,然后开个 pull request. :zap:


Whitespace

  • Tabs, not spaces.
  • End files with a newline.
  • Make liberal use of vertical whitespace to divide code into logical chunks.
  • Don’t leave trailing whitespace.
    • Not even leading indentation on blank lines.

留空白

  • 用 Tabs,而非 空格
  • 文件结束时留一空行
  • 用足够的空行把代码分割成合理的块
  • 不要在一行结尾留下空白
    • 千万别在空行留下缩进

Prefer let-bindings over var-bindings wherever possible

能用 let 尽量用 let 而不是 var

Use let foo = … over var foo = … wherever possible (and when in doubt). Only use var if you absolutely have to (i.e. you know that the value might change, e.g. when using the weak storage modifier).

Rationale: The intent and meaning of both keywords is clear, but let-by-default results in safer and clearer code.

尽可能的用 let foo = ... 而不是 var foo = ... (并且包括你疑惑的时候)。万不得已的时候,再用 var (就是说:你 知道 这个值会改变,比如:有 weak 修饰的存储变量)。

理由: 这俩关键字 无论意图还是意义 都很清楚了,但是 let 可以产生安全清晰的代码。

A let-binding guarantees and clearly signals to the programmer that its value will never change. Subsequent code can thus make stronger assumptions about its usage.

It becomes easier to reason about code. Had you used var while still making the assumption that the value never changed, you would have to manually check that.

Accordingly, whenever you see a var identifier being used, assume that it will change and ask yourself why.

let-有保障 并且它的值的永远不会变对程序猿也是个 清晰的标记,对于它的用法,之后的代码可以做个强而有力的推断。

猜测代码更容易了。不然一旦你用了 var,还要去推测值会不会变,这时候你就不得不人肉去检查。

这样,无论何时你看到 var,就假设它会变,并问自己为啥。

Return and break early

尽早地 Return 或者 break

When you have to meet certain criteria to continue execution, try to exit early. So, instead of this:

当你遇到某些操作需要通过条件判断去执行,应当尽早地退出判断条件:你不应该用下面这种写法

if n.isNumber {
    // Use n here
} else {
    return
}

use this:

guard n.isNumber else {
    return
}
// Use n here

You can also do it with if statement, but using guard is prefered, because guard statement without return, break or continue produces a compile-time error, so exit is guaranteed.

或者你也可以用 if 声明,但是我们推荐你使用 guard

理由: 你一但声明 guard 编译器会强制要求你和 return, break 或者 continue 一起搭配使用,否则会产生一个编译时的错误。

Avoid Using Force-Unwrapping of Optionals

避免对 可选类型 强解包

If you have an identifier foo of type FooType? or FooType!, don’t force-unwrap it to get to the underlying value (foo!) if possible.

如果你有个 FooType?FooType!foo,尽量不要强行展开它以得到基本类型(foo!)。

Instead, prefer this:

if let foo = foo {
    // Use unwrapped `foo` value in here
} else {
    // If appropriate, handle the case where the optional is nil
}

Alternatively, you might want to use Swift’s Optional Chaining in some of these cases, such as:

或者使用可选链,比如:

// Call the function if `foo` is not nil. If `foo` is nil, ignore we ever tried to make the call
foo?.callSomethingIfFooIsNotNil()

Rationale: Explicit if let-binding of optionals results in safer code. Force unwrapping is more prone to lead to runtime crashes.

理由: if let 绑定可选类型产生了更安全的代码,强行展开很可能导致运行时崩溃。

Avoid Using Implicitly Unwrapped Optionals

避免毫无保留地展开可选类型

Where possible, use let foo: FooType? instead of let foo: FooType! if foo may be nil (Note that in general, ? can be used instead of !).

Rationale: Explicit optionals result in safer code. Implicitly unwrapped optionals have the potential of crashing at runtime.

如果 foo 可能为 nil ,尽可能的用 let foo: FooType? 代替 let foo: FooType!(注意:一般情况下,?可以代替!

理由: 明确的可选类型产生了更安全的代码。无保留地展开可选类型也会挂。

Prefer implicit getters on read-only properties and subscripts

对于只读属性的 propertiessubscripts,选用隐式的 getters 方法

When possible, omit the get keyword on read-only computed properties and
read-only subscripts.

如果可以,省略只读属性的 propertiessubscriptsget 关键字

So, write these:

var myGreatProperty: Int {
    return 4
}

subscript(index: Int) -> T {
    return objects[index]
}

… not these:

var myGreatProperty: Int {
    get {
        return 4
    }
}

subscript(index: Int) -> T {
    get {
        return objects[index]
    }
}

Rationale: The intent and meaning of the first version is clear, and results in less code.

理由: 第一个版本的代码意图已经很清楚了,并且用了更少的代码

Always specify access control explicitly for top-level definitions

对于顶级定义,永远明确的列出权限控制

Top-level functions, types, and variables should always have explicit access control specifiers:

顶级函数,类型和变量,永远应该有着详尽的权限控制说明符

public var whoopsGlobalState: Int
internal struct TheFez {}
private func doTheThings(things: [Thing]) {}

However, definitions within those can leave access control implicit, where appropriate:

当然,这样也是恰当的,因为用了隐式权限控制

internal struct TheFez {
    var owner: Person = Joshaber()
}

Rationale: It’s rarely appropriate for top-level definitions to be specifically internal, and being explicit ensures that careful thought goes into that decision. Within a definition, reusing the same access control specifier is just duplicative, and the default is usually reasonable.

理由: 顶级定义指定为 internal很少有恰当的,要明确的确保经过了仔细的判断。有了一个定义,重用同样的权限控制说明符就显得重复,所以默认的通常是合理的。

When specifying a type, always associate the colon with the identifier

当指定一个类型时,把 冒号和标识符 连在一起

When specifying the type of an identifier, always put the colon immediately
after the identifier, followed by a space and then the type name.

当指定标示符的类型时,冒号要紧跟着标示符,然后空一格再写类型

class SmallBatchSustainableFairtrade: Coffee { ... }

let timeToCoffee: NSTimeInterval = 2

func makeCoffee(type: CoffeeType) -> Coffee { ... }

Rationale: The type specifier is saying something about the identifier so
it should be positioned with it.

理由: 类型区分号是对于 identifier 来说的,所以要跟它连在一起。

Also, when specifying the type of a dictionary, always put the colon immediately
after the key type, followed by a space and then the value type.

Only explicitly refer to self when required

需要时才写上 self

When accessing properties or methods on self, leave the reference to self implicit by default:

当调用 selfpropertiesmethods 时,self 用默认的隐式引用:

private class History {
    var events: [Event]

    func rewrite() {
        events = []
    }
}

Only include the explicit keyword when required by the language—for example, in a closure, or when parameter names conflict:

必要的时候再加上self, 比如在闭包里,或者 参数名冲突了:

extension History {
    init(events: [Event]) {
        self.events = events
    }

    var whenVictorious: () -> () {
        return {
            self.rewrite()
        }
    }
}

Rationale: This makes the capturing semantics of self stand out more in closures, and avoids verbosity elsewhere.

原因: 在闭包里用self更加凸显它的语义,并且避免了别处的冗长

Prefer structs over classes

首选 structs 而非 classes

Unless you require functionality that can only be provided by a class (like identity or deinitializers), implement a struct instead.

Note that inheritance is (by itself) usually not a good reason to use classes, because polymorphism can be provided by protocols, and implementation reuse can be provided through composition.

For example, this class hierarchy:

除非你需要 class 才能提供的功能(比如 identitydeinitializers),不然就用 struct

要注意到继承通常是用 类 的好理由,因为 多态 可以通过 协议 实现,重用 可以通过 组合 实现。

比如,这个类的分级

class Vehicle {
    let numberOfWheels: Int

    init(numberOfWheels: Int) {
        self.numberOfWheels = numberOfWheels
    }

    func maximumTotalTirePressure(pressurePerWheel: Float) -> Float {
        return pressurePerWheel * Float(numberOfWheels)
    }
}

class Bicycle: Vehicle {
    init() {
        super.init(numberOfWheels: 2)
    }
}

class Car: Vehicle {
    init() {
        super.init(numberOfWheels: 4)
    }
}

could be refactored into these definitions:

可以重构成酱紫:

protocol Vehicle {
    var numberOfWheels: Int { get }
}

func maximumTotalTirePressure(vehicle: Vehicle, pressurePerWheel: Float) -> Float {
    return pressurePerWheel * Float(vehicle.numberOfWheels)
}

struct Bicycle: Vehicle {
    let numberOfWheels = 2
}

struct Car: Vehicle {
    let numberOfWheels = 4
}

Rationale: Value types are simpler, easier to reason about, and behave as expected with the let keyword.

理由: 值的类型更简单,容易辨别,并且通过let关键字可猜测行为。

Make classes final by default

默认 classesfinal

Classes should start as final, and only be changed to allow subclassing if a valid need for inheritance has been identified. Even in that case, as many definitions as possible within the class should be final as well, following the same rules.

Rationale: Composition is usually preferable to inheritance, and opting _in_ to inheritance hopefully means that more thought will be put into the decision.

Classes 应该作为基类,只能被子类已识别正当的继承(and only be changed to allow subclassing if a valid need for inheritance has been identified.)。即使这种例子,根据同样的规则,类中的定义也要尽可能的用 final 标注上

理由: 组合通常比继承更合适,而且不用 继承意味着考虑的更多(and opting in to inheritance hopefully means that more thought will be put into the decision.)。

Omit type parameters where possible

能不写类型参数的就别写了

Methods of parameterized types can omit type parameters on the receiving type when they’re identical to the receiver’s. For example:

参数化类型的方法可以省略接收者的类型参数,当他们对接收者来说一样时。比如:

struct Composite<T> {
    …
    func compose(other: Composite<T>) -> Composite<T> {
        return Composite<T>(self, other)
    }
}

could be rendered as:

struct Composite<T> {
    …
    func compose(other: Composite) -> Composite {
        return Composite(self, other)
    }
}

Rationale: Omitting redundant type parameters clarifies the intent, and makes it obvious by contrast when the returned type takes different type parameters.

理由: 省略多余的类型参数让意图更清晰,并且通过对比,让返回值为不同的类型参数的情况也清楚了很多。

Use whitespace around operator definitions

操作定义符 两边留空格

Use whitespace around operators when defining them. Instead of:

当定义操作定义符 时,两边留空格。不要酱紫:

func <|(lhs: Int, rhs: Int) -> Int
func <|<<A>(lhs: A, rhs: A) -> A

write:

func <| (lhs: Int, rhs: Int) -> Int
func <|< <A>(lhs: A, rhs: A) -> A

Rationale: Operators consist of punctuation characters, which can make them difficult to read when immediately followed by the punctuation for a type or value parameter list. Adding whitespace separates the two more clearly.

理由: 操作符 由 标点字符组成,当立即连着 类型或者参数值,会让代码非常难读。加上空格分开他们就清晰了

在OC与Swift混编时需要注意些神马?

swift新特性(nullable和nonnull)

在swift中,可以使用!和?来表示一个对象是optional的还是non-optional,如view?和view!。而在Objective-C中则没有这一区分,view即可表示这个对象是optional,也可表示是non-optioanl。

在Swift与Objective-C混编时,Swift编译器并不知道一个Objective-C对象到底是optional还是non-optional,因此这种情况下编译器会隐式地将Objective-C的对象当成是non-optional

为了解决这个问题,苹果在Xcode 6.3引入了一个Objective-C的新特性:nullability annotations

这一新特性的核心是两个新的类型注释:nullable和nonnull。从字面上我们可以猜到,__nullable表示对象可以是NULL或nil ,而 __nonnull表示对象不应该为空。当我们不遵循这一规则时,编译器就会给出警告。

NSArray和NSDictionary

在使用集合时,如果你能够确定集合内的对象类型时,最好明确指定类型
比如

@property (nonatomic, strong) NSArray<NSString *> *array;

否则在swift调用时 会识别为[AnyObject] 导致一些不必要产生的转换