2018-06-20 14:49:13 qq_37269542 阅读数 669
  • Swift 2.1 基础实操高清视频教程

    我们通过一些代码片段学习Swift中的constant和variable、各种基本types和tuple以及Swift中重要的语言特性之一: type inference。并录制了泊学高清视频,同步搭配了泊阅文档,为开发者朋友们的学习提供了一种全新的学习视觉享受。

    8450 人正在学习 去看看 崔轶

最近因为项目需求需要对项目代码进行升级,从之前的swift2.0版本升级到swift4.1版本。现将升级过程中遇到的一些语法变化与大家分享一下,希望会对大家有所帮助,

Swift 2.0 --> Swift 4.0

1.self.edgesForExtendedLayout = UIRectEdge.None  -->  self.edgesForExtendedLayout = UIRectEdge.init(rawValue: 0)

2.UINavigationBar.appearance().titleTextAttributes=NSDictionary(object:UIColor.whiteColor(), forKey:NSForegroundColorAttributeName) as? [String : AnyObject]  -->  UINavigationBar.appearance().titleTextAttributes = [NSAttributedStringKey.foregroundColor : UIColor.white]
[NSForegroundColorAttributeName: UIColor.white]  -->  [NSAttributedStringKey.foregroundColor : UIColor.white]

3.使用Alamofire获取statusCode: res.result.error?.code  -->  res.response?.statusCode

4.CGRectZero  -->  CGRect.zero

5.从其他线程回到主线程的方法:
   dispatch_async(dispatch_get_main_queue(), { () -> Void in 

   })		--> 

   DispatchQueue.main.async {

   }

 6.	UILabel获取字体大小的属性boundingRectWithSize的改变:
 	let size = body.boundingRectWithSize(CGSizeMake(CGFloat(w-20), CGFloat(10000.0)),options:NSStringDrawingOptions.UsesLineFragmentOrigin,  attributes: [NSFontAttributeName:UIFont.systemFontOfSize(12)],context:nil)     -->
 	let size = body.boundingRect(with: CGSize.init(width: CGFloat(Constants.SCREEN_W - 20), height: CGFloat(10000.0)),options:NSStringDrawingOptions.usesLineFragmentOrigin,  attributes:[NSAttributedStringKey.font : UIFont.systemFont(ofSize: 12)],context:nil)

 7.let myMutableString = NSMutableAttributedString(string: (!body.isEmpty ? body : "") , attributes: [NSFontAttributeName:UIFont(name: "HelveticaNeue", size: 12.0)!])	 -->  
   let myMutableString = NSMutableAttributedString.init(string: (!body.isEmpty ? body : ""), attributes: [NSAttributedStringKey.font : UIFont(name: "HelveticaNeue", size: 12.0)!])
 
 8.let paragraphStyle = NSMutableParagraphStyle()
 	myMutableString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle,range: NSRange(location:0,length:myMutableString.length))   -->
 	myMutableString.addAttribute(NSAttributedStringKey.paragraphStyle, value: paragraphStyle, range: NSRange.init(location: 0, length: myMutableString.length))

 9.SDWebImage的用法改变:
   headImg.sd_setImageWithURL(NSURL(string: self.images[indexPath.row] as! String), placeholderImage: UIImage(named: "default_logo"))     -->   
   headImg.sd_setImage(with: NSURL.init(string: self.images[indexPath.row] as! String)! as URL, placeholderImage: UIImage(named: "default_logo"), options: .retryFailed, completed: nil)

10. UIApplication.sharedApplication().keyWindow?.windowLevel = UIWindowLevelStatusBar    -->   UIApplication.shared.keyWindow?.windowLevel = UIWindowLevelStatusBar

11. NSCalendarUnit.Day  -->   NSCalendar.Unit.day

12. var components = cal.components([NSCalendar.Unit.day, NSCalendar.Unit.month, NSCalendar.Unit.year, NSCalendar.Unit.weekOfYear, NSCalendar.Unit.hour, NSCalendar.Unit.minute, NSCalendar.Unit.second, NSCalendar.Unit.nanosecond], from: NSDate() as Date)
	components.setValue(components.month-3, forComponent: NSCalendar.Unit.month)  -->  components.setValue(components.month! - 3, for: .month)

