#function swift

2015-12-15 16:41:42 aa574202228 阅读数 1303

概述:在刚学习Swift的时候,我都是盲目的找资料,这里找一点那里找一点,没有统一的学习资料。正好这段时间公司没有什么事情做,领导又让我学习一下Swift编程,索性我就跟着Apple官方的推荐的《The Swift Programming Language》书籍来系统的学习一下Swift。也建议想学习Swift的同学认真跟着这本书去学习,因为这本书真的很不错!      我这里自己的总结都是在本书中学到的!

1、Defining and Calling Functions   定义和调用函数

func sayHello01(personName:String)->String{
   let greenting = "hello \(personName)"
   return greeting ;
}
print(sayHello01("张三"))
我之前学习过java、javascript,这和swift声明函数的方式有点相似,有时候容易就写成Javascript的函数声明了,不过多敲几遍就记住了,也不容易混淆。


</pre><p>2、Function whitout Parameters   没有参数的函数</p><pre name="code" class="objc">func sayHello02()->String{
<p class="p1"><span class="s1">   return</span><span class="s2"> </span><span class="s3">"Hello World!"</span></p>}

3、Function with Multiple Parameters  含有多个参数的函数

func sayhello03(personName:String,alreadyGreeted:Bool)->String{
    if alreadyGreeted{
       return "haved say Hello!"
    }else{
       return "Hello \(personName)!"
    }
}
sayhello02("张三", alreadyGreeted: false)
注意:在调用一个多参数的函数时,除了第一个不需要写形参外,后面的参数必须要写形参,否则,编译会报错!但是也有方法可以不需要写形参,继续往下看。


4、Function whitout Return Values 没有返回值的函数

func sayHello04(personName:String){
    print("Hello \(personName)!")
}
sayHello04("Jan")


5、Function with Multiple Return Values   多个返回值的函数

func minMax(array:[Int])->(min:Int,max:Int){
    var min = 0 ;
    var max = 0 ;
    for number in array{
        if number<min{
            min = number
        }
        if number > max {
            max = number
        }
    }
    return (min ,max)
}
var result = minMax([10,2,13,29,99,-11])
print("The min number is \(result.min)")
print("The max number is \(result.max)")
注意:这里涉及到元组的内容,如果对元组不熟悉的同学,可以先看看元组的定义和使用方法。

6、Optional Tuple Return Type  可选元组返回类型

func minMax1(array:[Int])->(min:Int,max:Int)?{
    var min = 0 ;
    var max = 0 ;
    for number in array{
        if number<min{
            min = number
        }
        if number > max {
            max = number
        }
    }
    return (min ,max)
}
说明:可选元组返回类型指的是可以返回元组,也可以返回nil。


7、Specifying External Parameter Names   指定外部名称

func sayHello05(to person:String, and anOtherPerson:String){
    print("Hello \(person) and \(anOtherPerson)")
}
sayHello05(to: "张三", and: "李四 !")

说明:这样的函数写法我们可以理解为语义化,在官方的解释是:The use of external parameter names can allow a function to be called  in an expressive,sentence-like manner,while still providing a function body that is readable and clear in intent.     意思是说外部参数使得函数表达的意思更丰富,使得函数体看起来就知道该函数的意图。

8、Omitting external Parameter Names    忽略外部参数的名称

func sayHello06(personName:String,_ anOtherPersonName:String){
  print("Hello \(personName) and \(anOtherPersonName)")
}
sayHello06("张三", "李四")
说明:我们可以使用下划线‘_’来忽略外部参数的名称,在调用的时候可以不用写外部参数的名称,正如上3所述,我们可以是改方法来声明函数,在调用的时候就不需要写形参的名称。


9、Default Parameter Values 默认的参数值

func sayHello07(personName:String="张三"){
    print("Hello \(personName)")
}
sayHello07()


10、Variadic Parameters   可变的参数(可能有多个参数)

