Swift-オプションのチェーン

'nil'である可能性のあるオプションのクエリ、プロパティ、添え字、およびメソッドの呼び出しのプロセスは、オプションの連鎖として定義されます。オプションの連鎖は2つの値を返します-

  • オプションに「値」が含まれている場合、関連するプロパティ、メソッド、および添え字を呼び出すと値が返されます

  • オプションに「nil」値が含まれている場合、それに関連するすべてのプロパティ、メソッド、および添え字はnilを返します

メソッド、プロパティ、および添え字への複数のクエリがグループ化されるため、1つのチェーンに失敗すると、チェーン全体に影響し、「nil」値になります。

強制アンラッピングの代替としてのオプションのチェーン

オプションの連鎖は、オプション値の後に「?」を付けて指定します。オプションの値がいくつかの値を返すときに、プロパティ、メソッド、または添え字を呼び出すため。

オプションのチェーン '?' メソッド、プロパティ、添え字へのアクセスオプションのチェーン '!' アンラッピングを強制する
?プロパティ、メソッド、または添え字を呼び出すためのオプション値の後に配置されます !値のアンラップを強制するためにプロパティ、メソッド、または添え字を呼び出すためのオプションの値の後に配置されます
オプションが「nil」の場合、正常に失敗します オプションが「nil」の場合、強制アンラップは実行時エラーをトリガーします

'!'を使用したオプションのチェーンのプログラム

class ElectionPoll {
   var candidate: Pollbooth?
}

lass Pollbooth {
   var name = "MP"
}

let cand = ElectionPoll()
let candname = cand.candidate!.name

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

fatal error: unexpectedly found nil while unwrapping an Optional value
0 Swift 4 0x0000000103410b68
llvm::sys::PrintStackTrace(__sFILE*) + 40
1 Swift 4 0x0000000103411054 SignalHandler(int) + 452
2 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26
3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939
4 libsystem_platform.dylib 0x00000001074a0214 _sigtramp + 1976783636
5 Swift 4 0x0000000102a85c39
llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329
6 Swift 4 0x0000000102d320b3
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::__1::vector<std::__1::basic_string, std::__1::allocator >,
std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&,
char const* const*) + 1523
7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift
4::CompilerInstance&, std::__1::vector<std::__1::basic_string,
std::__1::allocator >, std::__1::allocator<std::__1::basic_string,
std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions
const&) + 1066
8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef,
char const*, void*) + 5275
9 Swift 4 0x0000000102754a6d main + 1677
10 libdyld.dylib 0x00007fff8bb9e5c9 start + 1
11 libdyld.dylib 0x000000000000000c start + 1950751300
Stack dump:
0. Program arguments:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 -
target-cpu core2 -sdk
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/
SDKs/MacOSX10.10.sdk -module-name main
/bin/sh: line 47: 15672 Done cat <<'SWIFT 4'
import Foundation
</std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std::
__1::basic_string

上記のプログラムは、クラス名として「選挙投票」を宣言し、メンバーシップ関数として「候補者」を含んでいます。サブクラスは、「MP」として初期化されるメンバーシップ関数として「投票ブース」および「名前」として宣言されます。スーパークラスの呼び出しは、オプションの「!」を使用してインスタンス「cand」を作成することによって初期化されます。値は基本クラスで宣言されていないため、「nil」値が格納され、強制アンラップ手順によって致命的なエラーが返されます。

'?'を使用したオプションのチェーンのプログラム

class ElectionPoll {
   var candidate: Pollbooth?
}

class Pollbooth {
   var name = "MP"
}
let cand = ElectionPoll()