13. formatter.stringFromDate(cal.dateFromComponents(components)!)  -->  formatter.string(from: cal.date(from: components)!)

14. string.characters.count  -->  string.count

15. string.stringByReplacingOccurrencesOfString(" ", withString: "")	-->	   string.replacingOccurrences(of: " ", with: "")

16. for i in str.characters {
	
	}         -->     
	for i in str {

	}

17. str.removeRange(index!)  -->   str.removeSubrange(index!)

18. let alertInputTelController = UIAlertController(title: title, message: "", preferredStyle: UIAlertControllerStyle.alert)
	alertInputTelController.addTextFieldWithConfigurationHandler {

	}	  -->   
	alertInputTelController.addTextField {

	}

19. addAttribute(NSForegroundColorAttributeName, value: UIColor.redColor(), range: NSRange.init(location: startIndex!, length: 1))   -->  
	attrString.addAttribute(.foregroundColor, value: UIColor.red, range: NSRange.init(location: startIndex!, length: 1))

20. tf.text?.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) != ""   --> 
	tf.text?.trimmingCharacters(in: NSCharacterSet.whitespaces) != ""     //检测textField中输入的字符去掉空格后是否为空的方法

21. kNewStoreInfo.setObject(tf.text!, forKey: key)   --> 
	kNewStoreInfo.setObject(tf.text!, forKey: key as NSCopying)

22. textView.text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())    -->   
	textView.text.trimmingCharacters(in: NSCharacterSet.whitespacesAndNewlines)

23. //将内容同步写到文件中去(Caches文件夹下)
        let cachePath = NSFileManager.defaultManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: .UserDomainMask)[0]
        let path = cachePath.URLByAppendingPathComponent("log.txt")
        appendText(path, string: "\(datestr) \(consoleStr)")     

        --> 

        let cachePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let path = cachePath.appendingPathComponent("log.txt")
        appendText(fileURL: path as NSURL, string: "\(datestr) \(consoleStr)")

24. FileManager.defaultManager().createFileAtPath(fileURL.path!, contents: nil, attributes: nil)  -->  
	FileManager.default.createFile(atPath: fileURL.path!, contents: nil, attributes: nil)

25. NSFileHandle.init(forWritingAtPath: fileURL.path!)   -->
	FileHandle.init(forWritingAtPath: fileURL.path!)

26. //找到末尾位置并添加
    fileHandle!.seekToEndOfFile()        
    fileHandle?.writeData(stringToWrite.dataUsingEncoding(NSUTF8StringEncoding)!)  -->
    fileHandle?.write(stringToWrite.data(using: String.Encoding.utf8)!)

27. string.componentsSeparatedByString(",")  -->   string.components(separatedBy: ",")

28. NSIndexPath(forRow: i, inSection: 0)  -->   NSIndexPath(row: i, section: 0)

29. NSComparisonResult.OrderedAscending  -->  ComparisonResult.orderedAscending

30. NSNotificationCenter.defaultCenter().postNotificationName("Notification_UploadImage", object: j)  -->
	NotificationCenter.default.post(name: NSNotification.Name(rawValue: "Notification_UploadImage"), object: j)

31. NSNotificationCenter.defaultCenter().postNotificationName("Notification_UploadImage", object: "error", userInfo: nil)  -->
	NotificationCenter.default.post(name: NSNotification.Name(rawValue: "Notification_UploadImage"), object: "error", userInfo: nil)

32. let startIndex =  Int("\(range.startIndex)") -->
	let startIndex =  Int("\(range.upperBound.encodedOffset)") - 1