func sayHello07(personName:String...){
    var allName:String = "" ;
    for name in personName{
       allName+=name
    }
    print("Hello \(allName)")
}
sayHello07("A","B")
说明:这里使用的‘...’来表示同一类型的参数可能有多个。





 
























2018-01-15 20:17:00 weixin_30564901 阅读数 95

OC Swift  
__FILE__ #file 打印当前文件路径,c字符串
__LINE__ #line 打印当前行号,整数
__FUNCTION__ #function 打印当前函数或方法 

转载于:https://www.cnblogs.com/10-19-92/p/8289749.html

2020-04-13 13:48:01 p15097962069 阅读数 217

本文翻译自:#ifdef replacement in the Swift language

In C/C++/Objective-C you can define a macro using compiler preprocessors. 在C / C ++ / Objective-C中,您可以使用编译器预处理程序定义宏。 Moreover, you can include/exclude some parts of code using compiler preprocessors. 此外,您可以使用编译器预处理程序包含/排除部分代码。

#ifdef DEBUG
    // Debug-only code
#endif

Is there a similar solution in Swift? Swift中有类似的解决方案吗?


#1楼

参考:https://stackoom.com/question/1ciLr/Swift语言中的-ifdef替换


#2楼

There is no Swift preprocessor. 没有Swift预处理器。 (For one thing, arbitrary code substitution breaks type- and memory-safety.) (一方面,任意代码替换都会破坏类型和内存安全性。)

Swift does include build-time configuration options, though, so you can conditionally include code for certain platforms or build styles or in response to flags you define with -D compiler args. 但是,Swift确实包含了构建时配置选项,因此您可以有条件地包含某些平台或构建样式的代码,或者响应使用-D编译器args定义的标志。 Unlike with C, though, a conditionally compiled section of your code must be syntactically complete. 但是,与C语言不同,代码的条件编译部分必须在语法上完整。 There's a section about this in Using Swift With Cocoa and Objective-C . Swift与Cocoa和Objective-C结合使用中有关于这一部分的内容。

For example: 例如:

#if os(iOS)
    let color = UIColor.redColor()
#else
    let color = NSColor.redColor()
#endif

#3楼

Yes you can do it. 是的,你可以做到。

In Swift you can still use the "#if/#else/#endif" preprocessor macros (although more constrained), as per Apple docs . 在Swift中,按照Apple docs的规定 ,您仍然可以使用“#if /#else /#endif”预处理器宏(尽管有更多限制)。 Here's an example: 这是一个例子:

#if DEBUG
    let a = 2
#else
    let a = 3
#endif

Now, you must set the "DEBUG" symbol elsewhere, though. 现在,您必须在其他位置设置“ DEBUG”符号。 Set it in the "Swift Compiler - Custom Flags" section, "Other Swift Flags" line. 在“ Swift编译器-自定义标志”部分的“其他Swift标志”行中进行设置。 You add the DEBUG symbol with the -D DEBUG entry. 您将DEBUG符号与-D DEBUG条目一起添加。

As usual, you can set a different value when in Debug or when in Release. 与往常一样,您可以在Debug或Release中设置不同的值。

I tested it in real code and it works; 我用真实代码对其进行了测试,并且可以正常工作。 it doesn't seem to be recognized in a playground though. 它似乎在操场上似乎未被认可。

You can read my original post here . 您可以在这里阅读我的原始帖子。


IMPORTANT NOTE: -DDEBUG=1 doesn't work. 重要说明: -DDEBUG=1不起作用。 Only -D DEBUG works. -D DEBUG有效。 Seems compiler is ignoring a flag with a specific value. 似乎编译器正在忽略具有特定值的标志。


#4楼

In many situations, you don't really need conditional compilation ; 在很多情况下,您实际上并不需要条件编译 you just need conditional behavior that you can switch on and off. 您只需要可以打开和关闭的条件行为即可。 For that, you can use an environment variable. 为此,您可以使用环境变量。 This has the huge advantage that you don't actually have to recompile. 这具有巨大的优势,您实际上不必重新编译。

You can set the environment variable, and easily switch it on or off, in the scheme editor: 您可以在方案编辑器中设置环境变量,并轻松地将其打开或关闭:

在此处输入图片说明

You can retrieve the environment variable with NSProcessInfo: 您可以使用NSProcessInfo检索环境变量:

    let dic = NSProcessInfo.processInfo().environment
    if dic["TRIPLE"] != nil {
        // ... do secret stuff here ...
    }

Here's a real-life example. 这是一个真实的例子。 My app runs only on the device, because it uses the music library, which doesn't exist on the Simulator. 我的应用程序仅在设备上运行,因为它使用的音乐库在模拟器上不存在。 How, then, to take screen shots on the Simulator for devices I don't own? 那么,如何在模拟器上为我不拥有的设备拍摄屏幕截图? Without those screen shots, I can't submit to the AppStore. 没有这些屏幕截图,我将无法提交到AppStore。

I need fake data and a different way of processing it . 我需要伪造数据其他处理方式 I have two environment variables: one which, when switched on, tells the app to generate the fake data from the real data while running on my device; 我有两个环境变量:一个在打开时告诉应用程序在设备上运行时从真实数据生成假数据; the other which, when switched on, uses the fake data (not the missing music library) while running on the Simulator. 另一种是在模拟器上运行时打开时使用伪造的数据(而不是缺少的音乐库)。 Switching each of those special modes on / off is easy thanks to environment variable checkboxes in the Scheme editor. 通过使用方案编辑器中的环境变量复选框,可以轻松打开/关闭这些特殊模式。 And the bonus is that I can't accidentally use them in my App Store build, because archiving has no environment variables. 而且好处是,我不会在App Store构建中意外使用它们,因为归档没有环境变量。


#5楼

