swift 进阶知识点

本文的知识点会比较散,是基础语法之外的一些进阶内容,如果有写的不妥的地方,欢迎评论区指正~

Optional

可选值是通过枚举实现的:

enum Optional<Wrapped> {
	case none
	case some(Wrapped)

对于Optional类型的值可以通过switch来处理,比如case .some(Wrapped),简写为case let Wrapped?,当然解包可选值最简单的方法莫过于用if/guard let的语法。

当需要可选值的时候,传入非可选值会隐式转换成可选值。

while let当条件返回nil时终止循环:

let array = [1, 2, 3]
var iterator = array.makeIterator()
while let i = iterator.next() {
	print(i, terminator: " ")
} // 1 2 3

还有一种for...where的用法,表示满足条件才会执行循环:

for i in 0..<10 where i % 2 == 0 {
	print(i, terminator: " ")
} // 0 2 4 6 8

双重可选值

let stringNumbers = ["1", "2", "three"]
let maybeInts = stringNumbers.map { Int($0) } // [Optional(1), Optional(2), nil]

如果用 maybeInts.makeIterator().next()遍历元素,其实每次返回的都是Int??,相当于解两次包。
如果想筛选出数组中不为nil的元素,可以用:

for case let i? in maybeInts {
// i 将是 Int 值,而不是 Int?
	print(i, terminator: " ")
}
// 1 2

Never & Void & nil

  • public enum Never { }:无法构建Never类型的值,绝对不会返回。guard语句的else路径必须退出当前域或者调用一个不会返回的函数,如fatalError()
  • public typealias Void = ():不返回任何值。
  • nil表示不存在。
var dictWithNils: [String: Int?] = [
"one": 1,
"two": 2,
"none": nil
]

如果dictWithNils["two"] = nil,则字典会删除该项。如果想让"two"对应的值为nil,可以dictWithNils["two"] = .some(nil)dictWithNils["two"]? = nil
这两种赋值的前提都是先保障字典key对应的可选值’存在’,然后给对应的值Int?赋值,而如果直接给dictWithNils["two"] 赋值,赋的只是最外层字典本身的可选值,一旦这个值为nil,那么该项也就不存在了。

Closure

闭包 = 函数 + 捕获的其局部变量外的变量。如果将闭包作为函数参数进行传递,有如下简写方式:

例如[1, 2, 3].map { $0 * 2 } // [2, 4, 6]

  1. 如果编译器可以从上下文中推断出类型的话,你就不需要指明它了。在我们的例子中,从数组元素的类型可以推断出传递给 map的函数接受 Int 作为参数,从闭包内的乘法结果的类型可以推断出闭包返回的也是 Int
  2. 如果闭包表达式的主体部分只包括一个单一的表达式的话,它将自动返回这个表达式的结果,你可以不写 return
  3. Swift 会自动为函数的参数提供简写形式,$0 代表第一个参数,$1 代表第二个参数,以此类推。
  4. 如果函数的最后一个参数是闭包表达式的话,你可以将这个闭包表达式移到函数调用的圆括号的外部,这样的尾随闭包语法 (trailing closure syntax) 在多行的闭包表达式中表现非常好。
  5. 最后,如果一个函数除了闭包表达式外没有别的参数,那么调用的时候在方法名后面的圆括号也可以一并省略。

自动闭包

Swift 中定义一个和 && 操作符具有相同功能的 and 函数:

func and(_ l: Bool, _ r: () -> Bool) -> Bool {
	guard l else { return false }
	return r()
}

我们可以使用 @autoclosure 标注来告诉编译器它应该将一个特定的参数用闭包表达式包装起来。

func and(_ l: Bool, _ r: @autoclosure () -> Bool) -> Bool {
	guard l else { return false }
	return r()
}

过度使用自动闭包可能会让你的代码难以理解,使用时的上下文和函数名应该清晰地指出实际求值会被推迟。

逃逸闭包

一个被保存在某个地方 (比如一个属性中) 等待稍后再调用的闭包就叫做逃逸闭包。相对的,永远不会离开一个函数的局部作用域的闭包就是非逃逸闭包。闭包参数默认是非逃逸的。如果你想要保存一个闭包稍后再用,你需要将闭包参数标记为 @escaping

对于那些使用闭包作为参数的函数,如果闭包被封装到像是元组或者可选值等类型的话,这个闭包参数也是逃逸的。因为在这种情况下闭包不是直接参数,它将自动变为逃逸闭包。这样的结果是,你不能写出一个函数,使它接受的函数参数同时满足可选值和非逃逸。很多情况下,你可以通过为闭包提供一个默认值来避免可选值。如果这样做行不通的话,可以通过重载函数,提供一个包含可选值 (逃逸) 的函数,以及一个不是可选值,非逃逸的函数来绕过这个限制:


// 如果用 nil 参数 (或者一个可选值类型的变量) 来调用函数,将使用可选值变种,而如果使用闭包字面量的调用将使用非逃逸和非可选值的重载方法
func transform(_ input: Int, with f: ((Int) -> Int)?) -> Int {
	print("使用可选值重载")
	guard let f = f else { return input }
	return f(input)
}

func transform(_ input: Int, with f: (Int) -> Int) -> Int {
	print("使用非可选值重载")
	return f(input)
}

捕获列表

闭包可以捕获并存储其定义上下文中任何常量和变量的引用。

闭包的生命周期从它们被创建和赋值开始,一直持续到它们被销毁(即,它们已经没有任何引用指向它们)。

关于闭包与引用循环(Reference cycles)的关系,首先需要了解闭包是引用类型,不是值类型。当一个闭包被赋值给一个变量,常量或者属性,实际上被赋值的是对该闭包的引用,而不是闭包的副本。

例如,如果一个类实例有个属性指向一个闭包,并且这个闭包又捕获(也就是引用)了这个类的实例,那么就会形成一个引用循环。

通过捕获列表可以避免循环引用:

counter = 0
g = {[c = counter] in print(c)}
counter = 1
g() // 0

捕获列表位于闭包的开始部分,包含在方括号([])中,每项由一对由等号分隔的元素组成,前面的元素是引用的名称(可能带有 weak 或 unowned 的标记),后面的元素是在闭包外部的实际变量或常量。

Custom operator

infix operator用来自定义一个中缀运算符。中缀运算符是处于两个操作数之间的运算符,比如加法运算符。

// 自定义运算符**表示取幂运算(即lhs的rhs次幂),并且其优先级与乘法运算相同(MultiplicationPrecedence)。
infix operator **: MultiplicationPrecedence // 使用已有的优先级group
func **(base: Int, power: Int) -> Int {
  precondition(power >= 2)
  var result = base
  for _ in 2...power {
    result *= base
  }
  return result
}

注意:Swift 中定义的运算符必须要有一个优先级组(precedence group)。上述代码中使用了已有的乘法优先级,你也可以自定义优先级:

precedencegroup PowerPrecedence {
  associativity: right // 2 ** 3 ** 2 从右向右结合
  higherThan: MultiplicationPrecedence
}
infix operator **: PowerPrecedence

let result = 2 * 3 ** 2 就会首先计算 3 ** 2

如果想让 ** 支持更过的类型,可以考虑范型:

func **<T: BinaryInteger>(base: T, power: Int) -> T {
  precondition(power >= 2)
  var result = base
  for _ in 2...power {
    result *= base
  }
  return result
}

inout

如果想在函数体内改变参数的值,可利用inout关键词。对于inout参数,你只能传递左值,因为右值是不能被修改的。当你在普通的函数或者方法中使用inout时,需要显式地将它们传入:即在每个左值前面加上&符号。

// ++ 自增运算符
postfix func ++(x: inout Int) {
x += 1
}

需要注意几点:

  • 不能够让这个inout参数逃逸,只能在函数返回前修改
  • 就像对待普通的参数一样,Swift 还是会复制传入的 inout 参数,但当函数返回时,会用这些参数的值覆盖原来的值。也就是说,即使在函数中对一个 inout 参数做多次修改,但对调用者来说只会注意到一次修改的发生,也就是在用新的值覆盖原有值的时候。同理,即使函数完全没有对 inout 参数做任何的修改,调用者也还是会注意到一次修改 (willSetdidSet 这两个观察者方法都会被调用)。

Subscripts

[]操作符进行扩展,可以操作类、结构体、枚举等类型的属性。

class Person {
  let name: String
  let age: Int
  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }
}

extension Person {
  subscript(key: String) -> String? {
    switch key {
      case "name": return name
      case "age": return "\(age)"
      default: return nil
	}
  }
}
let me = Person(name: "Cosmin", age: 36)
me["name"]
me["age"]

// Subscript parameters
subscript(key key: String) -> String? {
  // original code
}
me[key: "name"]
me[key: "age"]

Dynamic member lookup

Subscripts的使用转变为.操作符,做法如下:

// 1
@dynamicMemberLookup
class Instrument {
  let brand: String
  let year: Int
  private let details: [String: String]
  init(brand: String, year: Int, details: [String: String]) {
    self.brand = brand
    self.year = year
    self.details = details
}
// 2 可添加 class 前缀等价于 static 
  subscript(dynamicMember key: String) -> String {
    switch key {
      case "info": return "\(brand) made in \(year)."
      default: return details[key] ?? ""
    }
} }

KeyPath

Setting properties

键路径表达式以一个反斜杠开头,比如 \String.count。反斜杠是为了将键路径和同名的类型属性区分开来。类型推断对键路径也是有效的,在上下文中如果编译器可以推断出类型的话,你可以将类型名省略,只留下 \.count。”

class Tutorial {
  let title: String
  let details: (type: String, category: String)
  init(title: String,
       details: (type: String, category: String)) {
    self.title = title
    self.details = details
  }
}
// 通过 keyPath 可以直接获取和修改属性值
let tutorial = Tutorial(
  title: "Object Oriented Programming in Swift",
  details: (type: "Swift",
          category: "iOS")
)
let title = \Tutorial.title
let tutorialTitle = tutorial[keyPath: title]          

Keypath member lookup

KeyPath 可以和 MemberLookup 结合使用:

struct Point {
  let x, y: Int
}

@dynamicMemberLookup
struct Circle {
  let center: Point
  let radius: Int
  
  subscript(dynamicMember keyPath: KeyPath<Point, Int>) -> Int {
    center[keyPath: keyPath]
  }
}

