我遇到一个问题,在更新视图时ViewModel
会重新初始化。
我有两个视图SongListView
和PlayerView
,它们共享一个对象Player
。当玩家的游戏状态更改为(isPlaying == true)
时,viewModel
中的SongListView
会重置并变为空数组。因此,我视图上的列表变为空。
SongListView:
struct SongListView: View {
@ObservedObject var model: SongListViewModel = SongListViewModel() // This resets when player.isPlaying is set to true
@ObservedObject var player: Player
var body: some View {
List(model.songs, id: \.id) { song in
Button(action: {
self.player.play(link: song.link)
}) {
TitleRowView(title: song)
}
}
.onAppear {
self.model.get()
}
.navigationBarTitle(Text("Songs"), displayMode: .inline)
}
}
SongListViewModel:
class SongListViewModel: ObservableObject {
@Published var songs: [Song] = [Song(id: 2, name: "ish", link: "ishm")] // When I tap the row, the songs var is re-initialized
func get() {
guard let url = URL(string: "apiPath") else { return }
URLSession(configuration: URLSessionConfiguration.default).dataTask(with: url) {data, response, error
// Some more code
self.songs = data
}.resume()
}
}
PlayerView:
struct PlayerView: View {
@ObservedObject var player: Player
var body: some View {
HStack {
Button(action: {
if self.player.isPlaying {
self.player.pause()
} else {
self.player.play()
}
}) {
// This change causes the viewModel to reset to empty array
if self.player.isPlaying {
Image(systemName: "pause.fill")
.resizable()
} else {
Image(systemName: "play.fill")
.resizable()
}
}
}
}
}
玩家:
class Player : ObservableObject
{
@Published var isPlaying: Bool = false
private var player: AVPlayer?
// This method is called when the user taps on a row in List
func play(link: String) {
guard let url = URL(string: link) else { return }
let playerItem = AVPlayerItem(url: url)
player = AVPlayer(playerItem: playerItem)
player?.play()
isPlaying = true // If I comment this line, the songs list in viewModel does not changes
}
}
预先感谢!
更新:仍然无效
struct SongListView: View {
@ObservedObject var model: SongListViewModel
var body: some View {
// View
}
}
struct CategoryListView: View {
var categoryData : [Category]
@ObservedObject var player: Player
var body: some View {
List(categoryData, id: \.id) { category in
if category.id == 3 {
NavigationLink(destination: SongListView(model: SongListViewModel(), player: self.player)) {
TitleRowView(title: category)
}
}
}
}
}
答案 0 :(得分:3)
使用 Traceback (most recent call last):
File "<ipython-input-48-dcb4b19c1bd3>", line 25, in <module>
engine = sqlalchemy.create_engine(url)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\__init__.py", line 479, in create_engine
return strategy.create(*args, **kwargs)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\strategies.py", line 61, in create
entrypoint = u._get_entrypoint()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\url.py", line 172, in _get_entrypoint
cls = registry.load(name)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\util\langhelpers.py", line 240, in load
"Can't load plugin: %s:%s" % (self.group, name)
NoSuchModuleError: Can't load plugin: sqlalchemy.dialects:driver
而不是 Traceback (most recent call last):
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 2276, in _wrap_pool_connect
return fn()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 363, in connect
return _ConnectionFairy._checkout(self)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 773, in _checkout
fairy = _ConnectionRecord.checkout(pool)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 492, in checkout
rec = pool._do_get()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\impl.py", line 139, in _do_get
self._dec_overflow()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\util\langhelpers.py", line 68, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\util\compat.py", line 153, in reraise
raise value
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\impl.py", line 136, in _do_get
return self._create_connection()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 308, in _create_connection
return _ConnectionRecord(self)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 437, in __init__
self.__connect(first_connect_check=True)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 652, in __connect
connection = pool._invoke_creator(self)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\strategies.py", line 114, in connect
return dialect.connect(*cargs, **cparams)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\default.py", line 489, in connect
return self.dbapi.connect(*cargs, **cparams)
File "C:\Anaconda3\lib\site-packages\psycopg2\__init__.py", line 126, in connect
dsn = _ext.make_dsn(dsn, **kwargs)
File "C:\Anaconda3\lib\site-packages\psycopg2\extensions.py", line 175, in make_dsn
parse_dsn(dsn)
ProgrammingError: invalid dsn: invalid connection option "encoding"
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "<ipython-input-53-3b57714b0ad8>", line 28, in <module>
data_frame = pd.read_sql('select date_signed from edw.fpds.fpds_atom limit 5;', engine)
File "C:\Anaconda3\lib\site-packages\pandas\io\sql.py", line 438, in read_sql
chunksize=chunksize,
File "C:\Anaconda3\lib\site-packages\pandas\io\sql.py", line 1218, in read_query
result = self.execute(*args)
File "C:\Anaconda3\lib\site-packages\pandas\io\sql.py", line 1087, in execute
return self.connectable.execute(*args, **kwargs)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 2181, in execute
connection = self._contextual_connect(close_with_result=True)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 2242, in _contextual_connect
self._wrap_pool_connect(self.pool.connect, None),
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 2280, in _wrap_pool_connect
e, dialect, self
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 1547, in _handle_dbapi_exception_noconnection
util.raise_from_cause(sqlalchemy_exception, exc_info)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\util\compat.py", line 398, in raise_from_cause
reraise(type(exception), exception, tb=exc_tb, cause=cause)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\util\compat.py", line 152, in reraise
raise value.with_traceback(tb)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\base.py", line 2276, in _wrap_pool_connect
return fn()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 363, in connect
return _ConnectionFairy._checkout(self)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 773, in _checkout
fairy = _ConnectionRecord.checkout(pool)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 492, in checkout
rec = pool._do_get()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\impl.py", line 139, in _do_get
self._dec_overflow()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\util\langhelpers.py", line 68, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\util\compat.py", line 153, in reraise
raise value
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\impl.py", line 136, in _do_get
return self._create_connection()
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 308, in _create_connection
return _ConnectionRecord(self)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 437, in __init__
self.__connect(first_connect_check=True)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\pool\base.py", line 652, in __connect
connection = pool._invoke_creator(self)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\strategies.py", line 114, in connect
return dialect.connect(*cargs, **cparams)
File "C:\Anaconda3\lib\site-packages\sqlalchemy\engine\default.py", line 489, in connect
return self.dbapi.connect(*cargs, **cparams)
File "C:\Anaconda3\lib\site-packages\psycopg2\__init__.py", line 126, in connect
dsn = _ext.make_dsn(dsn, **kwargs)
File "C:\Anaconda3\lib\site-packages\psycopg2\extensions.py", line 175, in make_dsn
parse_dsn(dsn)
ProgrammingError: (psycopg2.ProgrammingError) invalid dsn: invalid connection option "encoding"
(Background on this error at: http://sqlalche.me/e/f405)
对我有用。
只要需要视图,标记为 @StateObject
的属性将保留其最初分配的 ObservedObject 实例,即使该结构被 SwiftUI 重新创建。
这允许您维护 ObservedObject 数据的状态。
答案 1 :(得分:2)
SwiftUI视图是结构,因此是不可变的。当您更新状态并导致视图重绘时,它实际上会创建视图的新实例。
您的SongListView
中有
@ObservedObject var model: SongListViewModel = SongListViewModel()
这意味着每次重新绘制SongListView
时(包括更改player.isPlaying
的任何时间),您都在使用{{1}的新实例初始化model
}。
您应该删除默认值,并通过参数将模型提供给SongListViewModel
的初始化程序-
SongListView
答案 2 :(得分:0)
因此,最终我能够通过删除dirname(base_url());
上的dirname(dirname(base_url()));
属性包装程序来解决此问题。我不确定为什么会这样。似乎一个视图中有多个@ObservedObject
会导致此问题。现在我的代码如下:
player: Player
答案 3 :(得分:0)
改用@StateObject! ObservedObject 似乎每次都在重新创建整个对象。