1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Swift vs. C# : Initialization

Posted at

Initialization is the process of preparing an instance of a class, structure, or enumeration for use.

Unlike Objective-C initializers, Swift initializers do not return a value.

  • C#も同じ

Setting Initial Values for Stored Properties

Classes and structures must set all of their stored properties to an appropriate initial value by the time an instance of that class or structure is created.

Stored Propertyはイニシャライザかデフォルト値で必ず設定されないといけない。

Initializers

Swift:

struct Point { 
   var X: Int
   init(){ X = 100 }
}

C#: コンストラクタ

Default Property Values

Swift:

  1> struct Point {  
  2.    var X: Int = 100 
  3. }
  4> var p : Point
  
p: Point = {
  X = 0
}

  5> var p = Point()
p: Point = {
  X = 100
}

C#: structはコンストラクタ用意する必要があるので、デフォルト値は意味ない

public struct Point {
   public int X = 100;
   public Point(int x ){
      X = x;
   }
}

Point p;
Console.WriteLine(p.X);

var p2  = new Point(200);
Console.WriteLine(p2.X);

0
200
public class Point {
   public int X = 100;
}

var p  = new Point();
Console.WriteLine(p.X);

100

Customizing Initialization

Initialization Parameters

Swift:

struct Point { 
   var X: Int
   init(x: Int){ X = x}
}

println( Point(x:90).X )
90
struct Point { 
   var X: Int
   init(X x: Int){ X = x}
}

println( Point(X:90).X )
90

C#: 外部名も使える

public struct Point {
   public int X = 100;
   public int Y = 100;
   public Point(int x, int y ){
      X = x; Y = y;
   }
}

var p = new Point(y:9, x:8);
_.Print("X={0} Y={1}", p.X, p.Y);

X=8 Y=9

Local and External Parameter Names

struct Point { 
   var X: Int
   init(X: Int){ self.X = X}
}

println( Point(X:90).X )
90

Swift: 通常、外部名必要

struct Point { 
   var X: Int
   init(X x: Int){ X = x}
}

println( Point(90).X )

./swift3.swift:8:16: error: missing argument label 'X:' in call
println( Point(90).X )
               ^
               X: 

Initializer Parameters Without External Names

Swift: アンダースコアで外部名不要

struct Point { 
   var X: Int
   init(_ x: Int){ X = x}
}

println( Point(90).X )

90

Optional Property Types

Swift: イニシャライザ終わる迄に初期化必須

struct Point { 
   var X: Int
   var Y: Int
   init(_ x: Int){ X = x}
}

./swift3.swift:6:25: error: variable 'self.Y' used before being initialized
   init(_ x: Int){ X = x}
                        ^
  • nil可能にすればよい
struct Point { 
   var X: Int
   var Y: Int?
   init(_ x: Int){ X = x}
}
 7> class Point {  
  8.    var X: Int 
  9.    var Y: Int 
 10.    init(_ x: Int){ } 
 11. }
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/21901/repl7.swift:5:20: error: property 'self.X' not initialized
   init(_ x: Int){ }

C#: structは同じく

public struct Point {
   public int X = 100;
   public int Y = 100;
   public Point(int x, int y ){}
}

(4,31): error CS0171: Field `Point.X' must be fully assigned before control leaves the constructor
(4,31): error CS0171: Field `Point.Y' must be fully assigned before control leaves the constructor

C#: class は問題ない(default(T)で初期化される)

public class Point {
   public int X ;
   public int Y ;
   public Point(){}
}

var p = new Point();
_.Print("X ={0}, Y={1}", p.X, p.Y );

Modifying Constant Properties During Initialization

Swift: initではletに設定できる

struct Position{
    let origin: Int
    init(o: Int){
        origin = o
    } 
}
var p =  Position(o:100)
println(p.origin)
  • デフォルト値で設定済でもinit()なら出来る
struct Position{
    let origin: Int = 100
    init(o: Int){
        origin = o
    } 
}

その後だめ

./swift3.swift:11:10: error: cannot assign to 'origin' in 'p'
p.origin = 200
~~~~~~~~ ^

