转载作者 香蕉大大 (Github

开发过程中我特别喜欢用语法糖,原因很简单,懒得看到一堆长长的代码,但是语法糖我今天无意中看到更有意思的玩法.这里暂时吧把今天新学到的知识点整理一下希望大家喜欢,如果有更好的补充希望能和我说下,我希望更更加好的完善。

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

本文的目录如下

  • OC语法糖

    • 基础@[],@{}用法在NSArray,NSDictionary,NSNumber使用

    • !重点!@()使用

    • !重点!语法糖在UI中的使用方法

  • swift

    • 基础if let 与 guard 语法糖

    • 基础语法糖Selector例子

OC语法糖


常用基础使用部分@[],@{}这两部分的用法

1.一般数组的初始化和访问数组元素是这样的在之前的博客中我是这样初始化NSArray的:

1
2
3
4
//NSArray的便利初始化
 NSArray *array1 = [[NSArray alloc] initWithObjects:@"aaa", @"bbb", @"ccc", nil];
 //NSArray的便利构造器
 NSArray *array2 = [NSArray arrayWithObjects:@"111", @"222", @"333", nil];

获取数组的元素

1
2
3
//获取相应索引的元素
id element = [array1 objectAtIndex:0];
NSLog(@"array1_count = %d, array[0] = %@", count, element);

简化后的数组初始化和访问的做法如下

1
2
3
4
5
6
7
//NSArray的定义
NSArray *array = @[@"lu", @"da", @"shi", @YES, @123];
int count = (int)[array count];
for (int i = 0; i < count; i++)
{
   NSLog(@"%@", array[i]);
}

2.对字典(NSDictionary)的简化也引用我之前博客中得一段代码吧

1
2
3
4
5
//不可变字典的初始化
NSDictionary *dictionay = [NSDictionary dictionaryWithObjectsAndKeys:@"value1", @"key1"
@"value2", @"key2", nil];
id value = [dictionay objectForKey:@"key1"];
NSLog(@"key1 => %@", value);

我们还可以这样做

1
2
3
4
5
6
7
//NSDictionary的定义简化
NSDictionary *dictionary = @{
                             @"key0" : @"value0",
                             @"key1" : @"value1",
                             @"key2" : @"value2"
                             };
NSLog(@"key2 => %@", dictionary[@"key2"]);

3.对NSNumber简化

我们可以这样做

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
把基本类型包装成对象的便利构造函数
 
-(id) initWithChar : (char) value;
 
-(id) initWithInt : (int) value;
 
-(id) initWithFloat : (float) value;
 
-(id) initWithBool: (BOOL) value;
 
把基本数据类型包装成对象的便利构造器
 
+(id) numberWithChar : (char) value;
 
+(id) numberWithInt : (int) value;
 
+(id) numberWithFloat : (float) value;
 
+(id) numberWithBool : (BOOL) value;

我们也可以这样做,说明:在char转换为NSNumber是存的是ASCII码的形式,c输出为97

1
2
3
4
5
//NSNumber的简化
NSNumber *a = @123;
NSNumber *b = @11.2;
NSNumber *c = @('a');
NSLog(@"a = %@, b = %@, c = %@", a, b, c);

针对以上部分的简单练习

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
//NSNumber的语法糖
NSNumber *intNumber = [NSNumber numberWithInt:100];
NSNumber *intNumber2 = @100;
//不可变字符串的语法糖
NSString *string = @"hanjunqiang";
//可变字符串的语法糖
NSMutableString *mString = @"大爱中华".mutableCopy;//后缀不能丢
 
//不可变数组的语法糖
NSArray *array = @[@"1",@"2",@"3",@"4"];
NSLog(@"%@",array);
 
//访问数组元素的语法糖
NSLog(@"%@",array[1]);
 
//可变数组的语法糖
NSMutableArray *mArray = @[@"1",@"2",@"3",@"4"].mutableCopy;
 
//字典的语法糖
//字典对象[key值]取出对应的value值
NSDictionary *dict = @{@"a":@"1",@"b":@"2"};//key值在冒号前,value值在冒号后
NSLog(@"%@",dict);
NSLog(@"%@",dict[@"a"]);
//可变字典可以赋值和修改值
NSMutableDictionary *mDic = @{@"a":@"1",@"b":@"2"}.mutableCopy;
mDic[@"a"]=@"100";
NSLog(@"%@",mDic[@"a"]);

@()介绍以及使用

在 Objective-C 中我们可以用 @”foo” 来创建一个 NSString 常量,看起来似乎平淡无奇。
但它背后其实比想象的精彩,@ 可以被理解成一个特殊的宏,其接受一个 C 字符串作为参数,也可写作 @(“foo”)。
之所以说 @ 是一个特殊的宏,是因为其能根据传入的 C 字符串类型不同——C 字符串常量或 C 字符串——在运行时构建返回不同类型的 NSString,
参见下面的代码:

1
2
3
4
5
6
7
8
9
char* obtain_c_string(void)
{
    return "c_string";
}
NSLog(@"%@", @"foo".class);
NSLog(@"%@", @("bar").class);
NSLog(@"%@", @(obtain_c_string()).class);
NSLog(@"%@",@"aaa");
NSLog(@"%@",@("aaa"));

输出如下
__NSCFConstantString
__NSCFConstantString
__NSCFString
aaa
aaa

可见,如果传入的是 C 字符串常量,运行时构建的则为 NSConstantString;如果传入的是C 字符串则创建的是 NSString
众所周知,Objective-C 代码里有很多地方需要我们把代码中的一些文法串写成字符串再作为传入参数,比如 KVO 中的 keyPath 参数往往就要传入形如 propertyA.propertyB 的字符串,从实用角度出发这有两个弊端: 写字符串的时候没有代码提示,很容易写错 即便一开始写对了,如果后来相关类重构了,keyPath 的参数便失效了,而 Xcode Refactor 无法扫描字符串 当我们理解了 @(),再加上自定义的宏,上述两个问题便可迎刃而解。

1
2
3
4
5
6
7
/**
 * # 将宏的参数字符串化,C 函数 strchr 返回字符串中第一个 '.' 字符的位置
 */
#define Keypath(keypath) (strchr(#keypath, '.') + 1)
// 有代码提示,可以被重构扫描到
[objA addObserver: objB forKeyPath: @Keypath(ObjA.property1.property2) options: nil 
context: nil];

UI使用部分

拿UIImageView来做例子,原来创建对象和下面一致

1
2
3
4
5
self.imageView = [[UIImageView alloc] init];  
self.imageView.backgroundColor = [UIColor redColor];  
self.imageView.image = [UIImage imageNamed:@"12345"];  
self.imageView.frame = CGRectMake(0, 0, 100, 100);  
[self.view addSubview:self.imageView];

重点来了
这个就是语法糖在UI中创建对象的使用,瞬间感觉很高大上~

1
2
3
4
5
6
7
8
self.imageView = ({  
    UIImageView *imageView = [[UIImageView alloc] init];  
    imageView.backgroundColor = [UIColor redColor];  
    imageView.image = [UIImage imageNamed:@"12345"];  
    imageView.frame = CGRectMake(0, 0, 100, 100);  
    [self.view addSubview:imageView];  
    imageView;  
});

swift语法糖


if let 与 guard 语法糖

话说if let 和 guard 只是语法糖,没有也可以,但有了可以使得代码更简洁方便。要理解 if let 和 guard,不妨设想假如没有这两者,代码会怎么写。

1
2
3
4
5
6
7
8
9
if let
func doSomething(str: String?)
{
    let v: String! = str
    if v != nil
    {
        // use v to do something
    }
}

Swift 中因为有optional, 经常需要判断是否为空。假如没有if let,大致写成上面的样子,有了if let, 可以改写成

1
2
3
4
5
6
7
func doSomething(str: String?)
{
    if let v = str
    {
        // use v to do something
    }
}

上面两段代码的控制流是一样的。对照着,可以看出if let的写法更加简洁方便。

1
2
3
4
5
6
7
8
9
10
11
12
guard
假如if中出现的代码很长,我们写代码时可以将错误情况先返回。比如:
func doSomething(str: String?)
{
    let v: String! = str
    if v == nil
    {
        return
    }
 
    // use v to do something
}

这样做可以避免过多的嵌套。上面代码实在太常见了,swift也提供一个guard这个语法糖,用guard可以改写成:

1
2
3
4
func doSomething(str: String?){
    guard let v = str else return }    
    // use v to do something
}

