Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] #14 - 스톱워치 구현 #15

Merged
merged 5 commits into from
Jan 7, 2022
Merged

[Feat] #14 - 스톱워치 구현 #15

merged 5 commits into from
Jan 7, 2022

Conversation

yangsubinn
Copy link
Member

🌴 PR 요약

🌱 작업한 브랜치

🌱 작업한 내용

  • 스톱워치 구현
  • 스톱워치에서 측정된 값 라벨에 반영

📌 참고 사항

여기저기 서치해서 찾은 타이머에서 ,, 간단하게 좀 추려봤슴니다
그리구 쫌 양심에 찔리기에 코드 뜯어보면서 이해하기 쉽게 주석 달아뒀슴다

근데 이게 맞을까..?

📸 스크린샷

기능 스크린샷
스톱워치 ezgif com-gif-maker (24)

📮 관련 이슈

@yangsubinn yangsubinn self-assigned this Jan 6, 2022
Copy link
Member

@L-j-h-c L-j-h-c left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

타이머 만들기 잘 봤어요 줌보선배! 코베도...조금씩은...익숙해지려고 노력중 ㅠ

Comment on lines +85 to +88
unowned let weakSelf = self

/// 0.035초마다 updateMainTimer 함수 호출하는 타이머
stopwatch.timer = Timer.scheduledTimer(timeInterval: 0.035, target: weakSelf, selector: #selector(updateMainTimer), userInfo: nil, repeats: true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

감쟈가...조심스레...질문 남깁니다 슨배...
여기서 self가 뷰컨이고, 미소유 참조로 바꿔주는 것 같은데
그 이유가 아래 타이머에서 0.035초마다 참조를 하기 때문에 메모리 효율을 높이기 위해서 사용하는건가요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@L-j-h-c 저도 기존에 있던 코드를 따라하면서 이해해보려한거라 확실하진 않지만,, 😓

넵 전 그렇게 이해했습니다..
근데 이제 또 weak를 사용한다면 nil이 될 수 있기 때문에 그 부분을 체크해줘야 하는 경우가 생길 수 있고,, self가 가리키는 뷰컨은 사라질 일은 없기 때문에? unowned로 지정한 것 같아요..!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@L-j-h-c 저도 기존에 있던 코드를 따라하면서 이해해보려한거라 확실하진 않지만,, 😓

넵 전 그렇게 이해했습니다.. 근데 이제 또 weak를 사용한다면 nil이 될 수 있기 때문에 그 부분을 체크해줘야 하는 경우가 생길 수 있고,, self가 가리키는 뷰컨은 사라질 일은 없기 때문에? unowned로 지정한 것 같아요..!

weak과 unowned 차이 알아가요...! 감삼당!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weak

weak는 옵셔널 타입입니다. 그래서 nil이 될 수 있으며 만약 참조하고 있는 인스턴스가 메모리에서 해제될 시, ARC가 nil로 참조값을 대체합니다. 따라서 참조하고 있는 객체가 생명주기가 짧은 경우(weak를 선언한 scope의 객체보다) 사용합니다. (수명이 더 긴 쪽에서 선언)
unowned

unowned는 weak와 달리 참조하고 있는 인스턴스가 메모리에서 해제될 시, nil이 되지 않습니다. 만약 참조하고 있는 객체가 매모리에서 해제된 후 접근할 시, crash가 날 수 있습니다. 따라서 참조하고 있는 객체의 생명주기가 현재 scope의 객체보다 생명주기가 더 길거나 같을 경우 사용합니다. (수명이 더 짧은쪽에서 선언)

라고 하네요! 혹시 놓친 부분 있으시면 얻어가세용!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 ARC 에서 카운트를 올리지 않기 위해서 미소유 참조를 사용하는 것 너무 좋네요! 그런데 타이머에서 뷰컨을 참조하다가 뷰컨을 끄게 되는 경우 그 찰나의 순간에 타이머는 해제된 뷰컨을 참조하게 될거 같아요(이론상) 그래서 You don’t (always) need [weak self] 이 글에서 보면 unowned 를 강제 언래핑과 같다고 말하더라구여 그래서 안전하게 사용하는것도 좋을 거 같아요!

Comment on lines +146 to +154
var minutes: String = "\((Int)(stopwatch.counter / 60))"
if (Int)(stopwatch.counter / 60) < 10 {
minutes = "0\((Int)(stopwatch.counter / 60))"
}

var seconds: String = String(format: "%.2f", (stopwatch.counter.truncatingRemainder(dividingBy: 60)))
if stopwatch.counter.truncatingRemainder(dividingBy: 60) < 10 {
seconds = "0" + seconds
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 60으로 나눠서 10보다 작으면 앞에 0 붙여주고...
  2. trunscatingRemainder가 float형의 나머지를 구하는데 사용된다는 점 알아갑니다...!
    https://minzombie.github.io/swift/truncatingRemainder/

stopwatch.timer = Timer.scheduledTimer(timeInterval: 0.035, target: weakSelf, selector: #selector(updateMainTimer), userInfo: nil, repeats: true)

/// RunLoop에서 timer 객체를 추가해서 관리
RunLoop.current.add(stopwatch.timer, forMode: .common)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 무슨 말인지 찾아봤는데, 스레드, async 등등 모르는게 너무 많이 나와서... 나중에 공부해보려구요 ㅠㅠ

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@L-j-h-c 저도 이번에 이 친구를 처음 봐서 좀 찾아봤는데,

일단 지금은 메인 스레드에서만 돌아가는거라 저 코드를 안 넣어줘도 정상적으로 작동하는데, 저 스톱워치를 비동기 처리하기 위해 global thread에서 사용하게 되면 제대로 동작하지 않는다고 합니다..
그래서 그럴 경우 RunLoop.current.add()로 RunLoop에서 메인이 아닌 다른 스레드에서 실행하는 객체를 추가해주는 작업이 필요한 것 같아요!

일단은.. 저도 정확하게 이해하진 못해서 머라 말하기가 애매하네여... 나중에 같이 공부해보십시다....
RunLoop 관련해서 본 자료 남겨봅니다..
https://babbab2.tistory.com/68
https://github.com/ClintJang/sample-ios-timer

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yangsubinn 음...솔직히 아리까리해서 저도 다음에 확실히 이해해볼게여....친절한 답변 감사함당~~!!! 앱잼기간 안에 공부해서....정리해보겠습니다 히히

@yangsubinn yangsubinn merged commit 52fec01 into develop Jan 7, 2022
@yangsubinn yangsubinn deleted the feature/#14 branch January 9, 2022 17:27

import Foundation

class Stopwatch: NSObject {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 좀 더 NSObject 를 상속받은 이유에 대해서 설명해주실 수 있을까용?
NSObjectobjective-C 의 객체들을 위한 기본 프레임워크로 오브젝티브씨에서 객체로 동작하고 런타임에서 시스템과 상화작용을 돕는다구 해요 그래서 독자적인 클래스를 만들때 NSObject 를 사용한다구 합니다!
Hoxy... 이 이유말구 여기서 NSObject 가 사용될 이유가 있을까용?

Comment on lines +85 to +88
unowned let weakSelf = self

/// 0.035초마다 updateMainTimer 함수 호출하는 타이머
stopwatch.timer = Timer.scheduledTimer(timeInterval: 0.035, target: weakSelf, selector: #selector(updateMainTimer), userInfo: nil, repeats: true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

weak

weak는 옵셔널 타입입니다. 그래서 nil이 될 수 있으며 만약 참조하고 있는 인스턴스가 메모리에서 해제될 시, ARC가 nil로 참조값을 대체합니다. 따라서 참조하고 있는 객체가 생명주기가 짧은 경우(weak를 선언한 scope의 객체보다) 사용합니다. (수명이 더 긴 쪽에서 선언)
unowned

unowned는 weak와 달리 참조하고 있는 인스턴스가 메모리에서 해제될 시, nil이 되지 않습니다. 만약 참조하고 있는 객체가 매모리에서 해제된 후 접근할 시, crash가 날 수 있습니다. 따라서 참조하고 있는 객체의 생명주기가 현재 scope의 객체보다 생명주기가 더 길거나 같을 경우 사용합니다. (수명이 더 짧은쪽에서 선언)

라고 하네요! 혹시 놓친 부분 있으시면 얻어가세용!

Comment on lines +85 to +88
unowned let weakSelf = self

/// 0.035초마다 updateMainTimer 함수 호출하는 타이머
stopwatch.timer = Timer.scheduledTimer(timeInterval: 0.035, target: weakSelf, selector: #selector(updateMainTimer), userInfo: nil, repeats: true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 ARC 에서 카운트를 올리지 않기 위해서 미소유 참조를 사용하는 것 너무 좋네요! 그런데 타이머에서 뷰컨을 참조하다가 뷰컨을 끄게 되는 경우 그 찰나의 순간에 타이머는 해제된 뷰컨을 참조하게 될거 같아요(이론상) 그래서 You don’t (always) need [weak self] 이 글에서 보면 unowned 를 강제 언래핑과 같다고 말하더라구여 그래서 안전하게 사용하는것도 좋을 거 같아요!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feat] 스톱워치 구현
3 participants