if let candname = cand.candidate?.name {
   print("Candidate name is \(candname)")
} else {
   print("Candidate name cannot be retreived")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Candidate name cannot be retreived

上記のプログラムは、クラス名として「選挙投票」を宣言し、メンバーシップ関数として「候補者」を含んでいます。サブクラスは、「MP」として初期化されるメンバーシップ関数として「投票ブース」および「名前」として宣言されます。スーパークラスの呼び出しは、オプションの「?」を使用してインスタンス「cand」を作成することによって初期化されます。値は基本クラスで宣言されていないため、「nil」値はelseハンドラブロックによってコンソールに格納および出力されます。

オプションのチェーンとプロパティへのアクセスのためのモデルクラスの定義

Swift 4言語は、オプションのチェーンの概念も提供し、複数のサブクラスをモデルクラスとして宣言します。この概念は、複雑なモデルを定義し、プロパティ、メソッド、および添え字のサブプロパティにアクセスするのに非常に役立ちます。

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var street: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let rectname = rectangle()
if let rectarea = rectname.print?.cprint {
   print("Area of rectangle is \(rectarea)")
} else {
   print("Rectangle Area is not specified")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Rectangle Area is not specified

オプションのチェーンによるメソッドの呼び出し

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }

   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Area of circle is not specified

circle()サブクラス内で宣言された関数circleprint()は、「circname」という名前のインスタンスを作成することによって呼び出されます。この関数は、値が含まれている場合は値を返し、含まれていない場合は、ステートメント 'if circname.print?.circleprint()!= nil'をチェックしてユーザー定義の印刷メッセージを返します。

オプションの連鎖による添え字へのアクセス

オプションの連鎖は、添え字値を設定および取得して、その添え字の呼び出しが値を返すかどうかを検証するために使用されます。「?」特定の添え字のオプション値にアクセスするために、添え字中括弧の前に配置されます。

プログラム1

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname =  radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Radius is not specified.

上記のプログラムでは、メンバーシップ関数 'radiusName'のインスタンス値が指定されていません。したがって、関数へのプログラム呼び出しはelse部分のみを返しますが、値を返すには、特定のメンバーシップ関数の値を定義する必要があります。

プログラム2

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Radius is measured in Units.

上記のプログラムでは、メンバーシップ関数 'radiusName'のインスタンス値が指定されています。したがって、関数へのプログラム呼び出しは値を返すようになりました。

オプションタイプの添え字へのアクセス

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }

   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")

let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]]
area["Radius"]?[1] = 78
area["Circle"]?[1]--

print(area["Radius"]?[0])
print(area["Radius"]?[1])
print(area["Radius"]?[2])
print(area["Radius"]?[3])

print(area["Circle"]?[0])
print(area["Circle"]?[1])
print(area["Circle"]?[2])

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Optional(35)
Optional(78)
Optional(78)
Optional(101)
Optional(90)
Optional(44)
Optional(56)

下付き文字のオプションの値には、下付き文字の値を参照することでアクセスできます。下付き文字[0]、下付き文字[1]などとしてアクセスできます。「radius」のデフォルトの添え字値は、最初に[35、45、78、101]および「Circle」[90、45、56]]として割り当てられます。 。次に、添え字の値がRadius [0]から78に、Circle [1]から45に変更されます。

複数レベルのチェーンのリンク

オプションの連鎖により、複数のサブクラスをそのスーパークラスのメソッド、プロパティ、および添え字とリンクすることもできます。

オプションの複数のチェーンをリンクできます-

タイプの取得がオプションでない場合、オプションのチェーンはオプションの値を返します。たとえば、オプションのチェーンを介して文字列を返す場合、文字列を返しますか?値

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Radius is not specified.

上記のプログラムでは、メンバーシップ関数 'radiusName'のインスタンス値が指定されていません。したがって、関数へのプログラム呼び出しはelse部分のみを返しますが、値を返すには、特定のメンバーシップ関数の値を定義する必要があります。

取得タイプがすでにオプションである場合、オプションのチェーンもオプションの値を返します。たとえば、文字列の場合?オプションのチェーンを介してアクセスすると、文字列が返されますか?値..

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Radius is measured in Units.

上記のプログラムでは、メンバーシップ関数 'radiusName'のインスタンス値が指定されています。したがって、関数へのプログラム呼び出しは値を返すようになりました。

オプションの戻り値を持つメソッドの連鎖

オプションのチェーンは、サブクラスで定義されたメソッドにアクセスするためにも使用されます。

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

遊び場を使用して上記のプログラムを実行すると、次の結果が得られます-

Area of circle is not specified