33. // 单例模式
    class var sharedInstance: TreeNodeHelper {
        struct Static {
            static var instance: TreeNodeHelper?
            static var token: dispatch_once_t = 0
        }
        dispatch_once(&Static.token) { // 该函数意味着代码仅会被运行一次,而且此运行是线程同步
            Static.instance = TreeNodeHelper()
        }
        return Static.instance!
    }
    -->  

    //由于dispatch_once在Swift4.0也已经被废弃   通过给DispatchQueue添加扩展实现
    extension DispatchQueue { 
    private static var _onceTracker = [String]()
    public class func once(token: String, block: () -> ()) {
        objc_sync_enter(self)
        defer {
            objc_sync_exit(self)
        }
        if _onceTracker.contains(token) {
            return
        }
        _onceTracker.append(token)
        block()
    }
    
    func async(block: @escaping ()->()) {
        self.async(execute: block)
    }
    
    func after(time: DispatchTime, block: @escaping ()->()) {
        self.asyncAfter(deadline: time, execute: block)
    }
}
// 单例模式
    class var sharedInstance: TreeNodeHelper {
        
        struct Static {
            static var instance: TreeNodeHelper?
            static let _onceToken = NSUUID().uuidString
        }
        //由于dispatch_once在Swift4.0也已经被废弃  此处通过给DispatchQueue添加扩展实现
        DispatchQueue.once(token: Static._onceToken) { // 该函数意味着代码仅会被运行一次,而且此运行是线程同步
           Static.instance = TreeNodeHelper()
        }
        return Static.instance!
    }

34. let url = NSURL(string:urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)!)  -->
	let url = NSURL(string: urlString.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!)

35. dispatch_async(DispatchQueue.global(0, 0), {
                    
    })    -->   
    DispatchQueue.global().async {

    }
 
36. 在Google Maps SDK中有三个常量来表示每种类型,此属性必须设置成其中一个. 这些常量是:
	kGMSTypeNormal
	kGMSTypeTerrain
	kGMSTypeHybrid
	在使用时候的变化:
 	kGMSTypeNormal  -->  GMSMapViewType.normal

 	kGMSMarkerAnimationPop --> GMSMarkerAnimation.pop

37. let directionsData = NSData(contentsOfURL: directionsURL! as URL)  -->
	let directionsData = NSData(contentsOf: directionsURL as URL)

38. 使用Alamofire解析获取返回的error code值方法:
	res.result.error?.code   -->   res.result.error?._code


2017-05-23 15:28:58 ruiruistyle__ 阅读数 1813
  • Swift 2.1 基础实操高清视频教程

    我们通过一些代码片段学习Swift中的constant和variable、各种基本types和tuple以及Swift中重要的语言特性之一: type inference。并录制了泊学高清视频,同步搭配了泊阅文档,为开发者朋友们的学习提供了一种全新的学习视觉享受。

    8450 人正在学习 去看看 崔轶

 func fileSizeOfCache()-> Int {

        // 取出cache文件夹目录 缓存文件都在这个目录下

        let cachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first

        //缓存目录路径

        // 取出文件夹下所有文件数组

        let fileArr = FileManager.default.subpaths(atPath: cachePath!)

        //快速枚举出所有文件名 计算文件大小

        var size = 0

        for file in fileArr! {            

            // 把文件名拼接到路径中

            let path = (cachePath! as NSString).appending("/\(file)")

            // 取出文件属性

            let floder = try! FileManager.default.attributesOfItem(atPath: path)

            // 用元组取出文件大小属性

            for (abc, bcd) in floder {

                // 累加文件大小

                if abc == FileAttributeKey.size {

                    size += (bcd as AnyObject).integerValue

                }

            }

        }

        let mm = size / 1024 / 1024

        return mm

    }

  func clearCache() {

        // 取出cache文件夹目录 缓存文件都在这个目录下

        let cachePath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first

        // 取出文件夹下所有文件数组

        let fileArr = FileManager.default.subpaths(atPath: cachePath!)

        // 遍历删除

        for file in fileArr! {

            let path = (cachePath! as NSString).appending("/\(file)")

            if FileManager.default.fileExists(atPath: path) {

                do {

                    try FileManager.default.removeItem(atPath: path)

                } catch {

                    

                } 

            }

        }

    }


2016-06-29 21:14:05 wj610671226 阅读数 9453
  • Swift 2.1 基础实操高清视频教程

    我们通过一些代码片段学习Swift中的constant和variable、各种基本types和tuple以及Swift中重要的语言特性之一: type inference。并录制了泊学高清视频,同步搭配了泊阅文档,为开发者朋友们的学习提供了一种全新的学习视觉享受。

    8450 人正在学习 去看看 崔轶