上面两段代码的控制流是一样的。也可以看出guard的写法更加简洁方便。

至于if let 和 guard 语法中出现的where,只是附加一些条件。相当于逻辑运算 && 和 ||。SQL中的条件语法也是用where这个关键字。

假如还不理解,动手将一段代码,不用if let 和 guard 进行改写。试多几次,就会发觉很自然了。

语法糖Selector例子

创建控制器,添加Button

1
2
3
4
5
6
7
8
9
10
11
12
override func viewDidLoad() {
    super.viewDidLoad()
 
    let btn = UIButton(frame: CGRectMake(100,100,100,100))
    btn.backgroundColor = UIColor.redColor()
    view.addSubview(btn)
 
}
 
func printFire() {
    print("fire")
}

想实现控制器里的Button点击事件,但是,如果一个控制器里的Button特别的多,那添加Button点击事件的Selector 会觉得特别的臃肿。所以语法糖就是要拓展Selector

1
2
3
4
5
private extension Selector {
 
    static let printFire = #selector(ViewController.printFire)
 
}

我们现在给viewDidLoad方法中的Button 添加点击事件

1
btn.addTarget(self, action: .printFire, forControlEvents: .TouchUpInside)

如果Button过多的话,用语法糖方便管理Button的点击事件,又不会把点击事件变得过于臃肿