let center = Point(x: 1, y: 2)
let circle = Circle(center: center, radius: 1)
// 应该是利用了类型推断
circle.x
circle.y

Keypaths as functions

KeyPath 可以当作函数使用:

let titles = [tutorial].map(\.title)

NSObjectobserve(_:options:changeHandler:) 方法将会对一个 \键路径进行观察,并在属性发生变化的时候调用 handler。不要忘记还需要将要观察的属性标记为 @objc dynamic,否则 KVO 将不会工作。

键路径可以帮助我们在两个 NSObject 之间实现双向绑定,键路径可以让我们的代码更加泛用,而不必拘泥于某个特定的属性:

// 通过扩展 NSObjectProtocol 而不是 NSObject,我们可以使用 Self
extension NSObjectProtocol where Self: NSObject {
    
    func observe<A, Other>(_ keyPath: KeyPath<Self, A>,
                       writeTo other: Other,
                      _ otherKeyPath: ReferenceWritableKeyPath<Other, A>)
    -> NSKeyValueObservation
    where A: Equatable, Other: NSObjectProtocol
    {
    	// 注意options的取值,需要在新值变化时调用handler 
        return observe(keyPath, options: .new) { _, change in
            guard let newValue = change.newValue,
                  other[keyPath: otherKeyPath] != newValue else {
                return // prevent endless feedback loop
            }
            other[keyPath: otherKeyPath] = newValue
        }
    }

    func bind<A, Other>(_ keyPath: ReferenceWritableKeyPath<Self,A>,
    to other: Other,
    _ otherKeyPath: ReferenceWritableKeyPath<Other,A>)
    -> (NSKeyValueObservation, NSKeyValueObservation)
    where A: Equatable, Other: NSObject
    {
        let one = observe(keyPath, writeTo: other, otherKeyPath)
        let two = other.observe(otherKeyPath, writeTo: self, keyPath)
        return (one,two)
    }
}

Property Wrappers

@propertyWrapper 是 Swift 中的一个特性,用于自定义属性的获取和设置行为。

@propertyWrapper
struct ZeroTo<Value: Numeric & Comparable> {
  private var value: Value
  let upper: Value

  init(wrappedValue: Value, upper: Value) {
    value = wrappedValue
    self.upper = upper
  }

  var wrappedValue: Value {
    get { min(max(value, 0), upper) }
    set { value = newValue }
  }

  // 可以通过 $ 获取该值, 没必要和 wrappedValue 是一个类型
  var projectedValue: Value { value }
}

// 当我们在函数或闭包的参数中使用属性包装器时,编译器将帮我们生成其他必要的初始化代码。当我们调用函数时,实际参数的值将用作 wrappedValue值。
func printValueV3(@ZeroTo(upper: 10) _ value: Double) {
  print("The wrapped value is", value)
  print("The projected value is", $value)
}
printValueV3(42) // 10

projectedValue 的使用示例如下:

@propertyWrapper
public struct ValidatedDate {
  private var storage: Date? = nil
  private(set) var formatter = DateFormatter()
  public init(wrappedValue: String) {
    self.formatter.dateFormat = "yyyy-mm-dd"
    self.wrappedValue = wrappedValue
  }
  public var wrappedValue: String {
    set {
      self.storage = formatter.date(from: newValue)
    }
    get {
      if let date = self.storage {
        return formatter.string(from: date)
      } else {
        return "invalid"
      }
    }
  }
  public var projectedValue: DateFormatter {
    get { formatter }
    set { formatter = newValue }
  }
}

Protocol

extension protocol 不仅可以为 protocol 提供默认实现,而且可以新增属性、方法的定义和实现。

associatedtype 用于在协议定义中声明一个占位类型,也就是类型的别名。具体的类型在协议被具体类型(如:结构体、类或枚举)遵守时才会被确定:

protocol Container {
    associatedtype Item
    mutating func append(_ item: Item)
    var count: Int { get }
    subscript(i: Int) -> Item { get }
}

struct IntArray: Container {
    // 在遵守协议的类型中指定 Item 实际上是 Int 类型
    typealias Item = Int

    var items = [Int]()

    mutating func append(_ item: Int) {
        items.append(item)
    }

    var count: Int {
        return items.count
    }

    subscript(i: Int) -> Int {
        return items[i]
    }
}

由于协议只是定义了一套共用的接口,很难将实现协议的类型关联起来,所以associatedtype 也可以为协议绑定特定类型的数据。

protocol Product {}
protocol ProductionLine  {
  func produce() -> Product
}
protocol Factory {
  var productionLines: [ProductionLine] {get}
}
extension Factory {
  func produce() -> [Product] {
    var items: [Product] = []
    productionLines.forEach { items.append($0.produce()) }
    print("Finished Production")
    print("-------------------")
    return items
} }

创建一个工厂,里面的产品线可以是任意的,但是我想让一个特定的工厂只生产特定的产品,就可以采用associatedtype 或者generics

protocol Product {
init() }
protocol ProductionLine {
  associatedtype ProductType
  func produce() -> ProductType
}
protocol Factory {
  associatedtype ProductType
  func produce() -> [ProductType]
}
struct GenericProductionLine<P: Product>: ProductionLine {
  func produce() -> P {
    P()
  }
}
struct GenericFactory<P: Product>: Factory {
  var productionLines: [GenericProductionLine<P>] = []
  func produce() -> [P] {
    var newItems: [P] = []
    productionLines.forEach { newItems.append($0.produce()) }
    print("Finished Production")
    print("-------------------")
    return newItems
  }
}

Opaque return types

函数的返回值可以是遵循某些协议的非固定类型:

// return 的必须要是同一类型数据
func makeValueRandomly() -> some FixedWidthInteger {
  if Bool.random() {
    return Int(42)
  }
else {
    return Int(24)
  }
}

有两点需要注意:

  • 不能把返回值作为函数参数
  • 不能够约束返回值的associatedtype,比如some Collection

Type Erasure

在 Swift 中,由于它是一个强类型语言,每一个类、结构体或者枚举都有自己所特有的类型。然而,往往在实际编程中,我们可能需要去抹除这些特定的类型信息,将不同的类型以一种统一的方式去处理。这就是所谓的 “类型擦除”。

类型擦除主要用在两个方面:

  • 将拥有相同行为或特性,但是类型不同的实例,包装成一种通用的类型。比如 Array、Set、Dictionary 都遵循 Collection 协议,我们可以把它们统一的看作是 AnyCollection。
  • 在泛型编程中,更好的隐藏类型的具体细节,提供更加清晰和方便的公共接口。

AnyCollection 的实现为例:

// 私有协议,抓住了 Collection 的公共接口
private protocol _AnyCollectionBox {
    associatedtype Element
    // 定义的其他需要实现的方法和属性
}

// 私有类,实现了私有协议,并持有一个 Collection
private class _CollectionBox<Base : Collection> : _AnyCollectionBox {
    var _base: Base
    init(_ base: Base) {
        _base = base
    }
    // 实现了其他的方法和属性
}

public struct AnyCollection<Element> : Collection {
    // 中间抽象,可以指向任何一个 Collection
    internal var _box: _AnyCollectionBox<Element>
    // 公共的构造方法,接收一个 Collection
    public init<C : Collection>(_ collection: C) where C.Element == Element {
        // 将接收到的 Collection 封装到 box 中
        _box = _CollectionBox(collection)
    }
    // 其他 Collection 协议的方法和属性
}

可以通过以下代码把承载不同元素的容器放到同一个数组里:

let array = Array(1...10)
let set = Set(1...10)
let reversedArray = array.reversed()
let arrayCollections = [array, Array(set), Array(reversedArray)]
let collections = [AnyCollection(array),
                   AnyCollection(set),
                   AnyCollection(array.reversed())]

我对类型擦除的理解就是,对于内部有associatedtype的协议而言,不能把他们放到一个数组里,编译器无法确定数组中的每个元素的具体类型,这是不被 Swift 允许的。所以才有了类型擦除(或许只是其中一个原因)。

额外扯一下AnyAny (或其他的泛型类型)并不是直接存储在数组中的,而是经过了一层封装。在 Array 的底层实现中,所有的元素都会被看作 AnyObject 类型的实例并存储在堆中。这就意味着这个 Array 是一个引用语义类型的集合,且每个元素实际上并不位于连续的内存空间中 – 相反,每个元素是一个指向堆中存储空间的引用。

当我们说 “数组中的每个 Any 元素在内存中的大小都是一样的” 时,指的是每个元素在数组中占用的内存大小一样 – 它们都是指针,指向存储在堆中的实例。无论这个实例是 Int 还是 String 或者其他的类型。

当然,如果数组元素是协议,是地址引用。

Class & Struct

改变结构体的可变类型的值实际上是重新给结构体变量赋值,拷贝结构体时,如果结构体中有类变量,那么拷贝的是该对象的引用,即不同的结构体可能有着对同一个对象的引用。

weak & unowned 引用

weak 应用作用于可选类型的对象,unowned引用不要求对象可选,但是要确保“被引用者”的生命周期比“引用者”要长。

在对象中,Swift 运行时使用另外一个引用计数来追踪 unowned 引用。当对象没有任何强引用的时候,会释放所有资源 (例如,对其他对象的引用)。然而,只要对象还有 unowned 引用存在,其自身所占用的内存就不会被回收。这块内存会被标记为无效,有时也称作僵尸内存 (zombie memory)。被标记为僵尸内存之后,只要我们尝试访问这个 unowned 引用,就会发生一个运行时错误。

相比弱引用,unowned 引用的开销也小一点,通过它访问属性或调用方法的速度会快一点点。

写时复制

写时复制的意思是,在结构体中的数据,一开始是在多个变量之间共享的:只有在其中一个变量修改了它的数据时,才会产生对数据的复制操作。集合类型(Array、Dictionary、Set、String)都是用写时复制实现的。

如果对结构体的类对象实现写时复制,可以利用isKnownUniquelyReferenced函数,检查一个引用类型的实例是否只有一个所有者。返回false时对引用的对象进行深拷贝,当引用唯一时没有必要进行复制。

Enum

if caseguard case 判断枚举类型是否匹配的同时,可以利用模式匹配定义枚举中包含的值,避免了 switch匹配。

递归

实现一个单向链表:

enum List<Element> {
	case end
	indirect case node(Element, next: List<Element>)
	/// 把一个含有值 `x` 的节点添加到链表的头部。
	/// 然后返回整个链表。
	func cons(_ x: Element) -> List {
		return .node(x, next: self)
	}
}

indirect 告诉编译器把 node 成员表示为一个引用,从而使递归起作用。枚举作为值类型是不能包含自身的,因为如果允许这样的话,在计算类型大小的时候,就会创建一个无限递归。编译器必须能够为每种类型确定一个固定且有限的尺寸。将需要递归的成员作为一个引用是可以解决这个问题的,因为引用类型在其中增加了一个间接层;并且编译器知道任何引用的存储大小总是为 8 个字节 (在一个 64 位的系统上)。当然,如果子节点是数组的话,就不需要indirect了,因为数组内部使用一个引用类型作为存储,已经提供了所需的间接层。

让链表实现 ExpressibleByArrayLiteral 协议,使其能够使用数组字面量来初始化一个链表。在具体的实现中,首先反转作为输入的数组 (因为链表是从结尾开始构建的),然后从 .end 节点开始,使用 reduce 将元素逐个添加到链表中:

extension List: ExpressibleByArrayLiteral {
	public init(arrayLiteral elements: Element...) {
		// reduce 方法接受一个初始的聚合值和一个闭包,每次迭代将当前聚合值和数组中的一个元素作为输入,并返回一个新的聚合值。
		self = elements.reversed().reduce(.end) { partialList, element in
			partialList.cons(element)
		}
	}
}
let list2: List = [3,2,1]
/*
node(3, next: List.node(2, next: List.node(1,
 next: List.end)))
*/

这个链表类型还有一个有趣的特性:它的可持久化。节点都是不可变的 - 一旦创建,你就无法修改它了。添加一个元素到链表中时并不会复制链表;它只是给你一个新的节点,这个节点会链接到现有列表的头部。

固定和非固定枚举

假如在某个版本中switch对一个枚举类型的值穷尽了,但是很有可能在后续版本该枚举类型又增加了,为了防止之前的版本崩溃,我们一般都会加上default的分支。这样做在编译和运行时虽然是没问题的,但是之前的代码就感知不到枚举类型的改动,如果想获取IDE的提示,可以在default加上@unknown的关键词,这样就有在枚举没有穷尽时产生一个warningwitch must be exhaustive

提示和窍门

  • 尽量避免使用嵌套 switch 语句。可以使用元组一次性匹配多个值。
  • 避免用 nonesome 来命名成员。因为在模式匹配的上下文中,它们可能与 Optional 的成员发生冲突。
  • 对那些用保留的关键字来命名的成员使用反引号 (backtick)。如果你使用某些关键字来作为成员名字的话 (例如,default),类型检查器会因为无法解析代码而产生错误。你可以用反引号(``)把名字括起来使用它。
  • 可以像工厂方法一样使用成员。如果一个成员拥有关联值的话,这个枚举值就单独地形成了一个签名为 (AssocValue) -> Enum 的函数。
  • 不要使用关联值来模拟存储属性。获取某个属性时用结构体更为方便,尤其是当枚举的关联值有较多重复时。
  • 把空枚举作为命名空间。除了由模块形成的隐式命名空间之外,Swift 没有内置的命名空间。但我们可以用枚举来“模拟”命名空间。由于类型定义是可以嵌套的,因此外部类型可以充当其包含的所有声明的命名空间。

字符串

基本概念

Character是人类阅读时理解的单个字符,也称为扩展字位簇(extended grapheme cluster),但它可能由多个Unicode标量(Unicode scalars)组成,原因在于字符集的庞大与扩张。由于Unicode是变长编码,一个Unicode标量可能由多个编码单元(code units)组成,对于UTF-8而言,会使用 1~4 个字节编码标量,所以其编码单元为UInt8;对于UTF-16而言,会使用 2/4 个字节编码标量,所以其编码单元为UInt16

// String - UTF-8; NSString - UTF-16
// 调用 count 时,结果都为 7
let single = "Pok\u{00E9}mon" // Pokémon
let double = "Poke\u{0301}mon" // Pokémon

single.unicodeScalars.count // 7
double.unicodeScalars.count // 8

single == double // true
// 比较编码单元速度会更快
single.utf8.elementsEqual(double.utf8) // false

let nssingle = single as NSString
nssingle.length // 7
let nsdouble = double as NSString
nsdouble.length // 8

// 在 UTF-16 编码单元的层面上进行比较,可以用 NSString.compare(_:) 比较组合之后的字面量
nssingle == nsdouble // false

简单的颜文字一般由两个Unicode标量组成,复杂点的颜文字可以通过一个标量值为 U+200D 的不可见零宽连接字符(zero-width joiner,ZWJ)连接简单颜文字而成。例如‍‍‍是由 + ZWJ + + ZWJ + + ZWJ + 构成的。

NSStringString在内存中的视图编码是不同的,在二者之间桥接时会消耗一定的时间和空间。假设通过String初始化了NSMutableAttributedString,获取其string属性时实际上是从NSString属性转化而来的,频繁的该操作会消耗大量时间,但是如果as NSString就能避免这种桥接,这是Swift内部的优化。

字符串索引

做字符串拼接时,字符的数量不等于两个字符串的字符总和,存在相邻字符拼接成新的字位簇的情况。

当使用字符串的索引访问字符时,需要使用String.Index,而不是普通的整数索引。字符和标量并不是一一对应的关系,就算知道给定字符串中第 n 个字符的位置,也并不会对计算这个字符之前有多少个 Unicode 标量有任何帮助。

随机访问字符串并不是O(1)的时间复杂度,查找第n个字符要检查内存中该字符之前所有的字符。而且无法通过下标替换字符,只能用replaceSubrange

字符串类型 Stringindices 属性是一个包含所有字位簇的索引集合。这些索引表示了在字符串中每个字符的开头位置,不论这个字符是由单个 Unicode 标量还是多个 Unicode 标量组成的。

子字符串 SubString 会一直持有整个原始字符串。如果有一个巨大的字符串,它的一个只表示单个字符的子字符串将会在内存中持有整个字符串。即使当原字符串的生命周期本应该结束时,只要子字符串还存在,这部分内存就无法释放。长期存储子字符串实际上会造成内存泄漏,由于原字符串还必须被持有在内存中,但是它们却不能再被访问。

将一个 String 转为 SubString 最快的方式是用不指定任何边界的范围操作符:str[...]

Uninode 标量

Unicode.Scalar.Properties 有着丰富的属性列表。

现在列出字符串中每一个标量的编码点、名称和一般分类只需要对字符串做一点格式化就行了:

"I’m a ‍.".unicodeScalars.map { scalar -> String in
	let codePoint = "U+\(String(scalar.value, radix: 16, uppercase: true))"
	let name = scalar.properties.name ?? "(no name)"
	return "\(codePoint): \(name)\(scalar.properties.generalCategory)"
}.joined(separator: "\n")

Result Builders

@resultBuilder 是 Swift 5.4 引入的一个新特性,主要用于简化构建和处理复杂对象的代码。在 SwiftUI 框架和 Swift 的函数式 API 中已经有它的身影。它可以将一组值经过特定的转换和计算构建为一个结果对象,有点类似于声明式编程的概念。

例如,我们需要创建一个HTML网页,网页包含head标签和body标签,每个标签又可能包含若干子标签。如果没有@resultBuilder,我们需要创建每个标签,设置属性,再将这个标签添加到其父标签下,代码会显得繁琐。

struct HTMLTag: HTMLRepresentable {
    var tag: String
    var children: [HTMLRepresentable] = []

    init(tag: String) {
        self.tag = tag
    }

    init(@HTMLBuilder _ content: () -> HTMLRepresentable...) {
        self.tag = "div"
        self.children = content()
    }

    init(tag: String, @HTMLBuilder _ content: () -> HTMLRepresentable...) {
        self.tag = tag
        self.children = content()
    }
}

@resultBuilder
struct HTMLBuilder {
    static func buildBlock(_ components: HTMLRepresentable...) -> HTMLRepresentable {
        let tag = HTMLTag(tag: "html")
        components.forEach { tag.add(child: $0) }
        return tag
    }
}

func buildPage(@HTMLBuilder content: () -> HTMLRepresentable) -> String {
    let tag = content()
    return tag.htmlString
}

let page = buildPage {
    HTMLTag(tag: "head")
    HTMLTag(tag: "body") {
        HTMLTag(tag: "h1") { "Hello, world!" }
    }
}
print(page)

@HTMLBuilder 可以定义一个或多个如下方法:

  • buildExpression: 处理单个表达式的结果。这通常是处理基本类型,例如 HTML 标签的字符串,或者自定义类型例如 HTMLTag。

  • buildBlock: 把 buildExpression 的所有结果合并成一个结果。例如将多个 HTMLTag 合并为一个。

  • buildOptional: 处理可选表达式(只有 if 一个分支)。例如你有一个返回 HTMLTag? 类型的表达式,这个方法定义了如何处理 nil 。

  • buildEither: 处理条件语句(if/else 分支、switch语句)。例如有一个条件语句,根据不同的条件返回不同的 HTMLTag。

  • buildArray: 处理数组表达式,例如有一个返回 [HTMLTag] 的表达式,这个方法定义了如何处理整个数组。通常是 for…each,每次循环生成一个结果,遍历完成之后将结果收集到一个数组中进行处理。

Concurrency

ConcurrencySwift新引入的一套实现并发的机制。它包括了一系列工具和语言特性,使得在 Swift 中进行异步编程变得更容易。

async/await

Swift中的async/await语法允许你书写看上去像是同步代码的异步代码。一个函数可以被声明为async,这意味着你可以在函数体内使用await关键字。当你 await 一个异步操作的时候,你的函数会被挂起,然后在异步操作结束后再继续执行,从而让其它代码可以在这个异步操作运行时继续执行。

Task/TaskGroup

Swift中的Task是一种可以并发运行的独立工作的抽象,一个Task可以在后台执行一个异步操作。你可以创建一个新的Task来执行一个async闭包。而TaskGroup则是一种可以并发运行许多Task的容器。

AsyncSequence

AsyncSequence是一种异步生成和处理元素序列的方法。它类似于同步的Sequence协议,但其元素是异步产生的。例如,你可以创建一个从文件中逐行读取内容的AsyncSequence,每次循环时,它只会读取和处理一个行,而不需要将整个文件加载到内存中。