如何快速将Swift2.0的项目过渡到Swift3.0

      今年WWDC之后,相信大家都已经更新到iOS10和Xcode8.0beta版本尝鲜了,其中包括SiriKit、新的语音识别框架SFSpeechRecognizer、通知框架(UserNotifications.framework、UserNotificationsUI.framework)等等都等待着我们去探索和发现呢!大笑

        我个人认为最先接触的必然是Swift3.0语法的变化了,想当初我们手把手用Swift2.0撸出的项目,后续必然会过渡到Swift3.0中,难道我们又要一行一行的去修改代码吗?想想就不开心大哭,下面介绍较快的方法吧项目过渡到Swift3.0中。

准备好Xcode8.0Beta,将我们之前的项目用Xcode8.0打开。打开之后Xcode会有一个提示下面我们跟着截图一起走吧。

1、这个提示是说:你的项目包含早期版本的Swift代码,询问你是否更新到Swift3


2、点击next

3、选择Swift3


4、这里选择我们需要更新代码的Targets


5、耐心等待


6、点击Save保存


在上面这张图中我们便可以清楚的看到Swift语法的变化,左边是最新的语法,右边是之前的语法版本

当然通过上面的操作只能把绝大部分的语法修改过来,但是有一些部分的代码需要我们根据自己的实际情况去修改它才能完全过渡到Swift3中。

比如:1、类似i++这样的代码需要手动修改为i += 1

   2、第三方的OC库,调用也可能发生一点点的改变,手动修改(高德地图)

   3、使用了C语言风格的for循环也需要自己修改

   ......自己去探索吧小伙伴大笑

总结Swift3中语法详细的变化参考文章:https://gold.xitu.io/entry/576bd4595bbb500059463426

一篇讲解Swift3.0变化的英文网站(个人感觉很不错):https://www.raywenderlich.com/135655/whats-new-swift-3

补:总结Swift语法变化的好文章 http://tech.glowing.com/cn/swift3/

适配 Swift 3 的一点小经验和坑:https://imtx.me/archives/2064.html




2017-10-18 18:23:24 bddzzw 阅读数 10275
  • Swift 2.1 基础实操高清视频教程

    我们通过一些代码片段学习Swift中的constant和variable、各种基本types和tuple以及Swift中重要的语言特性之一: type inference。并录制了泊学高清视频,同步搭配了泊阅文档,为开发者朋友们的学习提供了一种全新的学习视觉享受。

    8450 人正在学习 去看看 崔轶
/*
Swift 中的闭包有很多优化的地方
1 根据上下文推断参数和返回值的类型
2 从单行表达式闭包中隐式返回 可以省略return
3 可以使用简化的参数如 $0 $1 意为从0或者1开始
4 提供了尾随闭包的语法
*/
//语法   parameters参数 return 隐藏了
//{(parameters) -> return type in
//    parameters
//}
//最简单的闭包//省略in的
let b = {
    print("这也是闭包")
}

//用变量记录函数 (带参数的闭包)
//带有参数的闭包
//参数返回值 实现代码  {形参->返回值 in 代码}
//带参数待返回值的闭包
let countNum = {(num1:Int,num2:Int)->Int in
    return num1+num2;
}
let count1 = countNum(2,3)


//闭包的应用场景

/*异步执行完成回调  控制器之间的回调  自定义视图的回调*/

/*  以下代码需要在项目中的.Swift文件中完成
override func viewDidLoad() {
super.viewDidLoad()
loadData { (result) in
print("获取json信息\(result)")
}
// Do any additional setup after loading the view, typically from a nib.
}
func loadData(completion: @escaping (_ result: [String])->()) -> () {
DispatchQueue.global().async {
print("耗时操作\(Thread.current)")
Thread.sleep(forTimeInterval: 1.0);
let json=["12","23","34"]
DispatchQueue.main.async(execute: {
print("主线程\(Thread.current)")
completion(json)
})
}
}
结果为:耗时操作<NSThread: 0x600000277000>{number = 3, name = (null)}
主线程<NSThread: 0x604000075a80>{number = 1, name = main}
获取json信息["12", "23", "34"]
*/

