LoginSignup
1
0

More than 5 years have passed since last update.

【swift】複数の同名宣言とローカル変数(定数)で作られたメソッドの使用に関する疑問(初心者)

Last updated at Posted at 2018-03-02

swiftの入門書を写経時に少し混乱したので、自分用にメモ
間違ってるもしくは情報不足(確実にあると思う。)があったら都度修正予定。

つまづきかけた疑問点と簡易的回答
・変数・定数がそれぞれ複数の場所で宣言されている。
 →スコープによるもの
・他の関数内で作られたインスタンスにおけるメソッドを外部の関数内の別インスタンスから扱えてしまっている。
 → 参照渡しによるもの  →  UserDefautlsによるもの

経緯
・viewDidLoad()内で定数インスタンスが宣言して作られている。
・そのインスタンスによって初期値のキーが登録されている。
・他関数内(viewDidLoad外)で同名の定数のインスタンスが作られている。
・その同名インスタンスではviewDidLoad()内で登録されたが、関数内で登録されていないキーを使用している。

ここで先の2つの疑問
1.定数は変更できないのにもかかわらず、複数宣言できているのはなぜか。
2.スコープの関係で複数の定数インスタンスが存在できるとして、どうして別のローカルスコープ(viewDidLoad関数)で設定されたキーを扱えるのか。

回答(調べた感じあってるとは思う。 → 間違っていました。)
1.関数・メソッド(スコープ)内で作られた変数や定数はローカル変数・定数として扱われ、スコープを抜けた時点で消えるため、そのスコープ外で同名の変数・定数が存在・宣言されていても問題はない。
2.ローカルスコープ内で作られてもクラスにおけるインスタンスは参照渡しであるため、インスタンスを通じて新たに設計されたものは参照元のデータにも影響を与えるため、スコープを抜け出てインスタンスが消えたあともスコープ内で設定された点は参照元に残る。
その参照元に新たに作られたインスタンスは参照元に残された部分も引き継ぐため扱うことができる。

ではなくて、
  viewDidLoad()内でUserDefaultsによってインスタンスが生成されているため。これによりローカルスコープを抜けてもなお、データが保持される。

次の疑問点
それでは、前の仮設してた回答はどうだったのか。
もしもUserDefaultsを使用しないで通常の参照渡しによるインスタンス生成を行った場合では同じ結果にはならない?
インスタンスでの変更は参照元のデータに影響を与えることで、スコープを抜け出ても新たに同じデータを参照元にした別ローカルスコープ内のインスタンスはその影響を受けるれるとしたら同じような挙動になりそうだが・・・・
こちらに関しては調べてわかったら追記します。

以下ソース(写経時にあげたのでまだ途中しか書いてない。)
問題にしているのは settings の部分

class ViewController: UIViewController {

//set timer variable
var timer : Timer?

//set count
var count = 0

//set the key 
let settingKey = "timer_value"

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    //create userdefaults instance
    let settings = UserDefaults.standard

    // initial date in UserDefaults
    settings.register(defaults: [settingKey:10])
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

@IBOutlet weak var countDownLabel: UILabel!

@IBAction func settingButtonAction(_ sender: Any) {
}

@IBAction func startButtonAction(_ sender: Any) {

    //unwrap timer & insert into nowtimer
    if let nowTimer = timer {

        //if started nostart
        if nowTimer.isValid == true {

            //no actiuon
            return
        }
    }

    //set timer
    timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector( self.timerInterrupt(_:) ), userInfo: nil, repeats: true )

}


@IBAction func stopButtonAction(_ sender: Any) {

    //unwrap timer and into nowtimer
    if let nowTimer = timer {

        if nowTimer.isValid == true {

            nowTimer.invalidate()
        }
    }
}

//update the UI ( return: remainCount:残り時間)
func displayUpdate() -> int {

    //create userdefault instance
    let settings = UserDefaults.standard

    //give the sec totimerValue
    let timerValue = settings.integer(forKey: settingKey)

    //create remain time
    let remainCount = timerValue - count

    //display remainCount to UI
    countDownLabel.text = "残り\(remainCount)秒"

    //retun
    return remainCount
}

// deal the past time
@objc func timerInterrupt(_ timer: Timer) {

    //count ++
    count += 1

    //stop timer if remaincounter = 0
    if displayUpdate() <= 0 {

        count = 0

        //stop timer
        timer.invalidate()
    }
}

}

1
0
2

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
0