どうもサルです。
私サルめは、構造体のことがわかったようでわからないまま、Xcode をシバいてStoryboardをいじいじしたりDelegate で通知をとばしたりViewControllerをいじいじしたりUserDefaultにデータをいれたりしていました。
流石にこのままではまずいと、頭のヘルメットが黄色に光り輝き始めたため、そろそろきちんと整理しようかと思い立った所存です。
softmoco.com
こちらのサイトを参考にしました
>>>Swift の struct(構造体)では、値を保持するためのプロパティや関連する機能のメソッドなどをまとめて定義しておいて、必要な時にその struct のインスタンス を生成して使うことができます。
使い方としてはクラスと同じと言うことですね
書き方の例 >>>>>>>>>>>>>>
struct Fueltank {
var alert : String = "A"
var fuel : Int
init (alert : String , fuel : Int ){
self .alert = alert
self .fuel = fuel
}
func indication (){
print (" \(alert ) is \(fuel )L" )
}
}
var ind = Fueltank (alert : "Fuel Remaining Amount" , fuel : 30 )
ind.indication ()
⇨結果 Fuel Remaining Amount is 30
クラスとの差異としては、①継承ができない ②参照渡しでなく値渡し ③デイニシャライザが使えない の3点。
①継承ができない については、新しくクラス、構造体を作成する際、その参照元 として(スーパークラス のように)継承をおこなうことができない。クラスの継承については以前の記事で説明済み
②参照渡しでなく値渡しとなる とは、下記例で見比べるとわかりやすい。
構造体で実行した場合(値渡し)>>>>>>>>>>>>>>
struct Fueltank {
var alert : String = "A"
var fuel : Int
init (alert : String , fuel : Int ){
self .alert = alert
self .fuel = fuel
}
func indication(){
print (" \(alert ) is \(fuel )L" )
}
}
var ind = Fueltank(alert: "Fuel Remaining Amount" , fuel: 30 )
var ind2 = ind
ind2 .fuel = 15
ind .indication()
ind2 .indication()
⇨結果 Fuel Remaining Amount is 30L
Fuel Remaining Amount is 15L
クラスで実行した場合(参照渡し)>>>>>>>>>>>>>>
class Fueltank {
var alert : String = "A"
var fuel : Int
init (alert : String , fuel : Int ){
self .alert = alert
self .fuel = fuel
}
func indication(){
print (" \(alert ) is \(fuel )L" )
}
}
var ind = Fueltank(alert: "Fuel Remaining Amount" , fuel: 30 )
var ind2 = ind
ind2 .fuel = 15
ind .indication()
ind2 .indication()
⇨結果 Fuel Remaining Amount is 15L
Fuel Remaining Amount is 15L
値渡しの場合は、indと代入後にfuelプロパティを書き換えたind2の値が異なるが、
参照渡しの場合、両方とも同じ値となる。
これは、値渡しが通常の演算通り、代入時の値(30)を渡しているのに対し、
参照渡しは、値(30)のプロパティはここにありますよ、という情報を渡している。
値渡しされた変数(ind2)を書き換えても、代入元(ind)の値はかわらないが、
参照渡しされた変数(ind2)を書き換えると、参照元 となるインスタンス のプロパティそのものを書き換えてしまい、代入元(ind)も同じプロパティを参照しているので、両者とも値が変わってしまう。
例えるなら、Webページ上にある画像に対して、A君がB君にコピーして渡すのが値渡し
B君が画像にどんなコラージュをあててもA君の画像はもとのまま
A君の画像
B君の画像
Webページ上にある画像に対して、A君がB君にページリンクを渡すのが参照渡し
B君がリンク元 の画像にコラージュをあてると、同じリンクから参照しているA君の画像もコラ画像 になってしまう。
A君の画像
B君の画像
要は値を渡すか参照元 を渡すかって言う、まんまの意味なんですけどね。
ちなみに値渡しのところで、意図的に参照渡しを行いたい場合は、引数の前に&をつかえば実行可能。詳しくは下記ページをご参照ください。
qiita.com
③デイニシャライザが使えないとは?
そもそもイニシャライザとは?
qiita.com
人のQiita記事で学び、自分のはてブ でアウトプットするサル
イニシャラザの中身は、クラス、構造体がインスタンス 化される際の、すべてのプロパティ、メソッドに対する初期値 ※基本的にすべて初期値が存在しなければならない。
UIKit Frameworkに最初から入っているスーパークラス などではなく、自分でクラス、構造体を作成する場合、すべてのプロパティ、メソッドに初期値を設定する必要がある。
なぜ初期値が存在しないといけないかと言うと、クラス、構造体のプロパティ、メソッドに初期値がなければ、インスタンス 化した際の初期値がない⇨nil として処理され、型の不一致、および解放前メモリへの不正アクセス 等でエラーが発生するため。(nil はオプショナル型、Any型以外では許容されていないよ!なのでこれらに限り初期値はなくてもOK)
値渡し、参照渡しの説明に使ったコードだと、こちらがイニシャライザ部分
ここでFueltank内の各プロパティの初期値を設定している。
※selfと記載することで、このクラス/構造体自身のメソッド、プロパティに代入する、という意味となる
init (alert : String , fuel : Int ){
self .alert = alert
self .fuel = fuel
}
その後、インスタンス 化したFueltankクラスの引数として、alertとfuelに引数を渡しているが、これはイニシャライザで定義した初期値を上書きしている、という事。
var ind = Fueltank(alert: "Fuel Remaining Amount" , fuel: 30 )
このイニシャライザ、クラスの場合は毎回必ず記述しないといけないが、構造体の場合はイニシャライザを定義しない場合、暗黙的に自動で全てのメソッド、プロパティに初期値が付与される。これを全項目イニシャライザとよぶ。
●車の構造体 イニシャライザなしでもインスタンス 化可能
struct Car {
let model: String
let type: String
let price: Double
let serial: Int
}
実際には、下記のイニシャライザが自動で作成され、かつ省略されている。
init(model: String, type: String, price: Double, serial: Int){
self.model = model
self.type = type
self.price = price
self.serial = serial
}
基本的にイニシャライザは、インスタンス 生成された際に一番最初に読み込まれる情報だが、逆にインスタンス が破棄される際(ある意味一番最後)に読み込まれるデイニシャライザ という構文もある。これは基本的に暗黙的に処理される内容だが、自分で内容を書くことも可能。
struct Car {
let model: String
let type: String
let price: Double
let serial: Int
init(model: String, type: String, price: Double, serial: Int){ //instance生成時呼出
self.model = model
self.type = type
self.price = price
self.serial = serial
}
deinit{ //instance終了時呼出
print("Car instance is terminated")
}
}
デイニシャライザはクラスのみ実行可能で、構造体では実行不可能。この違いがある
以上3点の差異について説明できました。書き方、使い方はクラスみたいなもんで、クラスは何らかの機能を有していて、インスタンス 生成してクラス自体がもつ目的を遂行するのに対し、構造体は単なるデータ、処理をまとめて保持する倉庫みたいな認識でいいのかな?
また一つ賢くなったサルでした
VIDEO youtu.be
山田亮 一Forever