//闭包表达式
let names = ["s","b","e","h","f"]

func backwards(a1:String,a2:String)->Bool{
    return a1<a2;
}
// public func sorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element]
var result = names.sorted(by:backwards)
print(result)

//参数名缩写
///以上代码还可以  Swift自动内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,$2来顺序调用闭包的参数。
var result1 = names.sorted(by:{$0<$1})
print(result1)

//作为一个函数接受两个String类型的参数并返回Bool类型的值Swift可以自动推断出您想使用大于号的字符串函数实现:
//运算符函数
var result2 = names.sorted(by:<)
print(result2)

//尾随闭包
//例子1  尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。

var result3 = names.sorted(){$0<$1}
print(result3)



//例子2
//此时点回车函数会变成中括号的形式 也就是说如果函数的最后一个参数是闭包,函数的参数可以提前结束
//        最后一个参数直接使用{}来包装闭包的代码
//        loadData1(completion: <#T##([String]) -> ()#>)
//以下两段代码相同只不过一个是使用尾随闭包的写法
/*func loadData(completion:@escaping (_ result:([String])->())->()){
    DispatchQueue.global().async {
        print("耗时操作\(Thread.current)")
        Thread.sleep(forTimeInterval: 1.0);
        let json=["12","23","34"]
        //以下两段代码相同只不过一个是使用尾随闭包的写法
        DispatchQueue.main.async{
            print("主线程\(Thread.current)")
            completion(json)
        }
        DispatchQueue.main.async(execute: {
            print("主线程\(Thread.current)")
            completion(json)
        })
        
    }
}
*/


良言一句三冬暖,恶语伤人六月寒。无论工作还是生活,都不要拿脾气当做与他人博弈的武器。即使侥幸一时赢了,最终也只是两败俱伤。一言一语间,完成的是沟通,体现的是修养。或许我们不能成为优秀的别人,却完全可以做更好的自己。
2016-08-16 14:10:26 Felicity294250051 阅读数 1162
  • Swift 2.1 基础实操高清视频教程

    我们通过一些代码片段学习Swift中的constant和variable、各种基本types和tuple以及Swift中重要的语言特性之一: type inference。并录制了泊学高清视频,同步搭配了泊阅文档,为开发者朋友们的学习提供了一种全新的学习视觉享受。

    8450 人正在学习 去看看 崔轶

