Swift中方法的多面性

虽然 Objective-C 的语法相对于其他编程语言来说写法有点奇怪,但是当你真正使用的时候它的语法还是相当的简单。下面有一些例子:

+ (void)mySimpleMethod
{
    // 类方法
    // 无参数
    // 无返回值
}

- (NSString *)myMethodNameWithParameter1:(NSString *)param1 parameter2:(NSNumber *)param2
{
    // 实例方法
    // 其中一个参数是 NSString 指针类型,另一个是 NSNumber 指针类型
    // 必须返回一个 NSString 指针类型的值
    return @"hello,world!";
}

相比而言,虽然 Swift 的语法看起来与其他编程语言有更多相似的地方,但是它也可以比 Objective-C 更加复杂和令人费解。

在继续之前,我需要澄清 Swift 中方法函数之间的不同,因为在本文中我们将使用这两个术语。按照 Apple 的Swift Programming Language Book里面的方法定义:

方法是与某些特定类型相关联的函数。类、结构体、枚举都可以定义实例方法;实例方法为给定类型的实例封装了具体的任务与功能。类、结构体、枚举也可以定义类型方法,类型方法与类型本身相关联。类型方法与 Objective-C 中的类方法(class methods)相似。

以上是长文慎读。一句话:函数是独立的,而方法是函数封装在类,结构或者枚举中的函数。

剖析 Swift 函数

让我们从简单的 “Hello,World” Swift 函数开始:

func mySimpleFunction() {
    println("hello,world!")
}

如果你曾在 Objective-C 之外的语言进行过编程,上面的这个函数你会非常熟悉

  • func表示这是一个函数。
  • 函数的名称是mySimpleFunction
  • 这个函数没有参数传入 - 因此是( )
  • 函数没有返回值
  • 函数是在{ }中执行

现在让我们看一个稍稍复杂的例子:

myFunctionName(param1: String,param2: Int) -> String {  }