As of Swift 4.1, if all you need is just check whether the code is built with debug or release configuration, you may use the built-in functions: 从Swift 4.1开始,如果只需要检查代码是使用调试还是发布配置构建的,则可以使用内置函数:

  • _isDebugAssertConfiguration() (true when optimization is set to -Onone ) _isDebugAssertConfiguration() (当优化设置为-Onone时为-Onone
  • _isReleaseAssertConfiguration() (true when optimization is set to -O ) _isReleaseAssertConfiguration() (将优化设置为-O时为true) (not available on Swift 3+) (不适用于Swift 3+)
  • _isFastAssertConfiguration() (true when optimization is set to -Ounchecked ) _isFastAssertConfiguration() (当优化设置为-Ounchecked时为-Ounchecked

eg 例如

func obtain() -> AbstractThing {
    if _isDebugAssertConfiguration() {
        return DecoratedThingWithDebugInformation(Thing())
    } else {
        return Thing()
    }
}

Compared with preprocessor macros, 与预处理器宏相比,

  • ✓ You don't need to define a custom -D DEBUG flag to use it ✓您无需定义自定义-D DEBUG标志即可使用它
  • ~ It is actually defined in terms of optimization settings, not Xcode build configuration 〜实际上是根据优化设置而不是Xcode构建配置定义的
  • ✗ Undocumented, which means the function can be removed in any update (but it should be AppStore-safe since the optimizer will turn these into constants) ✗未记录,这意味着该功能可以在任何更新中删除(但它应该是AppStore安全的,因为优化程序会将其转换为常量)

  • ✗ Using in if/else will always generate a "Will never be executed" warning. in在in / if / else中使用将始终生成“将永远不会执行”警告。


#6楼

As stated in Apple Docs Apple Docs中所述

The Swift compiler does not include a preprocessor. Swift编译器不包含预处理器。 Instead, it takes advantage of compile-time attributes, build configurations, and language features to accomplish the same functionality. 相反,它利用编译时属性,构建配置和语言功能来实现相同的功能。 For this reason, preprocessor directives are not imported in Swift. 因此,预处理器指令不会导入Swift中。

I've managed to achieve what I wanted by using custom Build Configurations: 通过使用自定义构建配置,我设法实现了想要的目标:

  1. Go to your project / select your target / Build Settings / search for Custom Flags 转到项目/选择目标/构建设置/搜索自定义标志
  2. For your chosen target set your custom flag using -D prefix (without white spaces), for both Debug and Release 对于所选目标,使用-D前缀(不带空格)设置调试和发布的自定义标志
  3. Do above steps for every target you have 对您拥有的每个目标执行上述步骤

Here's how you check for target: 检查目标的方法如下:

#if BANANA
    print("We have a banana")
#elseif MELONA
    print("Melona")
#else
    print("Kiwi")
#endif

在此处输入图片说明

Tested using Swift 2.2 使用Swift 2.2测试

2015-05-24 18:29:32 chenglei9128 阅读数 489
<pre name="code" class="objc">//
//  main.swift
//  FunctionsDemo
//
//  Created by 程磊 on 15/5/23.
//  Copyright (c) 2015年 chenglei. All rights reserved.
//

import Foundation

//1.函数的定义与调用
//以 func 作为前缀,返回箭头 -> 表示函数的返回类型
func sayHello(name:String) -> String {
    let greeting = "Hello" + name;
    return greeting;
}

println(sayHello("bielian"))

//1.1函数的参数与返回值
func minusResult(start: Int, end: Int) -> Int {
    return end - start;
}

println(minusResult(1,10));

//1.2无参函数
func sayHelloWorld() -> String {
    return "Hello World"
}

//1.3无返回值函数
/*
    严格上来说,虽然没有定义返回值,sayGoodBye函数依然返回了值。
    没有定义返回类型的函数会返回特殊的值,叫Void。它其实是一个空的元组(tuple),没有任何元素,可以写成()
*/
func sayGoodBye(name: String){
    println("GoodBye \(name)");
}

println(sayGoodBye("bielian"))

//1.4多重返回值函数
func count(string: String) -> (vs: Int, cs: Int, os:Int) {//返回一个元组
    var vowels = 0, consonants = 0, others = 0
    for character in string {
        switch String(character).lowercaseString {
            case "a","e","i","o","u":
                ++vowels;
            case "b","c","d","f","g","h":
                ++consonants;
            default:
                ++others;
        }
    }
    return (vowels, consonants, others);
}

let total = count("Hello!")
println("\(total.vs) vowels, and\(total.cs) consonants and\(total.os)others")

//2  函数参数名
//2.1 外部参数名

//Demo:把两个字符串联在一起,演示使用外部参数的好处
/*
    不使用外部参数
*/
//func join(s1: String, s2: String, joiner: String) -> String {
//    return s1 + joiner + s2;
//}
//println(join("Hello","World",","))

//使用外部参数
func join(string s1:String, toSting s2: String, withJoiner joiner: String) -> String {
    return (s1 + joiner + s2);
}
println(join(string: "hello", toSting: "world", withJoiner: ","));

//2.2 简写外部参数名
//如果你需要提供外部参数名,但是局部参数名已经定义好了,那么你不需要写两次这些参数名。相反,只写一次参数名,并用井号(#)作为前缀就可以了。这告诉Swift使用参数名作为局部和外部参数名。
func containsCharacter(#string: String, #charactertoFind: Character) -> Bool {
    for character in string {
        if character == charactertoFind {
            return true
        }
    }
    return false
}

//这样定义参数名,使得函数体更为可读,清晰,同时也可以以一个不含糊的方式被调用
let containsCon = containsCharacter(string: "qwertyuiop", charactertoFind: "y")
println(containsCon)

//2.3 默认参数值
//你可以在函数体中为每个参数定义默认值。当默认值被定以后,调用这个函数时可以略去这个参数
func join2(string s1:String, toString s2:String, withJoiner joiner:String = ",") ->String {
    return s1 + joiner + s2
}

let str1 = join2(string: "hello", toString: "world", withJoiner: "-");//指定第三个参数
println(str1);

let str2 = join2(string: "hello", toString: "world")
println(str2)

//2.4 默认参数的外部参数名
func join2(s1: String, s2: String, joiner: String = " ") -> String {
    return s1 + s2 + joiner
}
let str3 = join2("hello", "world", joiner: "=")


//3.可变参数
//传入可变参数的值在函数体内当做这个类型的一个数组。例如,一个叫做numbers 的 Double... 型可变参数,在函数体内可以做一个叫numbers的Double[]型的数组常量。
//一个函数最多能有一个可变参数
//可变参数必须放在参数表中最后的位置
func aritheticMean(numbers: Double...) -> Double {
    var total: Double = 0;
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
println(aritheticMean(1.1, 1.3, 1.5))
println(aritheticMean(0.3, 0.5, 0.9))

//4 常量参数与变量参数
//函数参数默认是常量。但有时候,如果函数中传入的参数可以修改的话将很有用。你可以通过指定一个或者多个参数为变量参数,从而避免自己在函数中定义新的变量,变量参数不是常量,你可以在函数中把它当做新的可以修改的副本来使用。
//通常在参数名前加关键字 var 来定义变量参数
func alignRight(var string: String, countNum: Int, pad:Character) -> String {//想要指定变量参数在其参数名前面加关键字var
    let amountToPad = countNum - count(string)
    for _ in 1...amountToPad {
        string = String(pad) + string
    }
    return string
}

let originalString = "Hello"
let paddedString = alignRight(originalString, 10, "-")
println("originalString:" + originalString)
println("paddedString" + paddedString)

//5 输入输出参数
//变量参数,正如上面所述,仅仅能在函数体内被更改。如果你想要一个函数可以修改参数的值,并且想要这些修改在函数调用结束后仍然存在,那么就应该把这个参数定义为输入输出参数(In-Out Parameters).
 //定义一个输入输出参数,在参数的前面加inout关键字
//输入输出参数不能有默认值,而且可变参数不能用inout标记,如果你用inout标记一个参数,这个参数就不能被var 或者 let标记
func swapTwoInts(inout a: Int, inout b: Int) {
    let temp = a
    a = b
    b = temp
}

//只能传入一个变量作为输入输出参数
var someInt = 3
var anotherInt = 7

//当传入的参数作为输入输出参数时,需要在参数的前面加&,表示这个值可以被函数修改
swapTwoInts(&someInt, &anotherInt)
println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")

//6.函数类型
//分三步: 1.定义函数;2.声明函数类型变量或常量;3.给函数类型变量赋值
func addToInts(a: Int, b: Int) -> Int {
    return a + b;
}

//2.声明函数类型变量,如下声明了一个叫做mathFunction的变量,类型是'一个有两个Int型的参数并返回一个Int型的值的函数',这里定义的参数类型以及返回值类型与上面定义的函数参数类型以及返回值类型都是一一对应的
var mathFunction: (Int, Int) -> Int

//3.给函数类型变量赋值
mathFunction = addToInts;

//可以讲上述步骤合并
//(1)
var mathFunction2: (Int, Int) -> Int = addToInts;
//(2)
var mathFunction3 = addToInts

//4.使用
println("Result: \(mathFunction(2,3)) ")
println("Result2: \(mathFunction2(2,3)) ")
println("Result3: \(mathFunction3(2,3)) ")



//Swift中调用C或者OC函数,必须要建立一个.h作为桥梁,其命名格式为"项目名字-Bridging-Header.h",在文件中引入相对应的文件或者方法,如果是C函数,则直接将方法名引入即可,如果是OC函数,则直接import导入头文件即可
//Swift中调用C函数
desc1()

//Swift中调用OC函数
var funcClass = FuncBlock()  //拿到OC类对象
funcClass.desc2()


//6.1函数类型作为参数类型
func printMathResult(mathFun: (Int, Int) -> Int, a: Int, b: Int) {
    println("Result4: \(mathFun(a,b))")
}

printMathResult(addToInts, 3, 4)


//6.2 函数类型作为返回类型
func stepForward(input: Int) -> Int {
    return input + 1
}

func stepBackward(input: Int) -> Int {
    return input - 1
}

//返回一个函数类型,第一个箭头指向对应要返回的函数类型
func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    return backwards ? stepBackward : stepForward
}

var currentValue = 3
//let moveNearTozero:(Int) -> Int = chooseStepFunction(currentValue > 0)//原型
let moveNearTozero = chooseStepFunction(currentValue > 0)
println("moveNearTozero = \(moveNearTozero)")//并没有调用其中的函数
println("Result5 = \(moveNearTozero(6))")

//嵌套函数
func chooseStepFunction2(backwards: Bool) -> (Int) -> Int {
    func stepForward2(input: Int) -> Int {
        return input + 1
    }
    
    func stepBackward2(input: Int) -> Int {
        return input - 1
    }
    return backwards ? stepBackward2 : stepForward2 //返回函数类型
}
var currentValue2 = -4
let moveNearTozero2 = chooseStepFunction2(currentValue2 > 0)
println("Result6 = \(moveNearTozero2(10))")


//8.闭包
/*
    表达式语法一般形式如下:
    {(parameters) -> returnType in 
        statements
    }
*/
//8.1闭包表达式

//不使用闭包
let names = ["Bielian","Harry","Howard","James","Young"]
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(backwards)
println("reversed = \(reversed)")

//使用闭包
//闭包的函数体部分由关键字in引入。该关键字表示闭包的参数和返回值类型定义已经完成,闭包函数即将开始
reversed = names.sorted({(s1: String,s2: String) -> Bool in
    return s1 > s2
})
println("reversed = \(reversed)")

//根据上下文推断类型
reversed = names.sorted({(s1, s2) in return s1 > s2})
println("reversed = \(reversed)")

//8.2单表达式闭包隐式返回
//如果闭包体中只有一个表达式,那么return关键字可以省略
reversed = names.sorted({(s1, s2) in s1 > s2})
println("reversed = \(reversed)")

//8.3参数名称缩写
//Swift自动为内联函数提供了函数名称缩写功能,可以直接通过$0、$1、$2来顺序调用闭包的函数
//如果闭包函数表达式中使用参数名称缩写,可以在闭包参数列表中省略对其的定义,in关键字也可以省略
reversed = names.sorted({$0 > $1})
println("reversed = \(reversed)")

//8.4运算符函数
//Swift的String类型定义了关于大于号(>)的字符串实现
reversed = names.sorted(>)
println("reversed = \(reversed)")

//8.5尾随闭包
//如果需要将一个很长的闭包表达式(以至于不能在一行中进行书写时)作为最后一个参数传递给函数,可以使用尾随闭包来增强函数的可读性。尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用
reversed = names.sorted(){
    $0 > $1
}
println("reversed = \(reversed)")


//8.6捕获值
func makeIncrementor(forIncrement amount: Int) -> ()->Int {
    var runningTotal = 0
    
    //incrementor函数并没有获取任何参数,但是在函数体内访问了runningTotal和amount变量。这是因为其通过捕获在包含他的函数体内已经存在的runningTotal和amount变量而实现
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}
let incrementByTen = makeIncrementor(forIncrement: 10)
//因为每次调用该函数的时候都会修改runningTotal的值,incrementor捕获了当前runningTotal变量的引用,而不是仅仅复制该变量的初始值。捕获一个引用保证了当makeIncrementor结束时候并不会消失,也保证了当下一次执行incrementor函数时,runningTotal可以继续增加
println(incrementByTen())   //10
println(incrementByTen())   //20
println(incrementByTen())   //30

let incrementByOne = makeIncrementor(forIncrement: 1)
println(incrementByOne())

//8.7闭包是引用类型
//上面的例子中,incrementByOne和ByTen是常量,但是这些常量指向的闭包仍然可以增加其捕获的变量值。这是因为函数和闭包都是引用类型

//如果将闭包赋值给了两个不同的常量/变量,两个值实际上指向的还是同一个闭包,所以仍然会改变其捕获的变量值
let alsoIncrementByTen = incrementByTen
println(alsoIncrementByTen())   //40



                                    

swift3.0 自定义Log

阅读数 432