C#: readonly はコンストラクタ内部で変更

public class Point {
   public readonly int Origin = 100;
   public int X ;
   public int Y ;
   public Point(){
        Origin = 200;
   }
}

var p = new Point();
_.Print("X ={0}, Y={1} Origin={2}", p.X, p.Y, p.Origin );

p.Origin = 300;

X =0, Y=0 Origin=200

(1,4): error CS0191: A readonly field `Point.Origin' cannot be assigned to (except in a constructor or a variable initializer)

Default Initializers

Swift: Classのデフォルトイニシャライザー

  1> class Size{ 
  2.     var width = 100 
  3.     var height = 100 
  4.     var depth: Int? 
  5. }
  6> var s = Size()
s: Size = {
  width = 100
  height = 100
  depth = nil
}
  • structだめじゃない?
  6> struct Size{
  7.     var width = 100 
  8.     var height = 100 
  9.     var depth: Int? 
 10. } 
 11. 
 11> var s = Size()
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/13139/repl5.swift:2:13: error: missing argument for parameter 'width' in call
var s = Size()
            ^
  • initializerが呼ばれなければよい。が、イニシャライズされない。
 11> var s : Size
s: Size = {
  width = 0
  height = 0
  depth = 0
}

C#: structはコンストラクタ必須。クラスは T() がデフォルトで指定しなくても呼ぶ事ができる。

Memberwise Initializers for Structure Types

 12> var s = Size(width:10, height:10, depth:10) 
s: Size = {
  width = 10
  height = 10
  depth = 10
}

Initializer Delegation for Value Types

Swift:

nitializers can call other initializers to perform part of an instance’s initialization.

This process, known as initializer delegation, avoids duplicating code across multiple initializers.

  2. struct Point {  
  3.    var X: Int 
  4.    var Y: Int? 
  5.    init(x: Int, y: Int) { X=x ; Y=y } 
  6.    init(pos: (Int, Int)) { self.init(x:pos.0, y:pos.1) } 
  7. } 
  8> var p = Point(pos: (10,10))
p: Point = {
  X = 10
  Y = 10
}
  • 引数タイプではなく引数名(外部名)でメソッドシグネチャが識別
  9> struct Point {  
 10.    var X: Int  
 11.    var Y: Int? 
 12.    init(x: Int, y: Int) { X=x ; Y=y } 
 13.    init(dx: Int, dy: Int) { X=2*dx ; Y=2*dy } 
 14.    init(pos: (Int, Int)) { self.init(x:pos.0, y:pos.1) } 
 15.    init(dpos: (Int, Int)) { self.init(dx:dpos.0, dy:dpos.1) } 
 16. }
 17> var p1 = Point(pos: (1,1))
p1: Point = {
  X = 1
  Y = 1
}
 18> var p2 = Point(dpos: (1,1))
p2: Point = {
  X = 2
  Y = 2
}
  • なので明示的に指定した外部名が異なればよい。以下もOK
    init(dx x: Int, dy y: Int) { X=2*x ; Y=2*y } 
  • これはいけるが
 30> struct PointEx{  
 31.     var X = 0 , Y = 0 
 32.     init(_ x: Int, y: Int){ X=x ; Y=y} 
 33.     init(_ pos: (Int, Int)){ self.init(pos.0, y:pos.1)} 
 34. } 
  • これはだめ
 36> struct PointEx{  
 37.     var X = 0 , Y = 0 
 38.     init(_ x: Int, _ y: Int){ X=x ; Y=y} 
 39.     init(_ pos: (Int, Int)){ self.init(pos.0, pos.1)} 
 40. }
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/15503/repl23.swift:5:35: error: could not find an overload for 'init' that accepts the supplied arguments
    init(_ pos: (Int, Int)){ self.init(pos.0, pos.1)}
                             ~~~~~^~~~~~~~~~~~~~~~~~

C#: this(arglist) で呼べる

public class Point {
   public int X ;
   public int Y ;
   public Point():this(9,9){
   }
   public Point(int x , int y)
   {
        X=x ; Y =y;
   }
}

var p = new Point();
_.Print("X ={0}, Y={1}", p.X, p.Y );

X =9, Y=9

Class Inheritance and Initialization

Swift:

All of a class’s stored properties—including any properties the class inherits from its superclass—must be assigned an initial value during initialization.

  1> class Point{ 
  2.    var x : Int 
  3.    var y : Int 
  4.    init() { x = 10 ; y = 10 } 
  5. } 
  
  6> class PointEx : Point{}                                                                                                              
  
  7> var p = PointEx()

p: PointEx = {
  __lldb_expr_1.Point = {
    x = 10
    y = 10
  }
}

Swift:

  • designated initializers
  • convenience initializers

C#:

public class Point {
   public int X ;
   public int Y ;
   public Point():this(9,9){
   }
   public Point(int x , int y)
   {
        X=x ; Y =y;
   }
}

public class PointEx: Point{}
var p = new PointEx();
_.Print("X ={0}, Y={1}", p.X, p.Y );

X =9, Y=9

Designated Initializers and Convenience Initializers

Swift:

クラス継承したときにイニシャライザのチェーンが発生するので、その時のチェーンの仕方の話

Designated Initializers:

  • primary initializers

Convenience initializers:

  • secondary initializers
  • supporting initializers

C#: Swiftみたいにめんどくさくないと思う

Syntax for Designated and Convenience Initializers

  3> class Point{ 
  4.    var x : Int 
  5.    var y : Int 
  6.    init() { x = 10 ; y = 10 } 
  7.    init(_ i: Int, _ j : Int) { x = i ; y = j }  
  8.    convenience init(pos: (Int, Int)) { self.init(pos.0, pos.1) } 
  9. }

 11> var p = Point()
p: Point = {
  x = 10
  y = 10
}
 12> var p = Point(5,5)
p: Point = {
  x = 5
  y = 5
}
 13> var p = Point(pos: (3,3))
p: Point = {
  x = 3
  y = 3
}
  • delegate initizalizer呼ばないといけない
  1> class Point{ 
  2.    var x : Int 
  3.    var y : Int 
  4.    init() { x = 10 ; y = 10 } 
  5.    init(_ i: Int, _ j : Int) { x = i ; y = j }  
  6.    convenience init(pos: (Int, Int))  
  7.    { x = pos.0 ; y = pos.1 } 
  8. }
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/16604/repl1.swift:7:16: error: convenience initializer for 'Point' must delegate (with 'self.init')
   convenience init(pos: (Int, Int)) 
               ^
  • delegate initializerを呼ぶのであれば convenience宣言しないといけない
  1> class Point{ 
  2.     var x = 0 , y = 0 
  3.     init(i: Int, j:Int) {  
  4.         println("init Point") 
  5.         x = i; y = j 
  6.     } 
  7.     init(pos: (Int, Int)){ 
  8.         println("init Point by pos") 
  9.         self.init(i: pos.0, j: pos.1 ) 
 10.     } 
 11. }
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/18195/repl1.swift:8:5: error: designated initializer for 'Point' cannot delegate (with 'self.init'); did you mean this to be a convenience initializer?
    init(pos: (Int, Int)){
    ^
    convenience 
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/18195/repl1.swift:10:14: note: delegation occurs here
        self.init(i: pos.0, j: pos.1 )

Initializer Chaining

Swiftルール

Rule1:

  • サブクラスのdesignated initializerは直上スーパークラスのdesignated initializerを呼ばないといけない

Rule 2:

  • convenience initializer はクラス内の別のイニシャライザーを呼ばないといけない

Rule 3:

  • convenience initializer最終的にはクラスのdesignated initializerのどれかを呼ばないといけない

簡単なチェーン

image

複雑なチェーン

image

Two-Phase Initialization

Swift : Two-Phase で初期化します

Phase 1:

  • あるクラスのイニシャライザが呼ばれる(designated か convenience)
  • メモリが割り当てられる。まだ初期化されない
  • designated initializeが処理が終わる迄にstored propertiesに値が割り当てられる。メモリが初期化される。
  • designated initializerスーパークラスのイニシャライザに処理を引き継ぐ。スパークラスでうへの処理を行う。
  • これを最後のスーパークラスまでさかのぼって繰り返す。
  • ここですべてのstored propertiesが初期化されてPhase1終了

Phase 2

  • おおもとのサブクラスから、各designated initializerがインスタンスへのカスタマイズ処理を行う。
  • ここで、selfにアクセス可能な状態になっていて、propertiesを変更したり、instance methodをコールできたりする。とか。
  • 最後にチェーンの中にあるconvenience initializersがインスタンスへのカスタマイズ処理が行えるようになる。

Initializer Inheritance and Overriding

Swift: 明示的に overrideしないといけない

  1> class Point{ 
  2.     var x = 0 , y = 0 
  3.     init() {  
  4.         println("init Point") 
  5.         x = 10; y = 10  
  6.     } 
  7. } 
  8.  
  9. class PointEx: Point{ 
 10.     init() {  
 11.         println("init PointEx") 
 12.         x = 20; y = 20 
 13.     } 
 14. }
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/17373/repl1.swift:11:5: error: overriding declaration requires an 'override' keyword
    init() { 
    ^
    override 
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/17373/repl1.swift:4:5: note: overridden declaration is here
    init() { 
    ^

Swift: 親のプロパティは親が面倒みる

  1> class Point{ 
  2.     var x = 0 , y = 0 
  3.     init() {  
  4.         println("init Point") 
  5.         x = 10; y = 10  
  6.     } 
  7. } 
  8.  
  9. class PointEx: Point{ 
 10.     override init() {                                                                                                                 
 11.         println("init PointEx") 
 12.         x = 20; y = 20 
 13.     } 
 14. }
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/17373/repl2.swift:13:9: error: use of property 'x' in base object before super.init initializes it
        x = 20; y = 20
        ^
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/17373/repl2.swift:13:17: error: use of property 'y' in base object before super.init initializes it
        x = 20; y = 20
                ^

Swift: super呼べば良い

  1> class Point{ 
  2.     var x = 0 , y = 0 
  3.     init() { println("*") } 
  4.     init(i: Int, j:Int) {  
  5.         println("init Point") 
  6.         x = i; y = j 
  7.     } 
  8.     init(pos: (Int, Int)){ 
  9.         println("init Point by pos") 
 10.         x = pos.0; y = pos.1 
 11.     } 
 12. } 

 14. class PointEx: Point{ 
 15.     override init() { 
 16.         println("*") 
 17.         super.init() 
 18.     } 
 19.     override init(i: Int, j:Int) { 
 20.         println("init PointEx") 
 21.         super.init(i:i, j:j) 
 22.     } 
 23. }

 25> var p = PointEx(i: 3, j:3 )
init PointEx
init Point
p: PointEx = {
  __lldb_expr_1.Point = {
    x = 3
    y = 3
  }
}

クラスメソッド違って、イニシャライザは自動的にサブクラスには引き継がれない(C#はデフォルトコンストラクタ以外引き継がない)

 26> var p2 = PointEx(pos: (3,3 ))
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/17948/repl10.swift:2:17: error: extra argument 'pos' in call
var p2 = PointEx(pos: (3,3 ))
                ^     ~~~~~~
                
 26> var p2 = Point(pos: (3,3))
init Point by pos
p2: Point = {
  x = 3
  y = 3
}

Automatic Initializer Inheritance

条件があえば自動的に引きがれるイニシャライザもある。(めんどくさい)

Rule 1:

  • サブクラスにdesignated initializersない。 この場合すべてのdesignated initializersを引き継ぐ

Rule 2:

  • Rule1をみたしているか、あるいはカスタム実装を用意していれば、 すべてのconvenience initializersを引き継ぐ

NOTE:

  • サブクラスはスーパクラスのdesignated initializer を、自身の中でconvenience initializerとして実装できる。(Rule2)

Required Initializers

Swift : required 修飾すると、サブクラスでは必須

  1> class Point { 
  2.     var x = 0 , y = 0 
  3.     required init(i: Int, j:Int) {  
  4.         x = i ; y = j 
  5.     } 
  6. } 
  7.  
  8. class PointEx: Point { 
  9.     init(pos: (Int, Int)){ 
 10.         super.init(i: pos.0, j: pos.1 ) 
 11.     } 
 12. }
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/18772/repl1.swift:13:1: error: 'required' initializer 'init(i:j:)' must be provided by subclass of 'Point'
}
^
/var/folders/3n/0lk686q1129clzkw38blpwdc0000gp/T/lldb/18772/repl1.swift:4:14: note: 'required' initializer is declared in superclass here
    required init(i: Int, j:Int) { 
             ^

しかし Rule1があるので、以下はOK

  1> class Point { 
  2.     var x = 0 , y = 0 
  3.     required init(i: Int, j:Int) {  
  4.         x = i ; y = j 
  5.     } 
  6. } 
  7. class PointEx: Point {}    
  8> var p = PointEx(i: 5, j: 5)
p: PointEx = {
  __lldb_expr_1.Point = {
    x = 5
    y = 5
  }
}

required隔世遺伝しない

  1> class Point { 
  2.     var x = 0 , y = 0 
  3.     required init(i: Int, j:Int) {  
  4.         x = i ; y = j 
  5.     } 
  6. } 
  
  7. class PointEx: Point {} 

  9. class PointExEx: PointEx{ 
 10.     init(pos: (Int, Int)){ 
 11.         super.init(i: pos.0, j: pos.1 ) 
 12.     }  
 13. }
    
 14> var p = PointExEx(pos: (9,9))
p: PointExEx = {
  __lldb_expr_1.PointEx = {
    __lldb_expr_1.Point = {
      x = 140735556008464
      y = 0
    }
  }
}
 15> p.x
$R0: Int = 9

Setting a Default Property Value with a Closure or Function

  • stored propetiesの設定のカスタマイズをしたかったら、クロージャかグローバル関数使えとのこと

  • クロージャ

 1> import Foundation
  2>        
  3. func getDayOfWeek(today: NSDate = NSDate.date()) -> Int { 
  4.     let cal = NSCalendar(calendarIdentifier: NSGregorianCalendar) 
  5.     let calcomp = cal.components( .WeekdayCalendarUnit, fromDate: today) 
  7.     let weekDay = calcomp.weekday 
  8.     return weekDay 
  9. }

 17> class ToDo { 
 18.   var day_of_week: String  = { 
 19.     return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][getDayOfWeek()-1]
 20.   }(); 
 21. } 

 22> var t = ToDo()
t: ToDo = {
  day_of_week = "Sat"
}
  • Type Method
 23> class ToDo { 
 24.   class func get_day_of_week(today :  NSDate = NSDate.date()) -> String {
 25.         var w = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"] 
 26.         var i = getDayOfWeek(today:today)-1 
 27.         return w[i] 
 28.   } 
 29.   var day_of_week = ToDo.get_day_of_week() 
 30. }  
 31. 
 31> var t = ToDo()
t: ToDo = {
  day_of_week = "Sat"
}

C#

ベースクラスのコンストラクタ

  • ベースクラスのコンストラクタは base(argslist)すればよい
  • ベースクラスのコンストラクタがよばれたあとで、自分のコンスクタのブロックが処理される
public class Point {
   public int X ;
   public int Y ;
   public Point():this(9,9){ } 

   public Point(int x , int y)
   {
        X=x ; Y =y;
   }
}

public class PointEx: Point
{
   public PointEx(int x, int y): base(x*2, y*2)
   {
       _.Print("X ={0}, Y={1}", this.X, this.Y );
        
      this.X += 3 ; this.Y += 3;    
   }
}

var p2 = new PointEx(5,5);
_.Print("X ={0}, Y={1}", p2.X, p2.Y );

X =10, Y=10
X =13, Y=13

デフォルトコンストラクタ以外は引き継がれない

public class Point {
   public int X ;
   public int Y ;
   public Point():this(9,9){ } 

   public Point(int x , int y)
   {
        X=x ; Y =y;
   }
}

public class PointEx: Point
{
}

var p2 = new PointEx(5,5);

(1,11): error CS1729: The type `PointEx' does not contain a constructor that takes `2' arguments

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?