1. yield return StartCoroutine(MyCoroutine());
2. yield return MyCoroutine();
위 두 개가 어떻게 다른지 모르겠음
근데 해보니까 좀 다르긴 함
예를 들어서 코루틴에서 다른 객체의 코루틴을 실행할 때
StopAllCoroutines()를 호출하면 1번은 종료되지만 2번은 종료되지 않음
private class MyClass
{
private IEnumerator MyCoroutine1
{
// Function()이 호출되면 OtherClass의 OtherCoroutine1()이 StartCoroutine()으로 호출한 코루틴 OtherCoroutine()은 종료되지 않음
yield return StartCoroutine(OtherClass.OtherCoroutine1());
}
private IEnumerator MyCoroutine2
{
// Function()이 호출되면 OtherClass의 OtherCoroutine2()가 그냥 호출한 OtherCoroutine()이 종료됨
yield return StartCoroutine(OtherClass.OtherCoroutine2());
}
private void Function()
{
StopAllCoroutines();
}
}
private class OtherClass
{
private IEnuemrator OtherCoroutine1
{
yield return StartCoroutine(OtherCoroutine());
}
private IEnumerator OtherCoroutine2
{
yield return OtherCoroutine();
}
private IEnumerator OtherCoroutine()
{
while (true) yield return null;
}
}
아래 링크는 그나마 비슷한 질문인데 도움되는 내용이 별로 없는 것 같아서 물어봄
해당 댓글은 삭제되었습니다.
반대로인 것 같은뎅 2번이 MyClass에서 호출된 StopAllCoroutines()에 의해서 종료돼
내가 유니티 켜서 확인해봤는데 우선 StopAllCoroutine() 동일한 스크립트 내에 있는 코루틴만 종료시킨다는 사실이 중요한데,
MyCoroutine1() 실행 시: MyClass에서 OtherClass의 인스턴스의 OtherCoroutine1()을 StartCoroutine으로 호출한다. OtherCoroutine1()에서 OtherCoroutine()을 StartCoroutine으로 호출한다. OtherCoroutine()에서 무한 루프를 실행 MyClass에서 StopAllCoroutines()를 호출해도 OtherCoroutine()은 중지되지 않는다. (StopCoroutine()은 현재 클래스 안에 있는 코루틴만 종료시키기 때문에 MyClass의 코루틴만 중지됨)
MyCoroutine2() 실행 시: MyClass에서 OtherClass의 인스턴스의 OtherCoroutine2()를 StartCoroutine으로 호출한다. OtherCoroutine2()에서 OtherCoroutine()을 일반 메서드 호출로 실행한다. OtherCoroutine()에서 무한 루프를 실행 MyClass에서 StopAllCoroutines()를 호출하면 OtherCoroutine()도 함께 중지된다. (OtherCoroutine()이 MyCoroutine2()의 일부로 실행되기 때문)
결론적으로 MyCoroutine2()가 OtherCoroutine2()를 실행하므로, MyClass에서 StopAllCoroutines()를 호출하면 MyCoroutine2()와 함께 OtherCoroutine()도 중지된다. (OtherCoroutine2()는 MyClass내에서 호출한 함수니까)
StartCoroutine()을 어디서 호출했는지에 따라서 해당 함수의 지역이 결정되는데, 직접 호출을 하면 해당 함수에 종속이 되는듯
좀 쉽게 알아보려면 해당 클래스가 붙어있는 GameObject가 Destroy()되면 해당 스크립트에서 실행중인 Coroutine들이 전부 종료되는데 MyCoroutine1()로 실행시켰다면 MyClass가 붙어있는 GameObject가 Destory되어도 코루틴이 실행되고 OtherClass가 붙은 GameObject를 Destoy해야 코루틴이 종료되는데
MyCoroutine2()로 실행중이라면 OtherClass()가 붙어있는 GameObject가 Destory되어도 코루틴이 실행되는데, MyClass가 붙어있는 GameObject가 Destory되면 코루틴이 종료되는걸로 보아 루프가 MyClass에 종속적이라는걸로 확인 가능한듯
와 이렇게 확인하는 방법이 있었네 이건 전혀 생각 못했다
이런 고민은 해본적 없었는데 재미있는 고민이네
도움 많이 됐어 진짜 고마워 나도 대충 그런가보다 해서 이런 차이가 있나보다 했는데 확신하지를 못하고 있었거든 하나만 더 물어볼게 yield return IEnumerator 이런 용법이 있어?
코루틴은 항상 StartCoroutine()으로 실행되어야 하는 걸로 알고 있었는데, 사실 yield return OtherCoroutine()이 가능한 이유를 잘 모르겠어. 구글링 아무리 해봐도 yield return IEnumerator에 대한 글은 저거 하나 뿐이야. 그럼 코루틴 내부에서 다른 코루틴을 실행할 때에만 특별히 StartCoroutine() 없이도 마치 함수처럼 호출할 수 있는 건가?
확인: 코루틴 내부에서 다른 코루틴을 호출하더라도 StartCoroutine()으로 호출해야 한다고 함 yield return OtherCoroutine()이 어떻게 가능한지 잘 모르겠어. 이것도 야매가 아니라 정석이라면 코루틴에서 호출한 코루틴이 어느 객체에 종속되느냐를 유용하게 활용할 수 있을 것 같아.
혹시 관련있는 주제일까 해서 추가로 써봐. 상위 클래스의 코루틴 protected virtual IEnumerator Coroutine()을 하위 클래스에서 상속하면 protected override IEnumerator Coroutine()이 되는데, 비주얼 스크립트에서는 자동으로 본문에 return base.Coroutine()을 작성해줘. 내가 처음 이걸 봤을 때는 당연히 StartCoroutine(base.Coroutine())이 되어야 할 거라고 생각했거든.
코루틴을 마치 IEnumerator를 반환하는 함수처럼 생각한다면 base.Coroutine()도 IEnumerator를 반환하니까 return base.Coroutine()은 전혀 문제가 될 것 같지 않아 보이는데, 코루틴이라고 생각하니까 조금 어렵네.
1. 코루틴은 유니티라면 StartCoroutine()으로 해야하는것이 맞음. 그래야 MonoBehaviour 객체의 업데이트 루프에 등록이 가능하므로 정확한 타이밍에 실행이 가능
2. yield return 다음에 오는 것은 IEnumerator 객체이기만 하면 가능함 StartCoroutine()도 IEnumerator 인터페이스를 구현한 객체이기 때문에, IEnumerator로 형변환하여 사용할 수 있음 마찬가지로 WaitForSeconds같은 애들도 IEnumerator 인터페이스를 구현한 객체이기 때문에 사용할 수 있는것임
Q : 그럼 코루틴 내부에서 다른 코루틴을 실행할 때에만 특별히 StartCoroutine() 없이도 마치 함수처럼 호출할 수 있는 건가? 호출 불가능함. 코루틴을 직접 호출한다면 해당 코루틴에는 IEnumerator 당연히 직접 인터페이스를 구현하지 않았을거니까 IEnumerator를 상속하는 객체가 아니게 됨 하지만 yield return을 사용하면 컴파일러가 자동으로 IEnumerator 인터페이스를 구현한 클래스를 생성해서 사용함 그래서 실행이되는것 StartCoroutine()은 Coroutine을 반환하는데, Coroutine도 IEnumerator 인터페이스를 상속하니까 실행이 가능함
코루틴은 IEnumerator를 반환하지만 해당 메서드를 직접 호출하면 IEnumerator 객체를 반환하지 않음
protected virtual IEnumerator Coroutine() 상속에 관련해서는 return base.Coroutine() 있다면 그냥 부모 코루틴을 실행하고, 종료시켜버리니까 이떄 반환된 IEnumerator 객체는 다른때 처럼 코루틴 제어하는 목적이 아닌 코루틴이 종료되었다는 용도로 사용되겠지 만약 부모 클래스의 Coroutine()을 실행하고 추가적으로 이어가고 싶다면 yield return을 사용하면 되겠지만 코루틴의 특성상 이렇게하면 현재 코루틴이 일시 중지되니까 동시에 실행하고 싶다면 StartCoroutine(base.Coroutine())을 하면 되는거고
비주얼 스튜디오에서는 그냥 일반적으로 가상함수를 재정의 할 때 부모 클래스의 구현을 호출하는 것이 일반적인 관습이기 때문에 그런식으로 작성해주는 것 뿐임
이렇게 함수를 재정의 할 때 반환형이 void가 아니라면 전부 return을 붙여주기 때문에 그런 과정에서 붙었다고 보면 될거같음
protected override IEnumerator Coroutine() return base.Coroutine(); protected override void Func() base.Func(); protected override int Func2() return base.Func2();
ㅇㅎ 이게 void가 아니면 전부 return을 해주는 거구나 주로 Awake(), Update(), OnEnable() 같은 함수을 오버라이드하니까 반환형이 있으면 자동으로 return을 작성해주는줄 몰랐어
나도 즉석에서 테스트하면서 하는중이라서 틀린 부분이 있을수도 있을것 같네
이거는 내가 코루틴에 대해서 알아본 정보들임 Coroutine()는 코루틴이기 때문에 IEnumerator 인터페이스를 구현해야 한다. 일반적으로 개발자가 코루틴을 작성할 때 직접 IEnumerator 인터페이스를 구현하지 않더라도, 'yield return'을 사용하면 컴파일러가 자동으로 해당 메서드에 대한 IEnumerator 인터페이스를 구현한 클래스를 생성한다. 따라서 Coroutine()는 실제로는 IEnumerator 인터페이스를 구현한 객체다.
Coroutine()를 직접 호출하는 것은 실행되지 않는다. 왜냐하면 코루틴은 일반 함수와 달리 시작, 일시 중지, 재개 등의 실행 상태를 관리하기 위해 Unity 엔진의 관리가 필요하기 때문. 따라서 코루틴을 실행하려면 반드시 Unity 엔진이 인식할 수 있는 방식인 'StartCoroutine()'을 사용해야 함
public class DerivedClass : BaseClass protected override IEnumerator Coroutine() return base.Coroutine(); 이런 경우에는 yield return도 없고 StartCoroutine()도 없는데 왜 실행이 가능? 이라는 질문이 있었는데 DerivedClass의 Coroutine()을 실행하려면 당연히 StartCoroutine()이나 yield return을 사용했을것임 그럼 Coroutine()에서 return된 base.Coroutine()을 위에서 말한 곳에 parameter으로 사용하게 되면서 실행이 되는것이라 생각하면 됨
아 그럼 결국에는 위의 예제에서도 OtherCoroutine2()는 OtherCoroutine()을 그대로 MyCoroutine2()에 리턴해주는 거고, 그럼 그 OtherCoroutine()을 마치 파라미터처럼 사용하면서 MyCoroutine()2는 OtherCoroutine()으로 StartCoroutine()을 실행하는 거구나
OtherCoroutine()이 private으로 선언되어 있더라도 마치 OtherCoroutine2()가 프로퍼티의 getter 같은 역할을 하는 거네
그럼 지금 읽고 나서 예상으로는 1. return OtherCoroutine()을 하면 OtherCoroutine2() 뒤에 무엇이 있어도 실행되지 않을 거고(마치 일반 함수에서 리턴하듯이), 2. yield return OtherCoroutine()을 하면 OtherCoroutine2()가 끝날 때까지 기다렸다가 뒤의 코드가 실행될 거고 3. StartCoroutine(OtherCoroutine())을 하면 OtherCoroutine2()을 실행하면서 동시에 이후의 코드도 같이 실행하겠네
바로 해보고 올게
1. 접근할 수 없는 코드가 있다면서 어둡게 나옴: 예상이 맞음
2. 예상이 맞음
3. StartCoroutine(OtherCoroutine())으로 하면 yield return 문이 없기 때문에 yield return null;을 추가로 써줘야 하긴 하지만 동시에 진행되는 건 맞음: 예상이 맞음
와 이건 진짜 도움 많이 됐다 어제부터 계속 고민하고 있었는데 해결됐어 진짜 고마워 코루틴 좀 어려워하고 있었는데 이번에 진짜 많이 정리 된 것 같아 복 많이 받고 만수무강해 완전고마워
나도 이 질문보고서 코루틴 자세히 알아보는 계기가 됐음 - dc App
일단 유니티의 "코루틴 시스템"하고 사전적 "코루틴"하고 "IEnumerator" 세가지를 떼어놓고 얘기를 해야 됨
사전적 코루틴부터 심플하게 얘기하면 "처리 중간에 다른 루틴에 갔다가, 중단 한 지점부터 다시 시작 할 수 있는 코드" 라고 말 할 수 있음
IEnumerator는 코루틴으로 동작하도록 C#의 문법적 지원(yield)을 받는 "순차적으로 여러 번 return할 수 있는 인터페이스" 라고 할 수 있는데
이 IEnumerator를 반환하는 메서드들은 yield return을 하면 IEnumerator라는 객체를 반환하고 IEnumerator.MoveNext()를 호출하면 다음 yield를 만날 때 까지 동작하고 IEnumerator.Current를 통해 yield return에서 반환한 값을 가져 올 수 있음
유니티 코루틴 시스템은 이 IEnumerator 메서드 객체를 기반으로 만든 시스템인데 YieldInstruction이라는 객체가 반환 될걸 기대하는 시스템임 YieldInstruction객체는 WaitForSeconds처럼 "언제 이 코루틴으로 다시 복귀할지"에 대한 정보를 유니티 코루틴 시스템에 알려주는 정보를 가지는 객체임
YieldInstruction이 그런 말이었구나 유니티 가서 찾아봐도 설명이 잘 안 되어 있어서 좀 어려웠거든 알려줘서 고마워