关于Swift 3.0的具体使用指南大家可以去阅读Swift 3.0中文文档(Swift 3.0 中文文档)和Swift 3.0官网文档(Swift 3.0 官网文档

1.首当其冲的就是闭包的修改。

升级完Xcode8之后根据提示会默认帮你进行一些修改。但是修改完成还有500+多个错误很大一部分是闭包的修改,我的内心是这样的。

在Swift2.3中我们写闭包是这样写:

    //Swift 2.2
    typealias detailCollectBlock = (state:Bool)->Void

    var detailCollect:detailCollectBlock?

    func detailCollect(detailCollect:detailCollectBlock)
    {
        self.detailCollect = detailCollect
    }

    //在需要的时候调用
    self.detailCollect?(state:true)

    //
    controller.detailPraise({ (state) in
        model.isPraise = (state ? "1" : "0")
            })
    //Swift3中的 使用方法1 
    typealias detailCollectBlock = (Bool)->Void

    var detailCollect:detailCollectBlock?

    func detailCollect(detailCollect:@escaping detailCollectBlock)
    {
        self.detailCollect = detailCollect
    }
    //在需要的时候调用
    self.detailCollect?(true)

    //在上页面回调接收的时候的用法
    controller.detailPraise(detailPraise: { (<#Bool#>) in
         model.isPraise = (state ? "1" : "0")
            })

    //使用方法2
    typealias detailCollectBlock = (_ state:Bool)->Void

    var detailCollect:detailCollectBlock?

    func detailCollect(_ detailCollect:@escaping detailCollectBlock)
    {
        self.detailCollect = detailCollect
    }

    //在需要的时候调用
    self.detailCollect?(state:true)

    //
    controller.detailPraise({ (state) in
        model.isPraise = (state ? "1" : "0")
            })

这个时候大家应该就可以从代码中发现,swift3中需要定义闭包的时候不需要命名参数名,只需要告诉参数类型即可.

现在迁移我们也可以使用方法2,这时我们的参数在使用时还是省略的(就和2.2时使用相同),外部调用闭包的时候就不需要在修改了。这样可以减少很多工作量,因为项目中的闭包实在是太多了..

如果闭包不是在当前作用域内执行而是还要继续传递到别的函数里的话, 那就必须加上@escaping,本身的意思是逃逸的

别接收回调的地方也和swift2.2不同,回调方法中会有block的名字,但是没有参数名了(方法2中就没有名字啦),只有参数的类型,我们需要自己来定义参数的名称.

详情见SE-0103SE-0118

2.在Swift2.3中我们函数在被调用时的第一个参数名会被省略,除非在前面在此定义eq:

//这样才会在调用的时候显示参数名 swift2.2时
func addCollect(detailId detailId)

在Swift3中我们不需要在这样做了。会一直带有第一个参数名

3.UIControlState等的表示状态的常量 都变成了首字母小写

//Swift2.2
self.toolsView?.praiseButton.setImage(UIImage.init(named: "tool_icon_like_normal"), forState: .Normal)

self.phone?.componentsSeparatedByString() //swift2.2

//swift3
self.toolsView?.praiseButton.setImage(UIImage.init(named: "tool_icon_like_normal"), for: .normal)

self.phone?.components(separatedBy: "-") //swift3

这样做也是为了脱离OC冗长的方法命名,精简了语意,但是可读性还需要长时间的检验吧

3.使用NSDictionary的修改

dict.setObject(true, forKey: "state")
dict.setObject(num, forKey: "key")

在之前我们一直使用NSDictionary(<font color=gray>因为从OC转过来感觉还是NSarray和NSDictionary用起来顺手的</font> ),用来设置key的时候。现在需要添加NSCopying ,所以我都改成Dictionary啦哈哈。现在我们也应该在之后写代码的时候避免使用NSString,NSArray, NSDictionary等因为现在更加不方便了~~

4.泛型

//swift2.2
 var selectResult:PHFetchResult?

//swift3
 var selectResult:PHFetchResult<PHAsset>?

这个是项目中图片管理器所用到的,现在就是需要在PHFetchResult后面告诉它是什么类型,也可以是AnyObject
这个后面还需要详细的介绍。给自己挖个坑

5.没有了CGRectMake 改用CGRect.init来初始化或者我们写一个他的扩展.来模拟之前的CGRectmake

//用来代替,修改的CGRectMake
func CGRectMake(_ x:CGFloat,_ y:CGFloat,_ width:CGFloat,_ height:CGFloat)->CGRect
{
    return CGRect.init(x: x, y: y, width: width, height: height)
}

6.关于颜色的初始化方法UIColor.color都去掉了括号,并且color的后缀页去掉了,新添加了Url类,也是为了脱离OC的NSUrl吧.

7.GCD的改变 更加Swift化.

DispatchQueue.main.async {
    let controller = LoginViewController()
    self.present(controller, animated: true, completion: nil)
                }

其实GCD的用法没有太多的改变,只是写法变的更加Swift,去掉了之前C语言的形式,多写读多熟悉应该就好了。

9.NSString操作的变化

//swift2.2
   let ch = (pinYinString as NSString).character(at: 0)
//swift3
    let ch=pinYinString?.unicodeScalars[(pinYinString?.unicodeScalars.startIndex)!]

因为我需要取到拼音的首字母来进行排序,所以需要获取到首字母的ASCII码。所以使用NSString更方便。但是现在不能这样用了,所以我们只能使用Swift中的这个unicodeScalars来获取啦。

8.枚举变成了小写,自己定义的时候是大写当他变成.语法的时候Xcode页把它变成了小写

没有更多推荐了,返回首页