How can I stop coroutine from another script file?

I have read the answers already given for similar problems but unable to find a solution. I have a coroutine in one script file, which I want to stop from another script file based on certain condition. Please guide me what I’m doing wrong. I have little experience with Unity.
I’m getting this message when I play the game:
“NullReferenceException: Object reference not set to an instance of an object
GameController.Start () (at Assets/Scripts/GameController.cs:18)”.

First script with the start coroutine is this:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class GameController : MonoBehaviour {

	public Camera cam;
	public GameObject[] balls;
	private float maxWidth;

	// Use this for initialization
	void Start () {
		if (cam == null) {
			cam = Camera.main;
		}
		Vector3 upperCorner = new Vector3(Screen.width, Screen.height, 0.0f);
		Vector3 targetWidth = cam.ScreenToWorldPoint(upperCorner);
		float ballWidth = balls[0].GetComponent<Renderer> ().bounds.extents.x;
		maxWidth = targetWidth.x - ballWidth;
		StartCoroutine (Spawn ());

	}
	
	public IEnumerator Spawn () {
		yield return new WaitForSeconds (2.0f); 
		while (true) {
			GameObject ball = balls [Random.Range (0, balls.Length)];
			Vector3 spawnPosition = new Vector3 (Random.Range (-maxWidth, maxWidth), transform.position.y, 0.0f);
			Quaternion spawnRotation = Quaternion.identity;
			Instantiate (ball, spawnPosition, spawnRotation);
			yield return new WaitForSeconds (Random.Range (1.0f, 2.0f));
		}

	}

	public void GameEnd () {

		StopCoroutine (Spawn ());
	
	}
}

and the script from where I’m trying to stop it is this:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class DestroyOnContact : MonoBehaviour {

	public GameObject gameOverText;
	public GameObject restartButton;



	void OnTriggerEnter2D (Collider2D other) {
		if (other.gameObject.tag != "Zero")
		{
			StartCoroutine (GameOver ());
		}
			
		GameController gc = gameObject.AddComponent<GameController> ();
		gc.GameEnd ();
		Destroy (other.gameObject);
	}

	IEnumerator GameOver () {

		yield return new WaitForSeconds (1.0f);
		gameOverText.SetActive (true);
		restartButton.SetActive (true);
	}

}

This will never work:

StopCoroutine (Spawn ());

When you call “Spawn()” it returns a statemachine object which you initially pass to StartCoroutine. Here when you call Spawn again you create a new seperate object which doesn’t run as a coroutine. So StopCoroutine can’t stop anything.

You have to save your “Coroutine” instance when you create it and use that in StopCoroutine:

private Coroutine gameCoroutine = null;


void Start()
{
    // [ ... ]
    gameCoroutine = StartCoroutine (Spawn ());
}

public void GameEnd ()
{
    if (gameCoroutine != null)
        StopCoroutine (gameCoroutine);
}