UnityNullReferenceException(空引用異常)問題

      網友投稿 2241 2022-05-30

      什么是NullReferenceException(空引用異常)?

      來自官方的詮釋:https://docs.unity3d.com/Manual/NullReferenceException.html

      一個NullReferenceException當你試圖訪問沒有引用任何對象的引用變量時發生。如果引用變量沒有引用對象,那么它將被視為null。當變量為null發出NullReferenceException.

      C#和JavaScript中的引用變量在概念上與C和C+中的指針相似。引用類型默認為null若要指示它們沒有引用任何對象,請執行以下操作。因此,如果您嘗試訪問正在被引用的對象,但是沒有引用對象,您將得到一個NullReferenceException.

      當你得到一個NullReferenceException在代碼中,這意味著在使用變量之前忘記設置變量。錯誤消息將類似于:

      NullReferenceException: Object reference not set to an instance of an object

      at Example.Start () [0x0000b] in /Unity/projects/nre/Assets/Example.cs:8

      此錯誤消息表明NullReferenceException發生在腳本文件的第8行Example.cs。另外,消息說異常發生在Start()功能。這使得Null引用異常很容易找到和修復。在本例中,代碼是:

      using UnityEngine; using System.Collections; public class Example : MonoBehaviour { // Use this for initialization void Start () { GameObject go = GameObject.Find("cube"); Debug.Log(go.name); } }

      代碼只需查找一個名為“cube”的游戲對象。在本例中,沒有具有該名稱的游戲對象,因此Find()函數返回null。在下一行,我們使用go變量,并嘗試打印出它引用的游戲對象的名稱。因為我們訪問的是一個不存在的游戲對象,運行時給我們提供了一個NullReferenceException

      一種常見的處理方法:

      使用try/catch檢測,,,

      一個原因NullReferenceException對象中應該初始化的變量。是否被初始化過。

      ** 另一種處理方法NullReferenceException是使用TRY/CATCH塊。**

      例如,此代碼:

      using UnityEngine; using System; using System.Collections; public class Example : MonoBehaviour { // Use this for initialization void Start () { try { GameObject go = GameObject.Find("cube"); Debug.Log(go.name); } catch (NullReferenceException ex) { Debug.Log("myLight was not set in the inspector"); } } }

      NullReferenceException當腳本代碼試圖使用未設置(引用)和對象的變量時發生。

      出現的錯誤消息告訴您在代碼中問題發生的位置。

      NullReferenceException可以通過編寫檢查null在訪問對象或使用TRY/CATCH塊之前。

      來自Android模擬器的誤導:(綠色部分是catch到的異常)

      Unity Edior 的報錯:

      MissingReferenceException: The object of type ‘GameObject’ has been

      destroyed but you are still trying to access it. Your script should

      either check if it is null or you should not destroy the object.

      UnityEngine.GameObject.GetComponent[RectTransform] () (at

      C:/buildslave/unity/build/artifacts/generated/common/runtime/GameObjectBindings.gen.cs:38)

      解決方法:

      發現是在類似清理的方法里面做了,賦值的初始化導致。

      推薦查看:https://blog.csdn.net/Czhenya/article/details/84333583

      GetComponent()是訪問電流的常用函數。游戲對象組件。這里有一個代碼片段,顯示如何禁用對象的呈現器,因此它在游戲視圖中不再可見。

      var renderer=GetComponent(); renderer.enable=false;

      當然了GetComponent()會回來零如果當前對象沒有請求的組件。這是一個嚴重的風險,因為設計人員可以隨時在沒有任何警告的情況下輕松地刪除組件。

      Use [RequireComponent] :

      首先你應該用[索取成分]只要有可能就進行注釋。

      [RequireComponent(typeof(Renderer))] public class Player : MonoBehaviour { void Start() { var renderer = GetComponent(); renderer.enabled = false; } }

      請注意[RequireComponent]不能保證給定組件始終可用。它實際上所做的是在對象設置期間添加缺少的組件。沒有什么稀奇古怪的,但它降低了NullReferenceException一點。

      是的,你絕對應該做一個空檢查。但是,如果組件碰巧丟失了,您必須決定要做什么。一般來說,你有三個選擇。

      1.顯示錯誤并忽略。

      2.將事件報告為bug

      3.試著恢復。

      正如您所看到的,拋出異常是沒有選擇的。那是因為我們希望我們的游戲盡可能穩定。

      1。顯示錯誤并忽略

      這是處理這類bug最簡單的方法。如果您在Unity編輯器中遇到它們,那么您將有一個很好的機會在它發布之前修復它。然而,如果這個問題出現在你的播放器設備上,你的情況就不會那么舒服了,而這些設備通常是你無法直接訪問的。

      [RequireComponent(typeof(Renderer))] public class Player : MonoBehaviour { void Start() { var renderer = GetComponent(); if (renderer) { renderer.enabled = false; } else { Debug.LogError("Missing Renderer component", this); } } }

      請注意,在第7行,我寫的是if (renderer)而不是if (renderer != null)。那是因為UnityEngine。對象覆蓋了(bool)操作符,這是執行空檢查的一個很好的快捷方式。

      如果有機會,您可能希望將此事件報告為bug。自動bug報告可以幫助您修復生產中的bug,因此您應該認真考慮這種實現。當然,你必須請求玩家允許你發送bug報告,否則它可能違反了與谷歌Play或App Store的協議,因此你的應用程序可能會被禁止。

      我個人使用的腳本名為SRDebugger,來自資產存儲。它允許顯示一個覆蓋表單,允許將bug報告發送到我的電子郵件地址。

      [RequireComponent(typeof(Renderer))] public class Player : MonoBehaviour { void Start() { var renderer = GetComponent(); if (renderer) { renderer.enabled = false; } else { SRDebug.Instance.ShowBugReportSheet( null, true, "Missing Renderer Component"); } } }

      這是第三種選擇,也是唯一能夠讓你的游戲正常運行的選擇。我認為它永遠不應該被使用,因為有煙就有火。恢復只是掩蓋煙霧,而你應該開始尋找火災。

      [RequireComponent(typeof(Renderer))] public class Player : MonoBehaviour { void Start() { var renderer = GetComponent(); if (!renderer) { renderer = gameObject.AddComponent(); Debug.LogWarning("Creating missing component Renderer"); } renderer.enabled = false; } }

      Assert GetComponent()

      記住,你應該盡快尋找任何問題。如果您的腳本將來使用某個組件,請確保在開始時檢查該組件是否可用。

      [RequireComponent(typeof(Renderer))] public class Player : MonoBehaviour { private Renderer _renderer; void OnEnable() { _renderer = GetComponent(); Assert.IsNotNull(_renderer, "Missing Renderer Component"); } public void Hide() { _renderer.enabled = false; } }

      注意回調!

      如果你的游戲包含從外部代碼和/或從另一個線程調用的回調,你可能會發現自己處于一種情況,當NullReferenceException被拋出時。當回調函數在發出請求幾秒鐘后被調用時,它可以發生在Social API中。在那個時候,發出請求的對象可能已經不存在了。

      這不是真的,但我們可能會遇到我們之前討論過的偽空問題。讓我們考慮這樣一個場景:

      結果加載場景。

      ResultsScreen腳本正在為當前玩家的分數請求社交API。

      玩家點擊“主菜單”按鈕。

      結果場景被卸載。

      加載主菜單場景。

      正在ResultsScreen腳本中調用Social API回調。

      Unity 之 NullReferenceException(空引用異常)問題

      因此,如果結果場景被卸載,那么在執行第六步時,所有的對象都應該被銷毀。這是不正確的,因為對ResultsScreen對象的引用仍然有效,對象仍然存在,但是它通過偽造自己的null檢查將自己報告為null,正如我在前一篇文章中解釋的那樣。它可能是這樣的:

      public class ResultScreen : MonoBehaviour { public Text ScoreLabel; void Start() { Social.LoadScores("Leaderboard01", scores => { if (scores.Length > 0) ScoreLabel.text = scores[0].formattedValue; }); } }

      您能猜到您將在哪里接收到NullReferenceException嗎?在第10行,ScoreLabel是否被分配并不重要。此時您將無法訪問它。

      如何在這種情況下保護自己?答案很奇怪,但很簡單。你應該對這個做一個空檢查。

      public class ResultScreen : MonoBehaviour { public Text ScoreLabel; void Start() { Social.LoadScores("Leaderboard01", scores => { if (!this) Debug.LogWarning("Current object no longer usable. Discarding callback."); return; if (scores.Length > 0) ScoreLabel.text = scores[0].formattedValue; }); } }

      是的,這是正確的!當前對象不會為空,因為它根本不可能是空的,但由于Unity正在偽造空檢查,這是檢查當前對象是否仍然可以使用的最好方法!

      當然,您可以空檢查將要使用的所有對象,但是在更復雜的場景中,這可能太復雜了。檢查這個是否為空應該足夠了。

      保持冷靜和單身

      單例通常被認為是反模式的。由于簡單和易于實現,仍然廣泛使用單例。

      在Unity中,最常見的單例類型是:

      根據需要創建單例

      引擎創建的單例程序(源自MonoBehaviour)

      讓我們看看單例的第二種類型。

      class Singleton : MonoBehaviour { public static Singleton Instance { get; private set; } void Awake() { Instance = this; } }

      首先,您應該確保盡快分配了單例實例字段,因此我將在Awake()方法中分配它。但這還不夠。有一個嚴重的風險是Awake()不會被調用一次。這種風險是由場景中存在單例對象的假設引起的。

      知道了這一點,你必須在每個類中創建一個斷言,你打算使用這個單例:

      class MyScript : MonoBehaviour { void Start() { Assert.IsNotNull(Singleton.Instance, "Missing Singleton!"); } }

      注意,我在Awake()函數中分配了一個單例,但在Start()函數中測試它的null值,而不是OnEnable()函數。

      這是因為Awake()和OnEnable()函數會為每個已啟用的GameObject逐一調用。在官方文檔中沒有很好地解釋,所以我將試著澄清這一點。

      有腳本:ScriptA和ScriptB都具有Awake()、OnEnable()和Start()函數。調用順序可能是這樣的:

      ScriptA: Awake()

      ScriptA: OnEnable()

      ScriptB: Awake()

      ScriptB: OnEnable()

      ScriptA: Start()

      ScriptB: Start()

      建議嗎?

      對于如何通過保護代碼不受nullreferenceexception的影響而使項目健壯,您還有其他有趣的建議嗎?請在下面的評論欄中分享你的建議!我會很感激的!

      5G游戲 unity

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:IPython基礎使用_Round2
      下一篇:如何處理消費過程中的重復消息?
      相關文章
      亚洲第一精品电影网| 亚洲卡一卡2卡三卡4卡无卡三| 亚洲AV无码一区东京热| 国产亚洲精品看片在线观看 | 亚洲AV无码一区二区三区久久精品| 亚洲最大在线观看| 日韩亚洲Av人人夜夜澡人人爽 | 亚洲av伊人久久综合密臀性色 | 伊人亚洲综合青草青草久热| 亚洲精品无码99在线观看| 午夜亚洲国产精品福利| 亚洲精品国产日韩无码AV永久免费网| 亚洲av永久无码| 老子影院午夜伦不卡亚洲| 日韩亚洲人成在线综合| 伊在人亚洲香蕉精品区麻豆| 国产亚洲人成在线影院| 亚洲综合亚洲综合网成人| 国内精品久久久久久久亚洲| 亚洲中文字幕无码久久综合网| 国产亚洲精品成人AA片新蒲金 | 亚洲AV成人无码网站| 男人的天堂亚洲一区二区三区 | 亚洲国产模特在线播放| 亚洲一卡2卡3卡4卡国产网站| 亚洲AV色吊丝无码| 亚洲日韩精品无码专区加勒比 | 色婷婷亚洲一区二区三区| 亚洲欧洲一区二区三区| 国产亚洲AV手机在线观看 | 亚洲暴爽av人人爽日日碰| 亚洲国产成人久久综合区| 精品国产亚洲一区二区在线观看 | 学生妹亚洲一区二区| 亚洲大尺度无码无码专线一区 | 久久亚洲精品无码aⅴ大香| 亚洲一区二区免费视频| 亚洲精品一卡2卡3卡四卡乱码| 国产亚洲午夜精品| 亚洲色成人网站WWW永久| 亚洲精品免费视频|