func findTitle(url: URL) async throws -> String? {
  for try await line in url.lines {
    if line.contains(""</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">return</span> line<span class="token punctuation">.</span><span class="token function">trimmingCharacters</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>whitespaces<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token constant">nil</span>
<span class="token punctuation">}</span>
</code></pre> 
  <p>对于没有执行顺序的异步代码,可以聚合到一起利用多个线程执行:</p> 
  <pre><code class="prism language-swift"><span class="token keyword">func</span> <span class="token function">findTitlesParallel</span><span class="token punctuation">(</span><span class="token builtin">first</span><span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">,</span> second<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">)</span> async <span class="token keyword">throws</span> <span class="token operator">-</span><span class="token operator">></span>
<span class="token punctuation">(</span><span class="token builtin">String</span><span class="token operator">?</span><span class="token punctuation">,</span>
<span class="token builtin">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  async <span class="token keyword">let</span> title1 <span class="token operator">=</span> <span class="token function">findTitle</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> <span class="token builtin">first</span><span class="token punctuation">)</span>   <span class="token comment">// 1</span>
  async <span class="token keyword">let</span> title2 <span class="token operator">=</span> <span class="token function">findTitle</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> second<span class="token punctuation">)</span>  <span class="token comment">// 2</span>
  <span class="token keyword">let</span> titles <span class="token operator">=</span> <span class="token keyword">try</span> await <span class="token punctuation">[</span>title1<span class="token punctuation">,</span> title2<span class="token punctuation">]</span>    <span class="token comment">// 3</span>
  <span class="token keyword">return</span> <span class="token punctuation">(</span>titles<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> titles<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span>              <span class="token comment">// 4</span>
<span class="token punctuation">}</span>
</code></pre> 
  <h4>Actor</h4> 
  <p>Actor是一种保证并发数据安全的模型,它通过串行化在它自身状态上执行的所有操作来提供数据安全性。Actors可以和其它Actors进行通信并对其它Actor进行异步操作,但不能直接访问其它Actors的状态。</p> 
  <p>Swift Actor 中并没有显式地使用锁来保护状态,而是通过内在设计来保证只有一个任务可以同时访问 Actor 的内部状态。这种设计更为友好,因为它避免了通常与加锁和解锁相关的竞态条件和死锁问题。</p> 
  <p>实际上,Actor 模型通过进入队列等待的方式来处理任务。当一个任务想要访问 Actor 的状态或成员函数时,这个任务将会被放入一个队列中,当其他任务完成后,此任务会按照在队列中的顺序被执行。这由编译器和运行时系统来管理,对开发者来说是透明的。</p> 
  <p>因此,也可以将 Actor 看作一个自动处理任务队列和确保数据安全的类,保证了在内部的数据访问和修改是安全的,</p> 
  <p>简单来说,尽管没有显式地锁定 Actor 中的状态,但通过这种内建的排队和任务管理机制,Actor 还是确保了其状态的访问足够安全,一个时刻只有一个任务在访问或修改状态。</p> 
  <pre><code class="prism language-swift">actor <span class="token builtin">Counter</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">var</span> value <span class="token operator">=</span> <span class="token number">0</span>
    
    <span class="token keyword">func</span> <span class="token function">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        value <span class="token operator">+</span><span class="token operator">=</span> <span class="token number">1</span>
        <span class="token function">print</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token comment">// 使用 Actor</span>
<span class="token keyword">let</span> counter <span class="token operator">=</span> <span class="token function">Counter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token builtin">Task</span> <span class="token punctuation">{</span>
    <span class="token comment">// 需要使用 await 关键字来调用 Actor 中的方法</span>
    await counter<span class="token punctuation">.</span><span class="token function">increment</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> 
  <p>Actor 可以实现协议,如果协议的方法要求是串行的,但是属性访问默认都是异步的,此时可以添加<code>nonisolated</code>关键词作<code>actor isolation</code>。</p> 
  <pre><code class="prism language-swift"><span class="token keyword">extension</span> <span class="token builtin">Counter</span><span class="token punctuation">:</span> <span class="token builtin">CustomStringConvertible</span> <span class="token punctuation">{</span>
  nonisolated <span class="token keyword">var</span> description<span class="token punctuation">:</span> <span class="token builtin">String</span> <span class="token punctuation">{</span>
    <span class="token string">"<span class="token interpolation"><span class="token delimiter variable">\(</span>value<span class="token delimiter variable">)</span></span>"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> 
  <h4>Sendable</h4> 
  <p>Sendable 协议是 Swift 中保证数据在并发环境下安全传递的一种手段。要理解这个问题,我们需要明白在并发环境下可能出现的一些问题。</p> 
  <p>当我们在说“传递数据的安全性”时,我们主要是想要避免数据非预期的并发修改。考虑这样的情况:你有两个并发执行的任务A和B。任务A创建了一个数据并送往任务B,当B使用这个数据的同时,A更改了这个数据。这样,B在使用的可能并非是你想要的数据,也许在B看到的数据和A发生变更之间存在微秒级的时间差,就可能导致数据异常或者程序错误。</p> 
  <p>即使在外部通过 Mutex(互斥锁)或者 Actor 来对数据进行保护,这样的问题仍然有可能发生。这是因为 Mutex 或 Actor 主要是保护数据的读者(接收者)和写者(发送者)之间的同步,而非保护同一份数据的多份拷贝。也就是说,即使是 Actor 并不能阻止一份数据在其他地方被修改。</p> 
  <p>为了解决这个问题,我们就要求传递的数据要是 Sendable 协议。如果一个类型符合 Sendable 协议,那么它的实例就可以安全地在多个并发执行的任务中共享。Swift 通过保证值类型在复制时拥有唯一的数据,和限制引用类型在遵守 Sendable 时是只读或者线程安全的,来防止这类问题。</p> 
  <p>举个例子,如果你有一个遵守 Sendable 的结构体,当你在任务A中创建这个结构体的实例并发送给任务B,实际传递给任务B的是这个实例的一份新的复制品,因此任务A中的原始数据修改并不会影响任务B的副本。</p> 
  <p>这就是为什么数据需要符合 Sendable 协议。这为我们在并发环境下处理数据提供了额外的安全性保障。</p> 
  <p>具体来说,Sendable 具有以下安全性保证:</p> 
  <ol> 
   <li> <p>值类型(如 Int,String,Array,等):由于值类型在传递时总是被复制,所以每个使用值的任务都有自己的独立副本,这就消除了数据竞争的可能性。因此,Swift 的许多值类型默认就遵循了 Sendable 协议。</p> </li> 
   <li> <p>引用类型(比如类和闭包):在默认情况下,引用类型是不遵从 Sendable 协议的,因为它们可能有可变状态,如果在无同步措施的情况下在多个任务间共享,可能引发数据竞争。然而,如果一个引用类型是只读的,或者内部状态的访问已经做了同步处理(例如,使用了锁或采用了 actor 模型),那么该类型就可以遵循 Sendable 协议。</p> </li> 
   <li> <p>自定义的符合 Sendable 的类型:可以使用 @Sendable 属性标记自己的自定义类型或函数以表明它们是 Sendable 的。但使用前需要确保其在并发环境下是安全的。</p> </li> 
  </ol> 
  <p>因此,只有遵守 Sendable 协议的数据才能在并发环境中安全地传递,这是因为 Sendable 的设计目标就是保证数据在并发传递过程中的安全性,避免可能的数据竞争。</p> 
 </div> 
</div>��������������������������������������������
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1750228098021867520"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(#,swift,swift,开发语言,ios)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1835513551624695808.htm"
                           title="【iOS】MVC设计模式" target="_blank">【iOS】MVC设计模式</a>
                        <span class="text-muted">Magnetic_h</span>
<a class="tag" taget="_blank" href="/search/ios/1.htm">ios</a><a class="tag" taget="_blank" href="/search/mvc/1.htm">mvc</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a><a class="tag" taget="_blank" href="/search/objective-c/1.htm">objective-c</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a>
                        <div>MVC前言如何设计一个程序的结构,这是一门专门的学问,叫做"架构模式"(architecturalpattern),属于编程的方法论。MVC模式就是架构模式的一种。它是Apple官方推荐的App开发架构,也是一般开发者最先遇到、最经典的架构。MVC各层controller层Controller/ViewController/VC(控制器)负责协调Model和View,处理大部分逻辑它将数据从Mod</div>
                    </li>
                    <li><a href="/article/1835513424734416896.htm"
                           title="UI学习——cell的复用和自定义cell" target="_blank">UI学习——cell的复用和自定义cell</a>
                        <span class="text-muted">Magnetic_h</span>
<a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a>
                        <div>目录cell的复用手动(非注册)自动(注册)自定义cellcell的复用在iOS开发中,单元格复用是一种提高表格(UITableView)和集合视图(UICollectionView)滚动性能的技术。当一个UITableViewCell或UICollectionViewCell首次需要显示时,如果没有可复用的单元格,则视图会创建一个新的单元格。一旦这个单元格滚动出屏幕,它就不会被销毁。相反,它被添</div>
                    </li>
                    <li><a href="/article/1835511030260789248.htm"
                           title="c++ 的iostream 和 c++的stdio的区别和联系" target="_blank">c++ 的iostream 和 c++的stdio的区别和联系</a>
                        <span class="text-muted">黄卷青灯77</span>
<a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/iostream/1.htm">iostream</a><a class="tag" taget="_blank" href="/search/stdio/1.htm">stdio</a>
                        <div>在C++中,iostream和C语言的stdio.h都是用于处理输入输出的库,但它们在设计、用法和功能上有许多不同。以下是两者的区别和联系:区别1.编程风格iostream(C++风格):C++标准库中的输入输出流类库,支持面向对象的输入输出操作。典型用法是cin(输入)和cout(输出),使用>操作符来处理数据。更加类型安全,支持用户自定义类型的输入输出。#includeintmain(){in</div>
                    </li>
                    <li><a href="/article/1835475582138281984.htm"
                           title="ios GCD" target="_blank">ios GCD</a>
                        <span class="text-muted">_Waiting_</span>

                        <div>1.GCD任务和队列学习GCD之前,先来了解GCD中两个核心概念:任务和队列。任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在GCD中是放在block中的。执行任务有两种方式:同步执行(sync)和异步执行(async)。两者的主要区别是:是否等待队列的任务执行结束,以及是否具备开启新线程的能力。同步执行(sync):同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等</div>
                    </li>
                    <li><a href="/article/1835431702365827072.htm"
                           title="iOS内存管理简单理解" target="_blank">iOS内存管理简单理解</a>
                        <span class="text-muted">烧烤有点辣</span>

                        <div>什么是引用计数引用计数(ReferenceCount)是一个简单而有效的管理对象生命周期的方式。当我们创建一个新对象的时候,它的引用计数为1,当有一个新的指针指向这个对象时,我们将其引用计数加1,当某个指针不再指向这个对象是,我们将其引用计数减1,当对象的引用计数变为0时,说明这个对象不再被任何指针指向了,这个时候我们就可以将对象销毁,回收内存。由于引用计数简单有效,除了Objective-C和S</div>
                    </li>
                    <li><a href="/article/1835399577348435968.htm"
                           title="[Swift]LeetCode943. 最短超级串 | Find the Shortest Superstring" target="_blank">[Swift]LeetCode943. 最短超级串 | Find the Shortest Superstring</a>
                        <span class="text-muted">黄小二哥</span>
<a class="tag" taget="_blank" href="/search/swift/1.htm">swift</a>
                        <div>★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址:https://github.com/strengthen/LeetCode➤原文地址:https://www.cnblogs.com/streng</div>
                    </li>
                    <li><a href="/article/1835399451192160256.htm"
                           title="[Swift]LeetCode767. 重构字符串 | Reorganize String" target="_blank">[Swift]LeetCode767. 重构字符串 | Reorganize String</a>
                        <span class="text-muted">weixin_30591551</span>
<a class="tag" taget="_blank" href="/search/swift/1.htm">swift</a><a class="tag" taget="_blank" href="/search/runtime/1.htm">runtime</a>
                        <div>★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址:https://github.com/strengthen/LeetCode➤原文地址:https://www.cnblogs.com/streng</div>
                    </li>
                    <li><a href="/article/1835368019430305792.htm"
                           title="Vue + Express实现一个表单提交" target="_blank">Vue + Express实现一个表单提交</a>
                        <span class="text-muted">九旬大爷的梦</span>

                        <div>最近在折腾一个cms系统,用的vue+express,但是就一个表单提交就弄了好久,记录一下。环境:Node10+前端:Vue服务端:Express依赖包:vueexpressaxiosexpress-formidableelement-ui(可选)前言:axiosget请求参数是:paramsaxiospost请求参数是:dataexpressget接受参数是req.queryexpresspo</div>
                    </li>
                    <li><a href="/article/1835367765121265664.htm"
                           title="iOS下拉放大效果" target="_blank">iOS下拉放大效果</a>
                        <span class="text-muted">RobinZhao</span>

                        <div>好多下拉放大的实现方式是在tableView上面添加一个view,同时更改tableView.contentInset,下拉时改变view的frame来实现。今天用另外一种方式实现,效果如下:加油.gif具体实现方法:通过tableViewCell结合xib来实现,具体代码如下HomeViewController.m代码#import"HomeViewController.h"#import"He</div>
                    </li>
                    <li><a href="/article/1835302695590785024.htm"
                           title="Github 2024-09-12 Go开源项目日报Top10" target="_blank">Github 2024-09-12 Go开源项目日报Top10</a>
                        <span class="text-muted">老孙正经胡说</span>
<a class="tag" taget="_blank" href="/search/github/1.htm">github</a><a class="tag" taget="_blank" href="/search/golang/1.htm">golang</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90/1.htm">开源</a><a class="tag" taget="_blank" href="/search/Github%E8%B6%8B%E5%8A%BF%E5%88%86%E6%9E%90/1.htm">Github趋势分析</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/1.htm">开源项目</a><a class="tag" taget="_blank" href="/search/Python/1.htm">Python</a><a class="tag" taget="_blank" href="/search/Golang/1.htm">Golang</a>
                        <div>根据GithubTrendings的统计,今日(2024-09-12统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下:开发语言项目数量Go项目10C项目1Terraform:基础设施即代码的开源工具创建周期:3626天开发语言:Go协议类型:OtherStar数量:40393个Fork数量:9397次关注人数:40393人贡献人数:358人OpenIssues数量:1943个Git</div>
                    </li>
                    <li><a href="/article/1835284370089406464.htm"
                           title="2018-08-16【Swift 4.1】 关于Swift4.0以后调用MJExtension无法模型转换问题" target="_blank">2018-08-16【Swift 4.1】 关于Swift4.0以后调用MJExtension无法模型转换问题</a>
                        <span class="text-muted">码农happy</span>

                        <div>1、本人使用swift4.1,弄了一晚上才弄好,结果还是一个小问题真是尴尬,要在model中每个属性前面加上@objcimportUIKitclassUserModel:NSObject{@objcvardix=String()}letdic=["dix":"ffffff"]asNSDictionaryletmodel=UserModel.mj_object(withKeyValues:dic)!</div>
                    </li>
                    <li><a href="/article/1835259969688137728.htm"
                           title="axios 请求封装" target="_blank">axios 请求封装</a>
                        <span class="text-muted">web Rookie</span>
<a class="tag" taget="_blank" href="/search/%E5%B7%A5%E4%BD%9C/1.htm">工作</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/ajax/1.htm">ajax</a>
                        <div>文章目录1.前言2.axios下载3.代码实现4.实际使用1.前言本文是对于axios的二次封装处理,axios是一个基于Promise的网络请求库,作用于node.js和浏览器中;本文对于axios中的封装着重于直接使用,如果想要学习axios相关知识可以先行离开,后续在对其进行完善2.axios下载npminstallaxios3.代码实现//request.tsimportaxios,{Ax</div>
                    </li>
                    <li><a href="/article/1835231613064146944.htm"
                           title="数据仓库介绍" target="_blank">数据仓库介绍</a>
                        <span class="text-muted">阿龙的代码在报错</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90/1.htm">数据分析</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E4%BB%93%E5%BA%93/1.htm">数据仓库</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a>
                        <div>数据仓库数据仓库的概念数据仓库的主要特征数据仓库的主流开发语言-sql结构化数据sql语句数据仓库的概念数据仓库(英语:DataWarehouse,简称数仓、DW),是一个用于存储、分析、报告的数据系统。数据仓库的目的是构建面向分析的集成化数据环境,分析结果为企业提供决策支持(DecisionSupport)。就是数据仓库只分析数据并不产生数据数据仓库的主要特征1、面向主题主题是一个抽象的概念,是</div>
                    </li>
                    <li><a href="/article/1835194426499100672.htm"
                           title="外卖霸王餐返利外卖会员卡小程序开发" target="_blank">外卖霸王餐返利外卖会员卡小程序开发</a>
                        <span class="text-muted">闹小艾</span>
<a class="tag" taget="_blank" href="/search/good506070/1.htm">good506070</a><a class="tag" taget="_blank" href="/search/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">微信小程序</a><a class="tag" taget="_blank" href="/search/%E5%B0%8F%E7%A8%8B%E5%BA%8F/1.htm">小程序</a>
                        <div>外卖霸王餐返利外卖会员卡小程序开发"社交电商赋能下的外卖返利小程序"是专为商家与用户双赢而设计的创新平台。以下是其开发方案的详细步骤:一、需求梳理:首先,我们需要明确小程序的核心功能和特色。包括设定活动类型、返利策略,以及用户体验友好的界面设计。二、技术决策:技术选型是关键。我们采用小程序的开发框架,利用JavaScript作为前端开发语言,并结合微信提供的API进行后端接口调用与数据处理。三、账</div>
                    </li>
                    <li><a href="/article/1835175340083867648.htm"
                           title="【免费】springboot项目申报管理系统|毕业设计|Javaweb项目" target="_blank">【免费】springboot项目申报管理系统|毕业设计|Javaweb项目</a>
                        <span class="text-muted">计算机学姐来啦</span>
<a class="tag" taget="_blank" href="/search/springboot/1.htm">springboot</a><a class="tag" taget="_blank" href="/search/ssm/1.htm">ssm</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/boot/1.htm">boot</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/1.htm">课程设计</a><a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E8%AE%BE/1.htm">毕设</a><a class="tag" taget="_blank" href="/search/%E6%AF%95%E4%B8%9A%E8%AE%BE%E8%AE%A1/1.htm">毕业设计</a><a class="tag" taget="_blank" href="/search/java-ee/1.htm">java-ee</a>
                        <div>收藏点赞不迷路关注作者有好处编号:springboot375springboot项目申报管理系统开发语言:Java数据库:MySQL技术:Spring+SpringMVC+MyBatis工具:IDEA/Ecilpse、Navicat、Maven1.万字文档展示(部分)2.系统图片展示第5章系统详细设计5.1管理员功能模块的实现5.1.1项目列表如图5.1显示的就是项目列表页面,此页面提供给管理员的</div>
                    </li>
                    <li><a href="/article/1835169418171215872.htm"
                           title="《C++语言的设计和演化》读书感悟(一)" target="_blank">《C++语言的设计和演化》读书感悟(一)</a>
                        <span class="text-muted">依晴无旧</span>
<a class="tag" taget="_blank" href="/search/C%5CC%2B%2B/1.htm">C\C++</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>写了一百多篇技术文章了,我突然想写一下和技术文搭一点关系的语言发展设计的文章,《C++语言的设计和演化》是我无聊翻自己库存电子书找到了,因为当年看这本书是C++之父写的,所以就保存下来,但是当时主要学习C++,这本书更多是C++之父从本身出发,对C++设计和演化的观点和感想,所以当时就被我扔去吃灰了。现在重拾起来,读起来别有风味。开发语言,虽然很多,但是万变不离其宗,学进去了,无非就是数据类型、控</div>
                    </li>
                    <li><a href="/article/1835163876656771072.htm"
                           title="函数可以返回数组吗?有哪3种返回方法呢?如代码种的func2、func3、func4都可以返回数组。func1为什么会报错呢?关于返回数组需要注意哪些呢?" target="_blank">函数可以返回数组吗?有哪3种返回方法呢?如代码种的func2、func3、func4都可以返回数组。func1为什么会报错呢?关于返回数组需要注意哪些呢?</a>
                        <span class="text-muted">神笔馬良</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/1.htm">数据结构</a>
                        <div>问题描述:根据下列代码回答下列问题。//Createdby黑马程序员.#include"iostream"usingnamespacestd;/**函数返回数组,就是返回指针,要注意:*-不可返回局部数组(在函数内创建的数组),如果要返回需要*-static修饰*-动态内存创建(new[]、delete[])*-返回全局(在函数外创建的对象)**不推荐函数返回数组,因为要么手动delete、要么s</div>
                    </li>
                    <li><a href="/article/1835152455894134784.htm"
                           title="Swift4.0: 利用图形上下文画基础图?" target="_blank">Swift4.0: 利用图形上下文画基础图?</a>
                        <span class="text-muted">Dayu大鱼</span>

                        <div>步骤:开启图片上下文获取上下文配置上下文3.1填充颜色cgColor3.2填充尺寸从图形上下文中获取图片关闭上下文返回图片importFoundationimportUIKitextensionUIImage{///画一个白色背景的图片classfuncimageWithWhiteBackGroundColor()->UIImage{//开始图形上下文UIGraphicsBeginImageCon</div>
                    </li>
                    <li><a href="/article/1835123089843777536.htm"
                           title="这些年我的无限循环歌曲" target="_blank">这些年我的无限循环歌曲</a>
                        <span class="text-muted">泽绒拥吉</span>

                        <div>这几年霉霉Taylorswift除了一养了两只猫,还发行了六张专辑,成为历史上唯一拥有四张百万销售量专辑的歌手外,她还从2008年北京奥运那年开始。纷纷扬扬,开展了大大小小六段恋爱,有人说霉霉换男朋友的速度=换衣服的速度?但不如更直接点说霉霉好眼光一如既往,跟着时间轴来看一下她的恋情,而如今霉霉更是爆出与男友JoeAlwyn已经交往历史上最长的20个月,并在爆出八月考虑结婚,连婚纱款式都已挑选堵妥</div>
                    </li>
                    <li><a href="/article/1835101595738664960.htm"
                           title="ios私钥证书(p12)导入失败,Windows OpenSSl 1.1.1 下载" target="_blank">ios私钥证书(p12)导入失败,Windows OpenSSl 1.1.1 下载</a>
                        <span class="text-muted">书边事.</span>
<a class="tag" taget="_blank" href="/search/%E5%85%B6%E4%BB%96/1.htm">其他</a>
                        <div>ios私钥证书(p12)导入失败如果你用的OpenSSL版本是v3那么恭喜你V3必然报这个错,解决办法将OpenSSL3降低成v1。WindowsOpenSSl1.1.1下载阿里云网盘下载地址:OpenSSLV1</div>
                    </li>
                    <li><a href="/article/1835077143051202560.htm"
                           title="网上商城项目总结报告" target="_blank">网上商城项目总结报告</a>
                        <span class="text-muted">WEB前端程序贵</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>网上商城项目总结报告1:掌握的知识通过网上商城这个实战项目的开发,不仅了解到了一个项目的业务逻辑,而且掌握了实现相关业务功能的方法。通过这个实战项目,了解到了模块化开发项目的基础结构的搭建,以及项目文件的管理方式。通过这个实战项目,运用封装的接口api文档实现了客户端服务器之间的交互知识。通过封装的axios实例对象与方法,向服务器请求数据,然后渲染页面。通过运用localStorage本地储存的</div>
                    </li>
                    <li><a href="/article/1835070715255156736.htm"
                           title="Linux dmesg命令:显示开机信息" target="_blank">Linux dmesg命令:显示开机信息</a>
                        <span class="text-muted">fafadsj666</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/1.htm">数据挖掘</a><a class="tag" taget="_blank" href="/search/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/1.htm">机器学习</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a>
                        <div>通过学习《Linux启动管理》一章可以知道,在系统启动过程中,内核还会进行一次系统检测(第一次是BIOS进行加测),但是检测的过程不是没有显示在屏幕上,就是会快速的在屏幕上一闪而过那么,如果开机时来不及查看相关信息,我们是否可以在开机后查看呢?答案是肯定的,使用dmesg命令就可以。无论是系统启动过程中,还是系统运行过程中,只要是内核产生的信息,都会被存储在系统缓冲区中,已经为大家精心准备了大数据</div>
                    </li>
                    <li><a href="/article/1835053432449363968.htm"
                           title="(小白入门)Windows环境下搭建React Native Android开发环境" target="_blank">(小白入门)Windows环境下搭建React Native Android开发环境</a>
                        <span class="text-muted">码农老黑</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/Native/1.htm">Native</a><a class="tag" taget="_blank" href="/search/%E7%A7%BB%E5%8A%A8%E5%BC%80%E5%8F%91/1.htm">移动开发</a><a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/studio/1.htm">studio</a>
                        <div>ReactNative(简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,是Facebook早先开源的UI框架React在原生移动应用平台的衍生产物,目前支持iOS和Android两大平台。RN的环境搭建在RN的中文社区有所介绍,但是对于小白来说还是有些太过简略了。RN中文社区详见参考,本文不涉及的问题也许在其中能够有所解答。ReactNative思想底层引擎是JavaSc</div>
                    </li>
                    <li><a href="/article/1835029737634885632.htm"
                           title="招银网络&大疆&元象一面" target="_blank">招银网络&大疆&元象一面</a>
                        <span class="text-muted">Redstone Monstrosity</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a>
                        <div>1.请尽可能详细地说明,XHR、axios和fetch这三者的区别是什么?axios和fetch的底层实现是什么?axios拦截器是什么?axios提供了哪些配置或功能,是fetch和XHR中没有的?你的回答中不要写出示例代码。XHR、axios和fetch的区别XHR(XMLHttpRequest)历史:XHR是最早的AJAX技术,由微软在1999年引入,后来被标准化。兼容性:几乎所有现代浏览器</div>
                    </li>
                    <li><a href="/article/1835022544919425024.htm"
                           title="思科路由器交换机密码破解过程详解" target="_blank">思科路由器交换机密码破解过程详解</a>
                        <span class="text-muted">zhane_hao</span>

                        <div>路由启动过程加电自检(POST)加载bootstrap代码检查配置寄存器寻找CiscoIOS加载CiscoIOS寻找配置文件加载配置文件若没有配置文件,进入Setup模式,进行初始化配置运行路由器操作系统查看命令•showversion:检查配置寄存器的值,硬件配置,IOS版本•showflash:检查Flash中的IOS,或是flash大小,使用情况(占用多少,剩下多少)•showstartup</div>
                    </li>
                    <li><a href="/article/1835005152646492160.htm"
                           title="python学习第七节:正则表达式" target="_blank">python学习第七节:正则表达式</a>
                        <span class="text-muted">一只会敲代码的小灰灰</span>
<a class="tag" taget="_blank" href="/search/python%E5%AD%A6%E4%B9%A0/1.htm">python学习</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0/1.htm">学习</a><a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a>
                        <div>python学习第七节:正则表达式正则表达式基本上在所有开发语言中都会使用到,在python中尤为重要。当我们使用python开发爬虫程序将目标网页扒下来之后我们要从网页中解析出我们想要的信息,这个时候就需要正则表达式去进行匹配。importrere的常量re模块中有9个常量,常量的值都是int类型!(知道就行)修饰符描述re.l使匹配对大小写不敏感re.L做本地化识别(locale-aware)</div>
                    </li>
                    <li><a href="/article/1834997709858238464.htm"
                           title="定制优化Nextcloud镜像" target="_blank">定制优化Nextcloud镜像</a>
                        <span class="text-muted">攻城狮_正</span>

                        <div>Nextcloud是一款开源免费的私有云存储网盘项目,可以让你快速便捷地搭建一套属于自己或团队的云同步网盘,从而实现跨平台跨设备文件同步、共享、版本控制、团队协作等功能。它的客户端覆盖了Windows、Mac、Android、iOS、Linux等各种平台,也提供了网页端以及WebDAV接口,所以你几乎可以在各种设备上方便地访问你的云盘。Nextcloud基于PHP语言开发,可以使用Nginx+PH</div>
                    </li>
                    <li><a href="/article/1834961794687397888.htm"
                           title="iOS使用SDWebview加载图片失败?" target="_blank">iOS使用SDWebview加载图片失败?</a>
                        <span class="text-muted">AnderQZ</span>

                        <div>今天调试遇到一个很无奈的问题,就是出现了image无法加载出来。最后才发现是图片使用了中文命名,真TM的坑!SDWebimage没办法识别中文,必须要encode才行!</div>
                    </li>
                    <li><a href="/article/1834955083956187136.htm"
                           title="Dev-C++头文件小Bug" target="_blank">Dev-C++头文件小Bug</a>
                        <span class="text-muted">蒟蒻pzjdsg666</span>
<a class="tag" taget="_blank" href="/search/bug/1.htm">bug</a><a class="tag" taget="_blank" href="/search/c%E8%AF%AD%E8%A8%80/1.htm">c语言</a><a class="tag" taget="_blank" href="/search/c%2B%2B/1.htm">c++</a>
                        <div>Dev-C++应该是大家最常用的C++软件了吧,但它有几个小Bug。1、“万能头”众所周知,“万能头”在官方比赛中不能使用(你要用没人拦着你~呵呵),但在Dev-C++可以使用。所以,我们可以省掉好多头文件!如下:#includeusingnamespacestd;2、C语言头文件在Dev-C++中,你竟然可以使用C语言头文件(惊不惊喜~意不意外~)如下:#include3、iostream竟然包</div>
                    </li>
                    <li><a href="/article/1834874286859448320.htm"
                           title="vue axios跨域访问相关问题 | axios默认发送‘application/x-www-form-urlencoded‘格式数据 | Content-Type is not allowed b" target="_blank">vue axios跨域访问相关问题 | axios默认发送‘application/x-www-form-urlencoded‘格式数据 | Content-Type is not allowed b</a>
                        <span class="text-muted">就是爱吃肉ro</span>
<a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a><a class="tag" taget="_blank" href="/search/%26amp%3B/1.htm">&</a><a class="tag" taget="_blank" href="/search/uni-app/1.htm">uni-app</a><a class="tag" taget="_blank" href="/search/axios/1.htm">axios</a><a class="tag" taget="_blank" href="/search/ajax/1.htm">ajax</a><a class="tag" taget="_blank" href="/search/cors%E8%B7%A8%E5%9F%9F/1.htm">cors跨域</a><a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/x-www-form-url/1.htm">x-www-form-url</a>
                        <div>文章目录概述报错1Content-TypeisnotallowedbyAccess-Control-Allow-Headersinpreflightrespon报错2返回状态码500好久没更博客了,最近一直搞框架搞项目,好多问题也都没有记录下来…好吧,那从今天起来,继续开始保持记录的好习惯,先写一下在axios上踩下了这么多坑.概述通过以下两个报错,来介绍解决使用axios来进行网络请求中的遇到的</div>
                    </li>
                                <li><a href="/article/101.htm"
                                       title="数据采集高并发的架构应用" target="_blank">数据采集高并发的架构应用</a>
                                    <span class="text-muted">3golden</span>
<a class="tag" taget="_blank" href="/search/.net/1.htm">.net</a>
                                    <div>问题的出发点: 
 
         最近公司为了发展需要,要扩大对用户的信息采集,每个用户的采集量估计约2W。如果用户量增加的话,将会大量照成采集量成3W倍的增长,但是又要满足日常业务需要,特别是指令要及时得到响应的频率次数远大于预期。 
      &n</div>
                                </li>
                                <li><a href="/article/228.htm"
                                       title="不停止 MySQL 服务增加从库的两种方式" target="_blank">不停止 MySQL 服务增加从库的两种方式</a>
                                    <span class="text-muted">brotherlamp</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/linux%E8%A7%86%E9%A2%91/1.htm">linux视频</a><a class="tag" taget="_blank" href="/search/linux%E8%B5%84%E6%96%99/1.htm">linux资料</a><a class="tag" taget="_blank" href="/search/linux%E6%95%99%E7%A8%8B/1.htm">linux教程</a><a class="tag" taget="_blank" href="/search/linux%E8%87%AA%E5%AD%A6/1.htm">linux自学</a>
                                    <div>现在生产环境MySQL数据库是一主一从,由于业务量访问不断增大,故再增加一台从库。前提是不能影响线上业务使用,也就是说不能重启MySQL服务,为了避免出现其他情况,选择在网站访问量低峰期时间段操作。 
 一般在线增加从库有两种方式,一种是通过mysqldump备份主库,恢复到从库,mysqldump是逻辑备份,数据量大时,备份速度会很慢,锁表的时间也会很长。另一种是通过xtrabacku</div>
                                </li>
                                <li><a href="/article/355.htm"
                                       title="Quartz——SimpleTrigger触发器" target="_blank">Quartz——SimpleTrigger触发器</a>
                                    <span class="text-muted">eksliang</span>
<a class="tag" taget="_blank" href="/search/SimpleTrigger/1.htm">SimpleTrigger</a><a class="tag" taget="_blank" href="/search/TriggerUtils/1.htm">TriggerUtils</a><a class="tag" taget="_blank" href="/search/quartz/1.htm">quartz</a>
                                    <div>转载请出自出处:http://eksliang.iteye.com/blog/2208166 一.概述 
SimpleTrigger触发器,当且仅需触发一次或者以固定时间间隔周期触发执行; 
  二.SimpleTrigger的构造函数 
 
 SimpleTrigger(String name, String group):通过该构造函数指定Trigger所属组和名称; 
 Simpl</div>
                                </li>
                                <li><a href="/article/482.htm"
                                       title="Informatica应用(1)" target="_blank">Informatica应用(1)</a>
                                    <span class="text-muted">18289753290</span>
<a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/workflow/1.htm">workflow</a><a class="tag" taget="_blank" href="/search/lookup/1.htm">lookup</a><a class="tag" taget="_blank" href="/search/%E7%BB%84%E4%BB%B6/1.htm">组件</a><a class="tag" taget="_blank" href="/search/Informatica/1.htm">Informatica</a>
                                    <div>1.如果要在workflow中调用shell脚本有一个command组件,在里面设置shell的路径;调度wf可以右键出现schedule,现在用的是HP的tidal调度wf的执行。 
2.designer里面的router类似于SSIS中的broadcast(多播组件);Reset_Workflow_Var:参数重置 (比如说我这个参数初始是1在workflow跑得过程中变成了3我要在结束时还要</div>
                                </li>
                                <li><a href="/article/609.htm"
                                       title="python 获取图片验证码中文字" target="_blank">python 获取图片验证码中文字</a>
                                    <span class="text-muted">酷的飞上天空</span>
<a class="tag" taget="_blank" href="/search/python/1.htm">python</a>
                                    <div>根据现成的开源项目 http://code.google.com/p/pytesser/改写 
在window上用easy_install安装不上  看了下源码发现代码很少  于是就想自己改写一下 
  
添加支持网络图片的直接解析 
  
  
#coding:utf-8 
#import sys 
#reload(sys) 
#sys.s</div>
                                </li>
                                <li><a href="/article/736.htm"
                                       title="AJAX" target="_blank">AJAX</a>
                                    <span class="text-muted">永夜-极光</span>
<a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a>
                                    <div>1.AJAX功能:动态更新页面,减少流量消耗,减轻服务器负担 
  
2.代码结构: 
   
<html>

<head>
<script type="text/javascript">
function loadXMLDoc()
{
.... AJAX script goes here ...
</div>
                                </li>
                                <li><a href="/article/863.htm"
                                       title="创业OR读研" target="_blank">创业OR读研</a>
                                    <span class="text-muted">随便小屋</span>
<a class="tag" taget="_blank" href="/search/%E5%88%9B%E4%B8%9A/1.htm">创业</a>
                                    <div>        现在研一,有种想创业的想法,不知道该不该去实施。因为对于的我情况这两者是矛盾的,可能就是鱼与熊掌不能兼得。 
       
        研一的生活刚刚过去两个月,我们学校主要的是</div>
                                </li>
                                <li><a href="/article/990.htm"
                                       title="需求做得好与坏直接关系着程序员生活质量" target="_blank">需求做得好与坏直接关系着程序员生活质量</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/IT+%E7%94%9F%E6%B4%BB/1.htm">IT 生活</a>
                                    <div>  
        这个故事还得从去年换工作的事情说起,由于自己不太喜欢第一家公司的环境我选择了换一份工作。去年九月份我入职现在的这家公司,专门从事金融业内软件的开发。十一月份我们整个项目组前往北京做现场开发,从此苦逼的日子开始了。 
       系统背景:五月份就有同事前往甲方了解需求一直到6月份,后续几个月也完</div>
                                </li>
                                <li><a href="/article/1117.htm"
                                       title="如何定义和区分高级软件开发工程师" target="_blank">如何定义和区分高级软件开发工程师</a>
                                    <span class="text-muted">aoyouzi</span>

                                    <div>在软件开发领域,高级开发工程师通常是指那些编写代码超过 3 年的人。这些人可能会被放到领导的位置,但经常会产生非常糟糕的结果。Matt Briggs 是一名高级开发工程师兼 Scrum 管理员。他认为,单纯使用年限来划分开发人员存在问题,两个同样具有 10 年开发经验的开发人员可能大不相同。近日,他发表了一篇博文,根据开发者所能发挥的作用划分软件开发工程师的成长阶段。 
  初</div>
                                </li>
                                <li><a href="/article/1244.htm"
                                       title="Servlet的请求与响应" target="_blank">Servlet的请求与响应</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/servlet/1.htm">servlet</a><a class="tag" taget="_blank" href="/search/get%E6%8F%90%E4%BA%A4/1.htm">get提交</a><a class="tag" taget="_blank" href="/search/java%E5%A4%84%E7%90%86post%E6%8F%90%E4%BA%A4/1.htm">java处理post提交</a>
                                    <div>  
Servlet是tomcat中的一个重要组成,也是负责客户端和服务端的中介 
  
  
1,Http的请求方式(get  ,post); 
  客户端的请求一般都会都是Servlet来接受的,在接收之前怎么来确定是那种方式提交的,以及如何反馈,Servlet中有相应的方法,  http的get方式 servlet就是都doGet(</div>
                                </li>
                                <li><a href="/article/1371.htm"
                                       title="web.xml配置详解之listener" target="_blank">web.xml配置详解之listener</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/web.xml/1.htm">web.xml</a><a class="tag" taget="_blank" href="/search/listener/1.htm">listener</a>
                                    <div>一.定义 
<listener>  
	<listen-class>com.myapp.MyListener</listen-class>  
</listener> 
  
二.作用        该元素用来注册一个监听器类。可以收到事件什么时候发生以及用什么作为响</div>
                                </li>
                                <li><a href="/article/1498.htm"
                                       title="Web页面性能优化(yahoo技术)" target="_blank">Web页面性能优化(yahoo技术)</a>
                                    <span class="text-muted">Bill_chen</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/Ajax/1.htm">Ajax</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a><a class="tag" taget="_blank" href="/search/Yahoo/1.htm">Yahoo</a>
                                    <div>1.尽可能的减少HTTP请求数 content 
2.使用CDN server 
3.添加Expires头(或者 Cache-control) server 
4.Gzip 组件 server 
5.把CSS样式放在页面的上方。 css 
6.将脚本放在底部(包括内联的) javascript 
7.避免在CSS中使用Expressions css 
8.将javascript和css独立成外部文</div>
                                </li>
                                <li><a href="/article/1625.htm"
                                       title="【MongoDB学习笔记八】MongoDB游标、分页查询、查询结果排序" target="_blank">【MongoDB学习笔记八】MongoDB游标、分页查询、查询结果排序</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/mongodb/1.htm">mongodb</a>
                                    <div>游标 
  
游标,简单的说就是一个查询结果的指针。游标作为数据库的一个对象,使用它是包括 
 
 声明 
 打开 
 循环抓去一定数目的文档直到结果集中的所有文档已经抓取完 
 关闭游标 
 
  
游标的基本用法,类似于JDBC的ResultSet(hasNext判断是否抓去完,next移动游标到下一条文档),在获取一个文档集时,可以提供一个类似JDBC的FetchSize</div>
                                </li>
                                <li><a href="/article/1752.htm"
                                       title="ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 的解决方法" target="_blank">ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 的解决方法</a>
                                    <span class="text-muted">白糖_</span>
<a class="tag" taget="_blank" href="/search/ORA-12514/1.htm">ORA-12514</a>
                                    <div> 今天通过Oracle SQL*Plus连接远端服务器的时候提示“监听程序当前无法识别连接描述符中请求服务”,遂在网上找到了解决方案: 
 ①打开Oracle服务器安装目录\NETWORK\ADMIN\listener.ora文件,你会看到如下信息: 
  
# listener.ora Network Configuration File: D:\database\Oracle\net</div>
                                </li>
                                <li><a href="/article/1879.htm"
                                       title="Eclipse 问题 A resource exists with a different case" target="_blank">Eclipse 问题 A resource exists with a different case</a>
                                    <span class="text-muted">bozch</span>
<a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a>
                                    <div>在使用Eclipse进行开发的时候,出现了如下的问题: 
Description Resource Path Location TypeThe project was not built due to "A resource exists with a different case: '/SeenTaoImp_zhV2/bin/seentao'.&</div>
                                </li>
                                <li><a href="/article/2006.htm"
                                       title="编程之美-小飞的电梯调度算法" target="_blank">编程之美-小飞的电梯调度算法</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E/1.htm">编程之美</a>
                                    <div>

public class AptElevator {

	/**
	 * 编程之美 小飞 电梯调度算法
	 * 在繁忙的时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。
	 * 所有乘客都从一楼上电梯,到达某层楼后,电梯听下来,所有乘客再从这里爬楼梯到自己的目的层。
	 * 在一楼时,每个乘客选择自己的目的层,电梯则自动计算出应停的楼层。
	 * 问:电梯停在哪</div>
                                </li>
                                <li><a href="/article/2133.htm"
                                       title="SQL注入相关概念" target="_blank">SQL注入相关概念</a>
                                    <span class="text-muted">chenbowen00</span>
<a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/Web/1.htm">Web</a><a class="tag" taget="_blank" href="/search/%E5%AE%89%E5%85%A8/1.htm">安全</a>
                                    <div>SQL Injection:就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。 
 
具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。 
 
首先让我们了解什么时候可能发生SQ</div>
                                </li>
                                <li><a href="/article/2260.htm"
                                       title="[光与电]光子信号战防御原理" target="_blank">[光与电]光子信号战防御原理</a>
                                    <span class="text-muted">comsci</span>
<a class="tag" taget="_blank" href="/search/%E5%8E%9F%E7%90%86/1.htm">原理</a>
                                    <div> 
 
      无论是在战场上,还是在后方,敌人都有可能用光子信号对人体进行控制和攻击,那么采取什么样的防御方法,最简单,最有效呢? 
 
      我们这里有几个山寨的办法,可能有些作用,大家如果有兴趣可以去实验一下 
 
      根据光</div>
                                </li>
                                <li><a href="/article/2387.htm"
                                       title="oracle 11g新特性:Pending Statistics" target="_blank">oracle 11g新特性:Pending Statistics</a>
                                    <span class="text-muted">daizj</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/dbms_stats/1.htm">dbms_stats</a>
                                    <div>oracle 11g新特性:Pending Statistics 转 
 
从11g开始,表与索引的统计信息收集完毕后,可以选择收集的统信息立即发布,也可以选择使新收集的统计信息处于pending状态,待确定处于pending状态的统计信息是安全的,再使处于pending状态的统计信息发布,这样就会避免一些因为收集统计信息立即发布而导致SQL执行计划走错的灾难。 
 
在 11g 之前的版本中,D</div>
                                </li>
                                <li><a href="/article/2514.htm"
                                       title="快速理解RequireJs" target="_blank">快速理解RequireJs</a>
                                    <span class="text-muted">dengkane</span>
<a class="tag" taget="_blank" href="/search/jquery/1.htm">jquery</a><a class="tag" taget="_blank" href="/search/requirejs/1.htm">requirejs</a>
                                    <div>RequireJs已经流行很久了,我们在项目中也打算使用它。它提供了以下功能: 
 
 声明不同js文件之间的依赖 
 可以按需、并行、延时载入js库 
 可以让我们的代码以模块化的方式组织 
 
初看起来并不复杂。 在html中引入requirejs 
在HTML中,添加这样的 <script> 标签: 
<script src="/path/to</div>
                                </li>
                                <li><a href="/article/2641.htm"
                                       title="C语言学习四流程控制if条件选择、for循环和强制类型转换" target="_blank">C语言学习四流程控制if条件选择、for循环和强制类型转换</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/c/1.htm">c</a>
                                    <div># include <stdio.h>

int main(void)
{
	int i, j;

	scanf("%d %d", &i, &j);

	if (i > j)
		printf("i大于j\n");
	else
		printf("i小于j\n");

	retu</div>
                                </li>
                                <li><a href="/article/2768.htm"
                                       title="dictionary的使用要注意" target="_blank">dictionary的使用要注意</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/IO/1.htm">IO</a>
                                    <div>NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                          user.user_id , @"id",
                          user.username , @"username",
         </div>
                                </li>
                                <li><a href="/article/2895.htm"
                                       title="Android 中的资源访问(Resource)" target="_blank">Android 中的资源访问(Resource)</a>
                                    <span class="text-muted">finally_m</span>
<a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a><a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/String/1.htm">String</a><a class="tag" taget="_blank" href="/search/drawable/1.htm">drawable</a><a class="tag" taget="_blank" href="/search/color/1.htm">color</a>
                                    <div> 
简单的说,Android中的资源是指非代码部分。例如,在我们的Android程序中要使用一些图片来设置界面,要使用一些音频文件来设置铃声,要使用一些动画来显示特效,要使用一些字符串来显示提示信息。那么,这些图片、音频、动画和字符串等叫做Android中的资源文件。 
在Eclipse创建的工程中,我们可以看到res和assets两个文件夹,是用来保存资源文件的,在assets中保存的一般是原生</div>
                                </li>
                                <li><a href="/article/3022.htm"
                                       title="Spring使用Cache、整合Ehcache" target="_blank">Spring使用Cache、整合Ehcache</a>
                                    <span class="text-muted">234390216</span>
<a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/cache/1.htm">cache</a><a class="tag" taget="_blank" href="/search/ehcache/1.htm">ehcache</a><a class="tag" taget="_blank" href="/search/%40Cacheable/1.htm">@Cacheable</a>
                                    <div>Spring使用Cache 
  
  
       从3.1开始,Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的</div>
                                </li>
                                <li><a href="/article/3149.htm"
                                       title="当druid遇上oracle blob(clob)" target="_blank">当druid遇上oracle blob(clob)</a>
                                    <span class="text-muted">jackyrong</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a>
                                    <div>http://blog.csdn.net/renfufei/article/details/44887371 
 
众所周知,Oracle有很多坑, 所以才有了去IOE。 
 
在使用Druid做数据库连接池后,其实偶尔也会碰到小坑,这就是使用开源项目所必须去填平的。【如果使用不开源的产品,那就不是坑,而是陷阱了,你都不知道怎么去填坑】 
 
用Druid连接池,通过JDBC往Oracle数据库的</div>
                                </li>
                                <li><a href="/article/3276.htm"
                                       title="easyui datagrid pagination获得分页页码、总页数等信息" target="_blank">easyui datagrid pagination获得分页页码、总页数等信息</a>
                                    <span class="text-muted">ldzyz007</span>

                                    <div>var grid = $('#datagrid');  
var options = grid.datagrid('getPager').data("pagination").options;  
var curr = options.pageNumber;  
var total = options.total;  
var max =</div>
                                </li>
                                <li><a href="/article/3403.htm"
                                       title="浅析awk里的数组" target="_blank">浅析awk里的数组</a>
                                    <span class="text-muted">nigelzeng</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%8C%E7%BB%B4%E6%95%B0%E7%BB%84/1.htm">二维数组</a><a class="tag" taget="_blank" href="/search/array/1.htm">array</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E7%BB%84/1.htm">数组</a><a class="tag" taget="_blank" href="/search/awk/1.htm">awk</a>
                                    <div>awk绝对是文本处理中的神器,它本身也是一门编程语言,还有许多功能本人没有使用到。这篇文章就单单针对awk里的数组来进行讨论,如何利用数组来帮助完成文本分析。 
  
有这么一组数据: 
   abcd,91#31#2012-12-31 11:24:00 
case_a,136#19#2012-12-31 11:24:00 
case_a,136#23#2012-12-31 1</div>
                                </li>
                                <li><a href="/article/3530.htm"
                                       title="搭建 CentOS 6 服务器(6) - TigerVNC" target="_blank">搭建 CentOS 6 服务器(6) - TigerVNC</a>
                                    <span class="text-muted">rensanning</span>
<a class="tag" taget="_blank" href="/search/centos/1.htm">centos</a>
                                    <div>安装GNOME桌面环境 
 
# yum groupinstall "X Window System" "Desktop" 
 
 
安装TigerVNC 
 
# yum -y install tigervnc-server tigervnc 
 
 
启动VNC服务 
 
# /etc/init.d/vncserver restart
# vncser</div>
                                </li>
                                <li><a href="/article/3657.htm"
                                       title="Spring 数据库连接整理" target="_blank">Spring 数据库连接整理</a>
                                    <span class="text-muted">tomcat_oracle</span>
<a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/bean/1.htm">bean</a><a class="tag" taget="_blank" href="/search/jdbc/1.htm">jdbc</a>
                                    <div>1、数据库连接jdbc.properties配置详解    jdbc.url=jdbc:hsqldb:hsql://localhost/xdb     jdbc.username=sa     jdbc.password=     jdbc.driver=不同的数据库厂商驱动,此处不一一列举     接下来,详细配置代码如下:      
Spring连接池      </div>
                                </li>
                                <li><a href="/article/3784.htm"
                                       title="Dom4J解析使用xpath java.lang.NoClassDefFoundError: org/jaxen/JaxenException异常" target="_blank">Dom4J解析使用xpath java.lang.NoClassDefFoundError: org/jaxen/JaxenException异常</a>
                                    <span class="text-muted">xp9802</span>

                                    <div>用Dom4J解析xml,以前没注意,今天使用dom4j包解析xml时在xpath使用处报错 
     异常栈:java.lang.NoClassDefFoundError: org/jaxen/JaxenException异常  
     导入包 jaxen-1.1-beta-6.jar 解决; 
&nb</div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>