• OCswift混编中的相互跳转和传值

    前段时间在开发项目中遇到了OC和swift混编的情况,下面就相互跳转和传值分享一下自己的经验:


    1.OC----> swift

    首先要在OC中引用swift头文件,写法是 #import "(项目名)-swift.h"

    跳转:

    swiftClearViewController *VC = [[swiftClearViewController alloc]init];

    [self.navigationController pushViewController:VC animated:YES];

    当需要传值时首先要在swift中定义变量

    然后就可以正常的进行传值了


    2.swift---->OC

    还是要引用头文件,这里的方法是创建桥接头文件,具体方法不再赘述

    跳转和传值和上面类似


    展开全文
  • OCSwift中的字符串

    2019-02-20 00:37:46
    一、OC中的字符串 引用类型在Object-C中,使用NSString和NSMutableString这两个类对字符串进行操作,一个字符串对象会被指针所引用。一般情况下,使用一个旧的字符串对象对一个新声明的字符串对象进行赋值,其实就是...

    一、OC中的字符串

    1. 引用类型

      在Object-C中,使用NSString和NSMutableString这两个类对字符串进行操作,一个字符串对象会被指针所引用。

      一般情况下,使用一个旧的字符串对象对一个新声明的字符串对象进行赋值,其实就是新的指针指向同一个字符串对象,也就是指针的拷贝,并没有生成新的字符串。只有对一个可变字符串对象进行拷贝,或者对任意字符串对象进行可变拷贝时才会生成一个新对象。

      同样的在函数、方法传值时,也是指针的传递,操作的都是同一份对象。

    2. 可变与不可变字符串

      NSString类型的对象是不可变字符串,NSString一旦被实例化,就不能再改变内容和长度。

      NSMutableString类型的对象是可变字符串,它可以进行拼接、移除、插入等操作。

    3. 常用字符串操作

    • 新建字符串
    // 创建一个空字符串
    NSString *str1 = [NSString string];
    NSString *str2 = @"";
        
    // 创建一个非空串
    NSString *str3 = @"我是一个字符串";
    
    • 是否空串
    NSString *name = @"";
    if (name.length == 0) {
        NSLog(@"名字是个空字符串");
    } else {
        NSLog(@"名字不是个空字符串");
    }
    
    • 长度
    name = @"Alean";
    NSInteger nameLength = name.length;
    NSLog(@"姓名长度:%zd个字符", nameLength);
    
    • 是否相同
    NSString *name2 = @"Alean";
    if ([name isEqualToString:name2]) {
        NSLog(@"姓名相同");
    } else {
        NSLog(@"姓名不同");
    }
    
    • 大小写转换
    NSString *upperName = name.uppercaseString;
    NSString *lowerName = name.lowercaseString;
    NSLog(@"姓名大写:%@ \n姓名小写:%@", upperName, lowerName);
    
    • 开头
    NSString *prefix = @"Ale";
    if ([name hasPrefix:prefix]) {
        NSLog(@"%@是以%@开头的", name, prefix);
    } else {
        NSLog(@"%@不是以%@开头的", name, prefix);
    }
    
    • 结尾
    NSString *suffix = @"na";
    if ([name hasSuffix:suffix]) {
        NSLog(@"%@是以%@结尾的", name, suffix);
    } else {
        NSLog(@"%@不是以%@结尾的", name, suffix);
    }
    
    • 从头截取子串
    NSInteger indexTo = 2;
    NSString *subNameTo = [name substringToIndex:indexTo];
    NSLog(@"%@从开头截取%@个字符的子串%@", name, @(indexTo), subNameTo);
    
    • 从指定位置截取子串
    NSInteger indexFrom = 3;
    NSString *subNameFrom = [name substringFromIndex:indexFrom];
    NSLog(@"%@从第%@个字符到结束的子串%@", name, @(indexFrom), subNameFrom);
    
    • 指定区间子串
    NSRange range = NSMakeRange(1, 2);
    NSString *subNameRange = [name substringWithRange:range];
    NSLog(@"%@从第%zd个字符截取长度为%zd的子串为%@", name, range.location, range.length, subNameRange);
    
    • 拼接
    NSString *all = [name stringByAppendingString:name2];
    NSLog(@"%@拼接%@的结果是:%@", name, name2, all);
    

    二、swift中的字符串

    1. 引用类型

      Swift中,String类型对象一个实际的值,使用旧的String对象对新定义的String赋值,实际创建了一个相等的新值。

      同样,函数传参时,也是传递的实际值,并且创建了一个新的字符串,函数内的操作不会改变原有的String对象。

    2. 可变与不可变字符串

      Swift中可变字符串使用var修饰,let用来修饰不可变字符串。

    3. 常用字符串操作

    • 创建一个空字符串
    let emptyStr1 = ""
    let emptyStr2 = String()
    
    • 创建字符串常量
    let nameConst = "Jack"
    
    • 创建字符串变量
    var nameVariable = "xiaoming"
    nameVariable = "xiaogang"
    
    • 是否空串
    var name = ""
    if name.isEmpty {
        print("名字是个空字符串")
    } else {
        print("名字叫:\(name)")
    }
    

    // 长度
    name = “Alean”
    let nameLength = name.characters.count
    print(“姓名长度:(nameLength)个字符”)

    • 是否相同
    let name2 = "Alean"
    if name == name2 {
        print("姓名相同")
    } else {
        print("姓名不同")
    }
    
    • 大小写转换
    let upperName = name.uppercased()
    let lowerName = name.lowercased()
    print("姓名大写:\(upperName) \n姓名小写:\(lowerName)")
    
    • 开头
    let prefix = "Ale"
    if name.hasPrefix(prefix) {
        print("\(name)是以\(prefix)开头的")
    } else {
        print("\(name)不是以\(prefix)开头的")
    }
    
    • 结尾
    let suffix = "na"
    if name.hasSuffix(suffix) {
        print("\(name)是以\(suffix)结尾的")
    } else {
        print("\(name)不是以\(suffix)结尾的")
    }
    
    • 从头截取子串
    let indexTo = 2
    let subIndexTo = name.index(name.startIndex, offsetBy: indexTo)
    let subNameTo = name.substring(to: subIndexTo)
    print("\(name)从开头截取\(indexTo)个字符的子串\(subNameTo)")
    
    • 从指定位置截取子串
    let indexFrom = -2
    let fromIndexFrom = name.characters.count + indexFrom
    let subIndexFrom = name.index(name.endIndex, offsetBy: indexFrom)
    let subNameFrom = name.substring(from: subIndexFrom)
    print("\(name)从第\(fromIndexFrom)个字符到结束的子串\(subNameFrom)")
    
    • 指定区间子串
    let subFormIndex = 1
    let subLength = 2
    let rangeStartIndex = name.index(name.startIndex, offsetBy: subFormIndex)
    let rangeLengthIndex = name.index(name.startIndex, offsetBy: subFormIndex + subLength)
    let range = Range(uncheckedBounds: (lower: rangeStartIndex, upper: rangeLengthIndex))
    let subNameRange = name.substring(with: range)
    print("\(name)从第\(subFormIndex)个字符截取长度为\(subLength)的子串为\(subNameRange)")
    
    • 拼接
    let all = name + name2
    print("\(name)拼接\(name2)的结果是:\(all)")
    
    展开全文
  • Swift 传值之代理传值

    2016-01-29 16:38:55
    Swift中,传值的方法有很多,都很简便,之前介绍了属性传值,swift的属性传值可以从下级页面传到上级页面,现在来介绍如何用代理传值。

    在Swift中,传值的方法有很多,都很简便,之前介绍了属性传值,swift的属性传值可以从下级页面传到上级页面,现在来介绍如何用代理传值。

    创建项目和storyBoard的方法和属性传值一样,这里不再赘述 

    属性传值:http://blog.csdn.net/zhangjitao_boke/article/details/50606185

    代理传值:http://blog.csdn.net/zhangjitao_boke/article/details/50606707

    闭包传值:http://blog.csdn.net/zhangjitao_boke/article/details/50607325

    通知传值:http://blog.csdn.net/zhangjitao_boke/article/details/50607818

    单例传值:http://blog.csdn.net/zhangjitao_boke/article/details/50608066


    创建类的目录如下:(这里特别的,可以创建一个协议类,专门用来书写协议,方便管理查看,当然你也可以写个协议放在控制器的最上头,效果是一样的)



    下面直接贴代码

    //
    // Delegate.swift
    // DelegatePassvalue
    //
    // Created by JT on 16/1/29.
    // Copyright © 2016年 JT. All rights reserved.
    //

    import Foundation

    protocol passValueDelegate:NSObjectProtocol {

    // 设置协议方法
    func passValue(text:String)

    }


    在FirstViewController中(在协议方法没有完全设置好之前会报红,这里不必介意)

    //
    // FirstViewController.swift
    // DelegatePassvalue
    //
    // Created by JT on 16/1/29.
    // Copyright © 2016年 JT. All rights reserved.
    //

    import UIKit
    // 遵循协议
    class FirstViewController: UIViewController,passValueDelegate {

    @IBOutlet weak var firstTextField: UITextField!

    override func viewDidLoad() {
    super.viewDidLoad()
    }
    // 实现代理方法
    func passValue(text: String) {
    firstTextField.text = text
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    let storyBoard = UIStoryboard.init(name: "Main", bundle: nil)
    let secondVC = storyBoard.instantiateViewControllerWithIdentifier("secondVC") as! SecondViewController

    // 设置代理
    secondVC.delegate = self
    self.navigationController?.pushViewController(secondVC, animated: true)
    }


    }

    在SecondViewController中

    //
    // SecondViewController.swift
    // DelegatePassvalue
    //
    // Created by JT on 16/1/29.
    // Copyright © 2016年 JT. All rights reserved.
    //

    import UIKit

    class SecondViewController: UIViewController {

    @IBOutlet weak var secondTextField: UITextField!

    // 设置代理变量为weak避免循环引用
    weak var delegate:passValueDelegate?
    override func viewDidLoad() {
    super.viewDidLoad()

    self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "返回", style: UIBarButtonItemStyle.Plain, target: self, action: "backAction")
    }

    func backAction() {

    // 让secondVC的代理去执行代理方法
    self.delegate?.passValue(secondTextField.text!)

    self.navigationController?.popToRootViewControllerAnimated(true)
    }


    }


    这样,Swift的代理传值就实现了,可以测试一下,完全没有问题。



    展开全文
  • //由于Swift的类型推导,newTuple被推导为(String,Int)类型的变量元组的解绑几个变量一旦联合在一起,组成了一个元组,他们就被“绑定”了,要想从一个元组中单独取出某一个数据时,需要解绑元组。直接解绑直接...

    定义

    元组是一个包含了若干个相关联变量的对象。

    元组的创建

    var newTuple = ("kt",20)
    //由于Swift的类型推导,newTuple被推导为(String,Int)类型的变量

    元组的解绑

    几个变量一旦联合在一起,组成了一个元组,他们就被“绑定”了,要想从一个元组中单独取出某一个数据时,需要解绑元组。

    直接解绑

    直接解绑是最简单的一种解绑方式,只要定义若干个变量与元组中的变量一一对应即可。

    var newTuple = ("kt",20)
    var (name , age) = newTuple
    println("name = \(name)")
    println("age = \(age)")

    输出结果:

    name = kt
    age = 20

    过滤元素解绑

    直接解绑使用简单,但是可能会增加一些代码量。如果元组中有100个数据,而我们只对一个数据感兴趣,可以用_ 来代替我们不感兴趣的变量名,也就是过滤掉他们。代码如下:

    var newTuple = ("kt",20)
    var (name , _) = newTuple
    println("name = \(name)")

    输出结果:

    name = kt

    下标解绑

    如果还是觉得需要写出变量名麻烦,还可以使用更简单的下表解绑。这时候可以把元组当做数组,直接写出变量的在元组中的下标即可。(下标从0开始)

    var newTuple = ("kt",20)
    println("name = \(newTuple.0)") //输出结果和之前一样。

    但是需要注意的是,这样的写法有一个缺点:下标不可以用变量来表示,也就是说这样的写法是错误的:

    var newTuple = ("kt",20)
    let index:Int = 0
    println("name = \(newTuple.index)")
    
    //错误,报错:“(String, Int)doesn't not have a member named 'index'”

    试图越界访问一个不存在的数据会导致编译错误。

    变量名解绑

    如果在定义元组的时候,指定了变量的变量名,还可以根据变量的变量名来解绑。

    var newTuple = (name: "kt", age: 20)
    println("name = \(newTuple.name)")

    与用下标解绑一样,这里的变量名name不可以用一个具有”name”值的String类型变量来代替。

    总结

    元组(Tuple)的概念对于没有接触过脚本语言的程序猿来说,是比较新的概念。但是元组既不复杂也不神秘,很多时候用Struct结构体或者类都可以解决。可以把元组理解为一种只能存放数据,却没有定义方法的轻量级数据结构。

    附录

    查看完整专栏——《Swift轻松入门》

    【Swift入门(一)——基本语法】
    【Swift入门(二)——字符与字符串】
    【Swift入门(三)——元组(Tuple)】
    【Swift入门(四)——可选类型(Optionals)与断言(Assert)】
    【Swift入门(五)——数组(Array)】
    【Swift入门(六)——字典(Dictionary)】
    【Swift入门(七)——结构体(Struct)】
    【Swift入门(八)——功能强大的求余运算符】
    【Swift入门(九)——String与Int、Double、Float等数字相互转换】
    【Swift入门(十)——循环引用、弱引用和无主引用】
    【Swift入门(十一)——类型转换与is、as操作】
    【Swift入门(十二)——利用Extension添加逆序输出字符串方法】

    展开全文
  • 知识背景: 在日程开放中页面传值是最为常见的,(具体动画特效见我的我的GitHub ) 效果图 学习目标: 学习闭包的使用学习页面传值FirstViewController --> SecondViewController通过闭包回调将值传回:...

    知识背景:

    1. 在日程开放中页面传值是最为常见的,(具体动画特效见我的我的GitHub )

    效果图

    学习目标:

    1. 学习闭包的使用
    2. 学习页面传值FirstViewController --> SecondViewController
    3. 通过闭包回调将值传回:SecondViewController --> FirstViewController

    步骤

    1. 创建两个UIViewController:

    LWRootViewController.swift 和 LWSecondViewController.swift
    因为是Demo,我的布局就比较随意.一般两种方式(纯代码创建和storyboard)本次使用纯代码创建

    2. LWRootViewController的具体代码

    1. 创建组件,初始化,代码如下:

    swift
    
        var textFieldWithTagOne: UITextField?
        var textFieldWithTagTwo: UITextField?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.view.backgroundColor = UIColor.whiteColor()
    
    
            //通过tag获取控件
            textFieldWithTagOne = UITextField(frame: CGRectMake(0, 0, 150,30))
            textFieldWithTagOne!.center = CGPoint(x: self.view.center.x, y: 100)
            textFieldWithTagOne!.backgroundColor = UIColor.grayColor()
            textFieldWithTagOne!.tag = 1
            textFieldWithTagOne!.addTarget(self, action: "getValue:", forControlEvents: UIControlEvents.EditingDidBegin)
            self.view.addSubview(textFieldWithTagOne!)
    
            textFieldWithTagTwo = UITextField(frame: CGRectMake(0, 0, 150,30))
            textFieldWithTagTwo!.center = CGPoint(x: self.view.center.x, y: 200)
            textFieldWithTagTwo!.backgroundColor = UIColor.grayColor()
            textFieldWithTagTwo!.tag = 2
            textFieldWithTagTwo!.addTarget(self, action: "getValue:", forControlEvents: UIControlEvents.EditingDidBegin)
            self.view.addSubview(textFieldWithTagTwo!)
    
        }
    • 这里涉及了代码创建界面时的为何放在ViewDidLoad()中,其实这就要扯到 UIViewController的生命周期了。(我会在文章末尾出简单讲一下^__^)

    2. 创建两个事件:

     swift
    //给两个textField添加的点击事件,通过tag
     func getValue(sender: UITextField) {
            let tag = sender.tag
            let second = LWSecondViewController()
            second.initWithClosure(tag, dataList: ["我是选项1", "我是选项2", "我是选项3", "我是选项4", "我是选项5", "我是选项6"], closuer: getValueClosure)
            //页面跳转,从下往上
            self.presentViewController(second, animated: true, completion: nil)
        }
        //闭包,在SecondViewController中回调传值的事件
        func getValueClosure(tag: Int,string: String) {
            let tf = self.view.viewWithTag(tag) as! UITextField
            tf.text = string
        }

    3. LWSecondViewController.swift的具体代码:

    在上一节,我已经详细讲解了如何代码创建UITableView以及如何调用自定义UITableViewCell和自定义UITableCell的制作,这里我就不再一一赘述。

    1. 变量声明跟初始化

    swift
    
    private let cellId = "DemoListID"
    
        //声明一个闭包
        private var myClosure: sendValueClosure?
        private var myTag: Int?
        private var dataList = [String]()
        //下面的方法需要传入上个界面的someFunctionThatAClosure函数指针
        func initWithClosure(tag: Int,dataList: [String],closuer: sendValueClosure?) {
            //讲函数指针赋值给myClosure闭包,该闭包中覆盖了someFunctionThatTakesAClosure函数中的局部变量等引用
            self.myTag = tag
            self.dataList = dataList
            self.myClosure = closuer
        }
    
        override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
            super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
    
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.view.backgroundColor = UIColor.whiteColor()
            let tableList = UITableView(frame: CGRectMake(0, 30, self.view.frame.width, self.view.frame.height))
            let nib = UINib(nibName: "DemoListCell", bundle: nil) //Cell文件名
            tableList.registerNib(nib, forCellReuseIdentifier: cellId)
            tableList.delegate = self
            tableList.dataSource = self
            tableList.reloadData()
            self.view.addSubview(tableList)
        }

    2. 有UITableView直接要写UITableViewDelegate和UITableViewDataSource的代理

    • 今天告诉大家另外一种方式,使用扩展在LWSecondViewController的类的外面添加
    • 在UITableView的点击事件中调用闭包,将当前的Cell的值传递给回LWRootViewController
    swift
    
    extension LWSecondViewController: UITableViewDataSource {
        func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return 1
        }
    
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return self.dataList.count
        }
    
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCellWithIdentifier(self.cellId, forIndexPath: indexPath) as! DemoListCell
            //cell.cellImg.image = UIImage(named: powerData[indexPath.row][2])
            cell.cellLabel.text = self.dataList[indexPath.row]
            return cell
        }
    
    }
    
    extension LWSecondViewController: UITableViewDelegate {
        func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
        {
            let index = indexPath.row
            let string = self.dataList[index]
            if let closure = self.myClosure {
                closure(tag: self.myTag!,string: string)
            }
            self.dismissViewControllerAnimated(true, completion: nil)
        }
    }

    ok!就是这么简单,回复让我知道 (^__^)

    TIPS

    添加事件小贴士

    1. 代码添加事件
      swift
       item.addTarget(self, action: "click:", forControlEvents: UIControlEvents.TouchUpInside)
    2. action: "funcName:" 和 action: Selector("funcName")的区别
      • 第一种可以讲当前的item当做对象传递给事件:funcName(sender: AnyObject)
      • 第二种不可以:funcName()

    这里跟大家讲一下生命周期:

    1. viewDidLoad 页面已经载入完毕,可以显示了
    2. viewWillAppear 页面界面将要显示
    3. viewDidAppear 页面界面已经展示出来
    4. viewWillDisappear 界面即将消失(可以做一下小动画在界面消失前)
    5. viewDidDisAppear 界面消失不见,但还是在内存中
    6. viewDidUnload 界面已经从内存中释放出来
    原文链接:http://www.jianshu.com/p/f5cc032e74f5
    展开全文
  • 目前随着公司开发模式的变更,swift也显得越发重要,相对来说,swift语言更加简洁,严谨.但对于我来说,感觉swift细节的处理很繁琐,可能是还没适应的缘故吧.基本每写一句代码,都要对变量的数据类型进行判断,还要进行强转...
  • Swift语言是苹果全力推广的语言,相对于苹果的Objective C(后面简称OC),Swift语言容易学习,语法简洁。Swift语言的很多特性不是完全新创造,借鉴了许多其他语言的语法特点。例如借鉴c#的值/引用二分类型。单继承,...
  • 通常来说将C++对象做为参数传递给Objective-C的方法中是比较方便的。 举例来说,比如我们有一个NSString的初始化方法,我们希望传递一个std::string做为参数传进去。 只要你传递了对象的指针,事情就完成了,...
  • 文章可能写得有点晚了,Swift语言已经诞生很久的时间了,现在它已经挤掉了OC很大的市场了,但是,总是存在很多老项目,或者是第三方库还没有完全翻译成Swift,因此,混编还是需要的。虽然现在详解可能有点晚,不过...
  • Swift中,类型分为两类:第一种是值类型,该类型的每个实例持有数据的副本,并且该副本对于每个实例来说是独一无二的一份,比如结构体(struct)、枚举(enum)、元组(tuple)都是值类型。第二种是引用类型,该...
  • * Swift使用自动引用计数(ARC)来管理应用程序的内存使用。这表示内存管理已经是Swift的一部分,在大多数情况下,你并不需要考虑内存的管理。当实例并不再被需要时,ARC会自动释放这些实例所使用的内存。 另外需要...
  • 需求 原生的UIButton的点击事件唯一的参数就是UIButton本身,我们通常使用UIButton自带的tag来使用不同的参数,在简单的业务场景下,通过tag都是可以满足需求的,但是在某些业务复杂的情况下,tag显得有些无力了,...
  • 作者:fengsh998 ... 转载请注明出处 ...如果觉得文章对你有所帮助,请通过留言或关注微信公众帐号fengsh998来支持我,谢谢...Swift使用自动引用计数(ARC)来管理应用程序的内存使用。这表示内存管理已经是Swift的一部
  • swift Array 数组 总结

    2015-09-09 17:59:43
    swift刚一出现的时候, 数组是作为引用类型出现的, 虽然作为一个结构体, 但是更像是类的对象的性质, 这可见数组的这个结构体的底层不单单是像C语言和OC中在栈区开辟空间去存储值类型那么简单, 猜测也是要去堆区开辟...
  • Swift入门笔记(一)

    2018-09-25 13:00:18
    Swift 语言与之前的Objectiv-C可共存(可以调用OC写的代码库,嵌入OC代码之中) Swift 语言不向下兼容,3.0以上逐渐稳定,相互兼容 Swift3.0 与 2.x语法不一致,不能兼容与混用 Swift从Python和Javascript中学了设计...
  • 值类型和引用类型只在之前的面试过程中碰到过,最近学习过程中,在体验 swift 的面向对象特性的时候,在 struct 和 class 中再次碰到了这个问题,说一说自己的收获吧。 值类型和引用类型在 OC 里面理解起来应该更...
  • Swift中的一些关键字

    2014-10-04 14:56:17
    以下关键字关于引用传参、属性、修改成员变量、静态变量、索引和构造函数重载 读过The Swift Programming Language的人都能看得出,我上面的这几个说法全不是apple的习惯用语。之所以这么起题目是因为很多最近转...
  • 最近在学swift,本以为多是语法与oc不同,而且都是使用相同的cocoa框架,相同的API,但是或多或少还是有些坑在里,为了避免以后再踩,在这里记下了,以后发现新的坑,也会慢慢在这里加上 [TOC] 1.main文件去...
  • 使用Cocoa现有的设计模式,有助于开发者编写一款拥有合理设计思路和良好的可扩展性应用的有效方法之一。大部分这些模式都依赖于在Objective-C中定义的类。由于Swift与Objective-C之间存在互用性,所以你依然可以在...
  • Swift使用自动引用计数(ARC)来管理应用程序的内存使用。这表示内存管理已经是Swift的一部分,在大多数情况下,你并不需要考虑内存的管理。当实例并不再被需要时,ARC会自动释放这些实例所使用的内存。 另外需要...
1 2 3 4 5 ... 8
收藏数 142
精华内容 56