下面是控制器的完整代码

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
import UIKit
 
class ViewController: UIViewController {
 
    override func viewDidLoad() {
        super.viewDidLoad()
 
        let btn = UIButton(frame: CGRectMake(100,100,100,100))
        btn.backgroundColor = UIColor.redColor()
        btn.addTarget(self, action: .printFire, forControlEvents: .TouchUpInside)
        view.addSubview(btn)
 
 
    }
 
    func printFire() {
        print("fire")
    }
 
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
 
 
}
 
private extension Selector {
 
    static let printFire = #selector(ViewController.printFire)
 
}
 
 

iOS语法糖 简单却不那么简单的更多相关文章

  1. 第十三节:实际开发中使用最多的监视锁Monitor、lock语法糖的扩展、混合锁的使用(ManualResetEvent、SemaphoreSlim、ReaderWriterLockSlim)

    一. 监视锁(Monitor和lock) 1. Monitor类,限定线程个数的一把锁,两个核心方法: Enter:锁住某个资源. Exit:退出某一个资源. 测试案例:开启5个线程同时对一个变量进行 ...

  2. Vue3 Composition API写烦了,试试新语法糖吧—setup script

    前言 Vue3发布近一年了,相信大家对Vue3的新特性,新语法都很熟悉了.那么在使用Composition API的过程中,有没有觉得整个过程比较繁琐.比如你的模板里用到了大量的state和方法的时候 ...

  3. C# 9 record 并非简单属性 POCO 的语法糖

    C# 9 record 并非简单属性 POCO 的语法糖 最近升级专案到大统一 .NET 5 并使用 C#9 语法尝试改写套件,发现之前以为 record 只是简单属性 POCO 的简化语法糖的认知是 ...

  4. iOS开发UI篇—UITableview控件简单介绍

    iOS开发UI篇—UITableview控件简单介绍 一.基本介绍 在众多移动应⽤用中,能看到各式各样的表格数据 . 在iOS中,要实现表格数据展示,最常用的做法就是使用UITableView,UIT ...

  5. 李洪强iOS开发Swift篇---12_NSThread线程相关简单说明

    李洪强iOS开发Swift篇---12_NSThread线程相关简单说明 一 说明 1)关于多线程部分的理论知识和OC实现,在之前的博文中已经写明,所以这里不再说明. 2)该文仅仅简单讲解NSThre ...

  6. qt-qml移动开发之在ios上开发和部署app流程简单介绍

    qt5.3已经全面支持移动开发,除了mac,windows,linux.还支持ios,android,wp,meego等移动平台,本教程是作者依据自己的经验,从头讲怎么样在ios上公布自己的app.因 ...

  7. 看看C# 6.0中那些语法糖都干了些什么(终结篇)

    终于写到终结篇了,整个人像在梦游一样,说完这一篇我得继续写我的js系列啦. 一:带索引的对象初始化器 还是按照江湖老规矩,先扒开看看到底是个什么玩意. 1 static void Main(strin ...

  8. C#语法糖,让编程更具乐趣

    一.什么是语法糖 语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法 ...

  9. Java语法糖1:可变长度参数以及foreach循环原理

    语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的 ...

随机推荐

  1. PAT 1117 Eddington Number [难]

    1117 Eddington Number (25 分) British astronomer Eddington liked to ride a bike. It is said that in o ...

  2. 2017-2018 ACM-ICPC German Collegiate Programming Contest (GCPC 2017) Solution

    A. Drawing Borders Unsolved. B. Buildings Unsolved. C. Joyride Upsolved. 题意: 在游乐园中,有n个游玩设施,有些设施之间有道路 ...

  3. JSDoc 注释规范

    命令名描述 @param @argument 指定参数名和说明来描述一个函数参数@returns 描述函数的返回值@author 指示代码的作者@deprecated 指示一个函数已经废弃,而且在将来 ...

  4. 20145326 《Java程序设计》实验五——Java网络编程及安全实验报告

    实验内容 1.掌握Socket程序的编写: 2.掌握密码技术的使用: 3.设计安全传输系统. 实验步骤 我和20145211黄志远http://www.cnblogs.com/nostalgia-/组 ...

  5. Java静态内存与动态内存分配的解析

    1. 静态内存 静态内存是指在程序开始运行时由编译器分配的内存,它的分配是在程序开始编译时完成的,不占用CPU资源. 程序中的各种变量,在编译时系统已经为其分配了所需的内存空间,当该变量在作用域内使用 ...

  6. TypeScript 照猫画虎

    定义变量类型 const num: number = 1 定义函数参数类型 const init: (p: str) => void = function(param) { alert(para ...

  7. Ubuntu Budgie 18.04 是最好的Remix【转】

    本文转载子:https://www.linuxidc.com/Linux/2018-05/152223.htm [日期:2018-05-05] 来源:Linux公社  作者:醉落红尘 [字体:大 中  ...

  8. Intellij IDEA 创建控制台项目,断点调试快捷方式

    在idea 2016中创建一个控制台项目(经常会忘) 打开创建界面 注意,什么都不要选,点击next(最坑的地方,经常忘) 再次点击next ============================= ...

  9. UVa 10294 项链和手镯(polya)

    https://vjudge.net/problem/UVA-10294 题意: 手镯可以翻转,但项链不可以.输入n和t,输出用t种颜色的n颗珠子能制作成的项链和手镯的个数. 思路: 经典等价类计数问 ...

  10. BZOJ 4012 【HNOI2015】 开店

    题目链接:开店 这道题显然一眼树分治,维护点分的结构,在每个点上,对每种年龄到这个点\(u\)以及他在点分树上父亲的距离和建一棵线段树,查询的时候一路往上跳即可. 但是我太懒了(其实你要说我不会也可以 ...