这个函数有一个String类型且名为param1的参数和一个Int类型名为param2的参数并且返回值是 `String 类型。

调用所有函数

Swift 和 Objective-C 之间其中一个巨大的差别就是当 Swift 函数被调用的时候参数工作方式。如果你像我一样喜欢 Objective-C 超长的命名方式,那么请记住,在默认情况下 Swift 函数被调用时参数名是不被外部调用包含在内的。

hello(name: String) {
    "hello \(name)")
}

hello("Mr. Roboto")

在你增加更多参数到函数之前,一切看起来不是那么糟糕。但是:

(name: String,age: Int,location: String) {
    "Hello \(name). I live in \(location) too. When is your \(age + 1)th birthday?")
}

hello("Mr. Roboto",5,"San Francisco")

如果仅阅读hello("Mr. Roboto",5,"San Francisco"),你可能很难知道每一个参数代表什么。

在 Swift 中,有一个概念称为*外部参数名称* 用来解决这个困惑:

(fromName name: String) {
    "\(name) says hello to you!")
}

hello(fromName:  上面函数中,fromName是一个外部参数,在函数被调用的时候将被包括在调用中。在函数内执行时,使用name这个内部参数来对输入进行引用。

如果你希望外部参数和内部参数相同,你不需要写两次参数名:

(name name: String) {
    "hello \(name)")
}

hello(name: "Robot")

只需要在参数前面添加#的快捷方式:

(#name: String) {
     当然,对于方法而言参数的工作方式略有不同...

调用方法

当被封装在类 (或者结构,枚举) 中时,方法的第一个参数名被外部包含,同时所有的后面的参数在方法调用时候被外部包含:

class MyFunClass {

    1)th birthday?")
    }

}

let myFunClass = MyFunClass()
myFunClass.hello( 因此最佳实践是在方法名里包含第一个参数名,就像 Objective-C 那样:

helloWithNamelet myFunClass = MyFunClass()
myFunClass.helloWithName( 相对于调用函数 “hello”,我将其重命名为helloWithName,这使得第一个参数name变得很清晰。

如果出于一些原因你希望在函数中跳过外部参数名 (我建议如果要这么做的话,你需要一个非常好的理由),为外部函数添加_来解决:

_ age: Int,_ location: String) {
        "San Francisco")

实例方法是柯里化 (currying) 函数

需要注意一个非常酷的是Swift 中实例方法是柯里化函数

柯里化背后的基本想法是函数可以局部应用,意思是一些参数值可以在函数调用之前被指定或者绑定。这个部分函数的调用会返回一个新的函数。

如果我有一个类:

MyHelloWorldClass {

    (name: String) -> String {
        \(name)"
    }
}

我可以建立一个变量指向类中的helloWithName函数:

let helloWithNameFunc = MyHelloWorldClass.helloWithName
// MyHelloWorldClass -> (String) -> String

我新的helloWithNameFuncMyHelloWorldClass -> (String) -> String类型,这个函数接受我的类的实例并返回另一个函数。新函数接受一个字符串值,并返回一个字符串值。

所以实际上我可以这样调用我的函数:

let myHelloWorldClassInstance = MyHelloWorldClass()

helloWithNameFunc(myHelloWorldClassInstance)("Mr. Roboto") 
// hello,Mr. Roboto

初始化:一个特殊注意的地方

在类,结构体或者枚举初始化的时候将调用一个特殊的init方法。在 Swift 中你可以像其他方法那样定义初始化参数:

Person {

    init(name: String) {
        // your init implementation
        // 你的初始化方法实现
    }

}

Person(name:  注意下,不像其他方法,初始化方法的第一个参数必须在实例时必须是外部的。

大多数情况下的最佳实践是添加一个不同的外部参数名 — 本例中的fromName—让初始化更具有可读性:

init(fromName name: String) {
        // 你的初始化方法实现
    }

}

Person(fromName:  当然,就像其他方法那样,如果你想让方法跳过外部参数名的话,可以添加_。我喜欢Swift Programming Language Book初始化例子的强大和可读性。

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}

let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius 是 100.0

let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 是 0.0

let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius 是 37.0 

如果你希望抽象类/枚举/结构体的初始化,跳过外部参数可以非常有用。我喜欢在David Owenjson-swift library中对这项技术的使用:

public struct JSValue : Equatable {

    // ... 截断的部分代码

    /// 使用 `JSArrayType` 来初始化 `JSValue`。 
    public init(_ value: JSArrayType) {
        self.value = JSBackingValue.JSArray(value)
    }

    /// 使用 `JSObjectType` 来初始化 `JSValue`。 
    (_ value: JSObjectType) {
        self.value = JSBackingValue.JSObject(value)
    }

    /// 使用 `JSStringType` 来初始化 `JSValue`。 
    (_ value: JSStringType) {
        self.value = JSBackingValue.JSString(value)
    }

    /// 使用 `JSNumberType` 来初始化 `JSValue`。
    (_ value: JSNumberType) {
        self.value = JSBackingValue.JSNumber(value)
    }

    /// 使用 `JSBoolType` 来初始化 `JSValue`。
    (_ value: JSBoolType) {
        self.value = JSBackingValue.JSBool(value)
    }

    /// 使用 `Error` 来初始化 `JSValue`。
    init(_ error: Error) {
        self.value = JSBackingValue.Invalid(error)
    }

    /// 使用 `JSBackingValue` 来初始化 `JSValue`。
    init(_ value: JSBackingValue) {
        self.value = value
    }
}

华丽的参数

相较于 Objective-C,Swift 有很多额外的选项用来指定可以传入的参数的类型,下面是一些例子。

可选参数类型

在 Swift 中有一个新的概念称之为optional types

可选表示 “那儿有一个值,并且它等于 x ” 或者 “那儿没有值”。可选有点像在 Objective-C 中使用 nil,但是它可以用在任何类型上,不仅仅是类。可选类型比 Objective-C 中的 nil 指针更加安全也更具表现力,它是 Swift 许多强大特性的重要组成部分。

表明一个参数是可选 (可以是 nil),可以在类型规范后添加一个问号:

myFuncWithOptionalType(parameter: String?) {
    // function execution
}

myFuncWithOptionalType("someString")
myFuncWithOptionalType(nil)

使用可选时候不要忘记拆包!

(optionalParameter: String?) {
    if let unwrappedOptional = optionalParameter {
        "The optional has a value! It's \(unwrappedOptional)")
    } else {
        "The optional is nil!")
    }
}

myFuncWithOptionalType("someString")
// optional has a value! It's someString

myFuncWithOptionalType(nil)
// The optional is nil

如果学习过 Objective-C,那么习惯使用可选值肯定需要一些时间!

参数默认值

(name: String = "you") {
    \(name)")
}

hello(name: "Mr. Roboto")

值得注意的是有默认值的参数自动包含一个外部参数名

由于参数的默认值可以在函数被调用时调过,所以最佳实践是把含有默认值的参数放在函数参数列表的最后。Swift Programming Language Book包含相关的内容介绍:

把含有默认值的参数放在参数列表最后,可以确保对它的调用中所有无默认值的参数顺序一致,而且清晰表述了在不同情况下调用的函数是相同的。

我是默认参数的粉丝,主要是它使得代码容易改变而且向后兼容。比如配置一个自定义的UITableViewCell的函数里,你可以在你的某个用例中用两个参数开始,如果另一个用例出现,需要另一个参数 (比如你的 Cell 的 label 含有不同文字颜色),只需要添加一个包含新默认值的参数 — 函数的其他部分已经被正确调用,并且你代码最新部分仅需要参数传入一个非默认值。

可变参数

可变参数是传入数组元素的一个更加可读的版本。实际上,比如下面例子中的内部参数名类型,你可以看到它是[String]类型 (String 数组):

helloWithNames(names: String...) {
    for name in names {
        "Hello,\(name)")
    }
}

// 2 names
helloWithNames("Mr. Robot",0)">"Mr. Potato")
// Hello,Mr. Robot
// 4 names
helloWithNames("Batman",0)">"Superman",0)">"Wonder Woman",0)">"Catwoman")

这里要特别记住的是可以传入 0 个值,就像传入一个空数组一样,所以如果有必要的话,不要忘记检查空数组:

if names.count > 0 {
        in names {
            \(name)")
        }
    } "Nobody here!")
    }
}

helloWithNames()
// Nobody here!

可变参数另一个要注意的地方是 — 可变参数必须是在函数列表的最后一个!

输入输出参数 inout

利用 inout 参数,你有能力 (经过引用来) 操纵外部变量:

var name1 = "Mr. Potato"
var name2 = "Mr. Roboto"

nameSwap(inout name1: String,inout name2: String) {
    let oldName1 = name1
    name1 = name2
    name2 = oldName1
}

nameSwap(&name1,&name2)

name1
// Mr. Roboto

name2
// Mr. Potato

这是 Objective-C 中非常常见的用来处理错误的模式。NSJSONSerialization是其中一个例子:

- (void)parseJSONData:(NSData *)jsonData
{
    NSError *error = nil;
    id jsonResult = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];

    if (!jsonResult) {
        NSLog(@"ERROR: %@",error.description);
    }
}

Swift 非常之新,所以这里没有一个公认的处理错误的方式,但是在 inout 参数之外肯定有非常多的选择!看看 David Owen's 最新的博客Swfit 中的错误处理。关于这个话题的更多内容已经在Functional Programming in Swift中被涵盖.

泛型参数类型

我不会在本文中大篇幅介绍泛型,但是这里有个简单的例子来阐述如何在一个函数中接受两个类型不定的参数,但确保这两个参数类型是相同的:

valueSwap<T>inout value1: T,168)">inout value2: T) {
    let oldValue1 = value1
    value1 = value2
    value2 = oldValue1
}

"Mr. Roboto"

valueSwap(&name1,&name2)

name1 // Mr. Roboto
name2 // Mr. Potato

var number1 = 2
var number2 = 5

valueSwap(&number1,&number2)

number1 // 5
number2 // 2

更多的泛型知识,我建议你阅读下 Swift Programming Language book 中的泛型章节

变量参数 var

默认情况下,参数传入函数是一个常量,所以它们在函数范围内不能被操作。如果你想修改这个行为,只需要在你的参数前使用 var 关键字:

var name = appendNumbersToNamevar name: String,#maxNumber: Int) -> String {
    for i in 0..<maxNumber {
        name += String(i + 1)
    }
    return name
}

appendNumbersToName(name,maxNumber:5)
// Mr. Robot12345

name
// Mr. Roboto

值得注意的是这个和 inout 参数不同 — 变量参数不会修改外部传入变量!

作为参数的函数

在 Swift 中,函数可以被用来当做变量传递。比如,一个函数可以含有一个函数类型的参数:

luckyNumberForName(String,Int) -> String) -> let luckyNumber = Int(arc4random() % 100)
    return lotteryHandler(name,luckyNumber)
}

defaultLotteryHandler"\(name),your lucky number is \(luckyNumber)"
}

luckyNumberForName(// Mr. Roboto,your lucky number is 38

注意下只有函数的引用被传入 — 在本例中是defaultLotteryHandler。这个函数之后是否执行是由接收的函数决定。

实例方法也可以用类似的方法传入:

FunLottery {

    \(luckyNumber)"
    }

}

let funLottery = FunLottery()
luckyNumberForName( 为了让你的函数定义更具可读性,可以考虑为你函数的类型创建别名 (类似于 Objective-C 中的 typedef):

typealias lotteryOutputHandler = (String,Int) -> String

 

你也可以使用不包含参数名的函数 (类似于 Objective-C 中的 blocks):

in
    "\(name)'s' lucky number is \(number)"
})
// Mr. Roboto's lucky number is 74

在 Objective-C 中,使用 blocks 作为参数是异步操作是操作结束时的回调和错误处理的常见方式,这一方式在 Swift 中得到了很好的延续。

权限控制

Swift 有三个级别的权限控制

  • Public 权限可以为实体启用定义它们的模块中的源文件的访问,另外其他模块的源文件里只要导入了定义模块后,也能进行访问。通常情况下,Framework 是可以被任何人使用的,你可以将其设置为 public 级别
  • Internal 权限可以为实体启用定义它们的模块中的源文件的访问,但是在定义模块之外的任何源文件中都不能访问它。通常情况下,app 或 Framework 的内部结构使用 internal 级别。
  • Private 权限只能在当前源文件中使用的实体。使用 private 级别,可以隐藏某些功能的特地的实现细节。

默认情况下,每个函数和变量是 internal 的 —— 如果你希望修改他们,你需要在每个方法和变量的前面使用private或者public关键字:

public func myPublicFunc() {

}

func myInternalFuncprivate func myPrivateFuncmyOtherPrivateFunc() {

}

Ruby 带来的习惯,我喜欢把所有的私有函数放在类的最下面,利用一个//MARK来区分:

MyFunClass {

    () {

    }

    // MARK: Private Helper Methods

    () {

    }

    () {

    }
}

希望 Swift 在将来的版本中包含一个选项可以用一个私有关键字来表明以下所有的方法都是私有的,类似于其他语言那样做访问控制。

华丽的返回类型

在 Swift 中,函数的返回类型和返回值相较于 Objective-C 而言更加复杂,尤其是引入可选和多个返回类型。

可选返回类型

如果你的函数有可能返回一个 nil 值,你需要指定返回类型为可选:

myFuncWithOptonalReturnType() -> String? {
    let someNumber = arc4random() % 100
    if someNumber > 50 {
        "someString"
    } else {
        return nil
    }
}

myFuncWithOptonalReturnType()

当然,当你使用可选返回值,不要忘记拆包:

let optionalString = myFuncWithOptonalReturnType()

let someString = optionalString {
    "The function returned a value: \(someString)")
} else {
    "The function returned nil")
}

The best explanation I've seen of optionals is from atweet by @Kronusdark:

对我而言最好的可选值的解释来自于@Kronusdark的一条推特:

我终于弄明白 @SwiftLang 的可选值了,它们就像薛定谔的猫!在你使用之前,你必须先看看猫是死是活。

多返回值

Swift 其中一个令人兴奋的功能是函数可以有多个返回值

findRangeFromNumbers(numbers: Int...) -> (min: Int,max: Int) {

    var min = numbers[0]
    max = numbers[0]

    for number in numbers {
        if number > max {
            max = number
        }

        if number < min {
            min = number
        }
    }

    return (min,31)">max)
}

findRangeFromNumbers(1,31)">234,31)">555,31)">345,31)">423)
// (1,555)

就像你看到的那样,在一个元组中返回多个值,这一个非常简单的将值进行组合的数据结构。有两种方法可以使用多返回值的元组:

let range = findRangeFromNumbers(423)
"From numbers: 1,234,555,345,423. The min is \(range.min). The max is \(range.max).")
// From numbers: 1,423. The min is 1. The max is 555.

let (max) = findRangeFromNumbers(236,31)">8,31)">38,31)">937,31)">328)
"From numbers: 236,8,937,328. The min is \(min). The max is \(max)")
// From numbers: 236,328. The min is 8. The max is 937

多返回值与可选值

当返回值是可选的时候,多返回值就比较棘手。对于多个可选值的返回,有两种办法解决这种情况。

在上面的例子函数中,我的逻辑是有缺陷的 —— 它有可能没有值传入,所以我的代码有可能在没有值传入的时候崩溃,所以我希望我整个返回值是可选的:

max: Int)? {

    if numbers.0 {

        0]
        0]

        in numbers {
            max {
                max = number
            }

            min {
                min = number
            }
        }

        max)
    } nil
    }
}

let range = findRangeFromNumbers() {
    "Max: \(range.max). Min: \(range.min)")
} "No numbers!")
}
// No numbers!

另一种做法是对元组中的每个返回值设为可选来代替整体的元组可选:

componentsFromUrlString(urlString: String) -> (host: String?,path: String?) {
    let url = NSURL(string: urlString)
    return (url.host,url.path)
}

如果你决定你元组值中一些值是可选,拆包时候会变得有些复杂,你需要考虑每中单独的可选返回值的组合:

let urlComponents = componentsFromUrlString("http://name.com/12345;param?foo=1&baa=2#fragment")

switch (urlComponents.host,urlComponents.path) {
case let (.Some(host),.Some(path)): println("This url consists of host \(host) and path \(path)") "This url only has a host \(host)") (.None,.Some(path)): "This url only has path \(path). Make sure to add a host!") "This is not a url!") } // This url consists of host name.com and path /12345 

如你所见,它和 Objective-C 的处理方式完全不同!

返回一个函数

Swift 中函数可以返回一个函数:

myFuncThatReturnsAFunc() -> (Int) -> return { number in
        "The lucky number is \(number)"
    }
}

let returnedFunction = myFuncThatReturnsAFunc()

returnedFunction(5) // The lucky number is 5

为了更具有可读性,你当然可以为你的返回函数定义一个别名:

typealias returnedFunctionType = (Int) -> String

returnedFunctionType {
    // The lucky number is 5

嵌套函数

如果在这篇文章中你没对函数有足够的体会,那么了解下 Swift 可以在函数中定义函数也是不错的。

myFunctionWithNumber(someNumber: Int) {

    incrementvar someNumber: Int) -> Int {
        return someNumber + 10
    }

    let incrementedNumber = increment(someNumber)
    "The incremeted number is \(incrementedNumber)")
}

myFunctionWithNumber(// The incremeted number is 15

@end

Swift 函数有更多的选项以及更为强大功能。从你开始利用 Swift 编程时,记住:能力越强责任越大。请一定要巧妙地优化可读性!

Swift 的最佳实践还没被确立,这门语言也在不断地进化,所以请朋友和同事来审查你的代码。我发现一些从来没见过 Swift 的人反而在我的 Swift 代码中提供了很大帮助。

Swift 编码快乐!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘贴.待开发的功能:1.支持自动生成约束2.开发设置页面3.做一个浏览器插件,支持不需要下载整个工程,可即时操作当前蓝湖浏览页面4.支持Flutter语言模板生成5.支持更多平台,如Sketch等6.支持用户自定义语言模板
现实生活中,我们听到的声音都是时间连续的,我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。目前我们在计算机上进行音频播放都需要依赖于音频文件。那么音频文件如何生成的呢?音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号的过程,我们人耳所能听到的声音频率范围为(20Hz~20KHz),因此音频文件格式的最大带宽是20KHZ。根据奈奎斯特的理论,音频文件的采样率一般在40~50KHZ之间。奈奎斯特采样定律,又称香农采样定律。...............
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿遍又亿遍,久久不能离开!看着小仙紫姐姐的蹦迪视频,除了一键三连还能做什么?突发奇想,能不能把舞蹈视频转成代码舞呢?说干就干,今天就手把手教大家如何把跳舞视频转成代码舞,跟着仙女姐姐一起蹦起来~视频来源:【紫颜】见过仙女蹦迪吗 【千盏】一、核心功能设计总体来说,我们需要分为以下几步完成:从B站上把小姐姐的视频下载下来对视频进行截取GIF,把截取的GIF通过ASCII Animator进行ASCII字符转换把转换的字符gif根据每
【Android App】实战项目之仿抖音的短视频分享App(附源码和演示视频 超详细必看)
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至2022年4月底。我已经将这篇博客的内容写为论文,上传至arxiv:https://arxiv.org/pdf/2204.10160.pdf欢迎大家指出我论文中的问题,特别是语法与用词问题在github上,我也上传了完整的项目:https://github.com/Whiffe/Custom-ava-dataset_Custom-Spatio-Temporally-Action-Video-Dataset关于自定义ava数据集,也是后台
因为我既对接过session、cookie,也对接过JWT,今年因为工作需要也对接了gtoken的2个版本,对这方面的理解还算深入。尤其是看到官方文档评论区又小伙伴表示看不懂,所以做了这期视频内容出来:视频在这里:本期内容对应B站的开源视频因为涉及的知识点比较多,视频内容比较长。如果你觉得看视频浪费时间,可以直接阅读源码:goframe v2版本集成gtokengoframe v1版本集成gtokengoframe v2版本集成jwtgoframe v2版本session登录官方调用示例文档jwt和sess
【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)
用Android Studio的VideoView组件实现简单的本地视频播放器。本文将讲解如何使用Android视频播放器VideoView组件来播放本地视频和网络视频,实现起来还是比较简单的。VideoView组件的作用与ImageView类似,只是ImageView用于显示图片,VideoView用于播放视频。...
采用MATLAB对正弦信号,语音信号进行生成、采样和内插恢复,利用MATLAB工具箱对混杂噪声的音频信号进行滤波
随着移动互联网、云端存储等技术的快速发展,包含丰富信息的音频数据呈现几何级速率增长。这些海量数据在为人工分析带来困难的同时,也为音频认知、创新学习研究提供了数据基础。在本节中,我们通过构建生成模型来生成音频序列文件,从而进一步加深对序列数据处理问题的了解。
基于yolov5+deepsort+slowfast算法的视频实时行为检测。1. yolov5实现目标检测,确定目标坐标 2. deepsort实现目标跟踪,持续标注目标坐标 3. slowfast实现动作识别,并给出置信率 4. 用框持续框住目标,并将动作类别以及置信度显示在框上
数字电子钟设计本文主要完成数字电子钟的以下功能1、计时功能(24小时)2、秒表功能(一个按键实现开始暂停,另一个按键实现清零功能)3、闹钟功能(设置闹钟以及到时响10秒)4、校时功能5、其他功能(清零、加速、星期、八位数码管显示等)前排提示:前面几篇文章介绍过的内容就不详细介绍了,可以看我专栏的前几篇文章。PS.工程文件放在最后面总体设计本次设计主要是在前一篇文章 数字电子钟基本功能的实现 的基础上改编而成的,主要结构不变,分频器将50MHz分为较低的频率备用;dig_select
1.进入官网下载OBS stdioOpen Broadcaster Software | OBS (obsproject.com)2.下载一个插件,拓展OBS的虚拟摄像头功能链接:OBS 虚拟摄像头插件.zip_免费高速下载|百度网盘-分享无限制 (baidu.com)提取码:6656--来自百度网盘超级会员V1的分享**注意**该插件必须下载但OBS的根目录(应该是自动匹配了的)3.打开OBS,选中虚拟摄像头选择启用在底部添加一段视频录制选择下面,进行录制.
Meta公司在9月29日首次推出一款人工智能系统模型:Make-A-Video,可以从给定的文字提示生成短视频。基于**文本到图像生成技术的最新进展**,该技术旨在实现文本到视频的生成,可以仅用几个单词或几行文本生成异想天开、独一无二的视频,将无限的想象力带入生活
音频信号叠加噪声及滤波一、前言二、信号分析及加噪三、滤波去噪四、总结一、前言之前一直对硬件上的内容比较关注,但是可能是因为硬件方面的东西可能真的是比较杂,而且需要渗透的东西太多了,所以学习进展比较缓慢。因为也很少有单纯的硬件学习研究,总是会伴随着各种理论需要硬件做支撑,所以还是想要慢慢接触理论学习。但是之前总找不到切入点,不知道从哪里开始,就一直拖着。最近稍微接触了一点信号处理,就用这个当作切入点,开始接触理论学习。二、信号分析及加噪信号处理选用了matlab做工具,选了一个最简单的语音信号处理方
腾讯云 TRTC 实时音视频服务体验,从认识 TRTC 到 TRTC 的开发实践,Demo 演示& IM 服务搭建。
音乐音频分类技术能够基于音乐内容为音乐添加类别标签,在音乐资源的高效组织、检索和推荐等相关方面的研究和应用具有重要意义。传统的音乐分类方法大量使用了人工设计的声学特征,特征的设计需要音乐领域的知识,不同分类任务的特征往往并不通用。深度学习的出现给更好地解决音乐分类问题提供了新的思路,本文对基于深度学习的音乐音频分类方法进行了研究。首先将音乐的音频信号转换成声谱作为统一表示,避免了手工选取特征存在的问题,然后基于一维卷积构建了一种音乐分类模型。
C++知识精讲16 | 井字棋游戏(配资源+视频)【赋源码,双人对战】
本文主要讲解如何在Java中,使用FFmpeg进行视频的帧读取,并最终合并成Gif动态图。
在本篇博文中,我们谈及了 Swift 中 some、any 关键字以及主关联类型(primary associated types)的前世今生,并由浅及深用简明的示例向大家讲解了它们之间的奥秘玄机。