#swift #swiftui
#swift #свифтуи
Вопрос:
у меня есть три переменных, так что, похоже, возникает компилятор, когда я пытаюсь проверить, прошло ли время или нет. У меня есть
let currentDate = Int(Date().timeIntervalSince1970)
let loginUpdateDate = sessionStore.userSession?.loginUpdateDate
let nextDateLoginUpdate = currentDate - loginUpdateDate
но когда я пытаюсь это сделать, я получаю
Компилятор не может проверить это выражение в разумные сроки; попробуйте разбить выражение на отдельные подвыражения
Это простая операция с Int, но кажется, что она перегружает компилятор. Я делаю это, чтобы использовать операторы if позже
if nextDateLoginUpdate < 300
полный код — это:
struct editProfileView: View {
@State var loadImage : Image? = nil
@State var source : UIImagePickerController.SourceType = .photoLibrary
@EnvironmentObject var sessionStore : SessionStore
@State var name: String = ""
@State var bio:String = ""
@Binding var showEditProfile:Bool
@State var showEditPassword = false
// var user = User?
@State var loadingView = false
//image picker
@State var showChoose = false
@State var image: Image? = nil
@State var showImagePicker = false
@State var imageData : Data? = nil
@State private var offsetValue: CGFloat = 0.0
var body: some View {
ZStack {
VStack {
//переменные для даты и проверки последующего обновления данных на странице
//let loginUpdateDate = sessionStore.userSession?.loginUpdateDate
//let nextDateLoginUpdate = currentDate - loginUpdateDate
Group {
Group {
VStack {
Group {
//аватарка
//если картинка не выбрана
if (self.image == nil) {
if (self.sessionStore.userSession?.profileImageUrl == nil) {
ZStack(alignment: .bottomLeading) {
Image("user-placeholder")
.resizable()
.scaledToFill()
.clipShape(Circle())
.frame(width: 100, height: 100)
Image(systemName: "goforward.plus").padding(5)
}.frame(width: 100, height: 100)
.onTapGesture {
//выключаем если прошло меньше времени
self.showImagePicker = true
}
} else {
if (self.loadImage == nil) {
ZStack(alignment: .bottomLeading) {
Image("user-placeholder")
.resizable()
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
.frame(width: 100, height: 100)
Image(systemName: "goforward.plus").padding(5)
}.frame(width: 100, height: 100)
.onTapGesture {
self.showChoose = true
//выключаем если прошло меньше времени
}
}
else {
ZStack(alignment: .bottomLeading) {
loadImage!
.resizable()
.scaledToFill()
.clipShape(Circle())
.frame(width: 100, height: 100)
Image(systemName: "goforward.plus").padding(5)
}.frame(width: 100, height: 100)
.onTapGesture {
self.showChoose = true
//выключаем если прошло меньше времени
}
}
}
VStack(alignment: .center) {
Text(name).font(.headline)
}
//если картинка выбрана
} else {
ZStack(alignment: .bottomLeading) {
image! //может использовать "!" так как делаем проверку и уверены, что это не nil
.resizable()
.scaledToFill()
.clipShape(Circle())
Image(systemName: "goforward.plus").padding(5)
}.frame(width: 100, height: 100)
.onTapGesture {
// self.showImagePicker = true
self.showChoose = true
}
}
HStack {
Text(LocalizedStringKey("Bio:")).fontWeight(.bold)
Spacer()
}
HStack {
TextField(LocalizedStringKey("Bio"), text:$bio).padding(.top)
}.padding(.bottom).padding(.horizontal).background(Color("textFieldBackground")).cornerRadius(10)
}
}
}.padding(.horizontal).padding(.top)
Button(action: {
let currentUser = Auth.auth().currentUser
if (currentUser != nil) {
self.loadingView = true
let id = currentUser!.uid
// добавить в коллекцию ниже параметры когда получитсвя везде обновлять инфо
// "username" : self.name, "keywords" : self.name.splitStringToArray()
Ref.FIRESTORE_COLLECTION_USERS.document(id).updateData(["bio" : self.bio]) { (err) in
//Конструкция: если err (ошибка) не nil, значит ест ьошибка и что-то пошло не так
// если nil, значит все хорошо
if let err = err {
//делаем что-то если ошибка
//например показываем надпись с сообщением об ошибке
print("Error updating document: (err)")
self.loadingView = false
} else {
self.sessionStore.userSession?.bio = self.bio
//то же самое только если все получилось
print("Document successfully updated")
if (self.imageData == nil) {
self.loadingView = false
self.showEditProfile = false
}
}
}
//save image
//Если новая картинка выбрана
if (self.imageData != nil amp;amp; self.sessionStore.userSession != nil) {
//Сначала загружаем в хранилище, а затем ссылку на это фото обновляем в базе данных у пользователя
let storageAvatarUserId = Ref.STORAGE_AVATAR_USERID(userId: Auth.auth().currentUser!.uid)
let metadata = StorageMetadata()
metadata.contentType = "image/jpg"
//для био было
//cлушатель для обновления био
self.sessionStore.userSession?.bio = self.bio
//для логина - апдейт
self.sessionStore.userSession?.username = self.name
NotificationCenter.default.post(name: NSNotification.Name("update_profile_bio"), object: nil)
StorageService.updateAvatar(userId: self.sessionStore.userSession!.uid, username: self.sessionStore.userSession!.username, email: self.sessionStore.userSession!.email, imageData: self.imageData!, metaData: metadata, storageAvatarRef: storageAvatarUserId, onSuccses: {url in
if url != nil {
self.sessionStore.userSession?.profileImageUrl = url!
NotificationCenter.default.post(name: NSNotification.Name("update_profile_image"), object: nil)
self.loadingView = false
self.showEditProfile = false
} else {
self.loadingView = false
}
})
}
}
}) {
HStack {
Spacer()
Text(LocalizedStringKey("Save changes")).foregroundColor(Color("ButtonFont")).fontWeight(.bold)
Spacer()
}.padding().background(Color("ButtonBackground"))
}.cornerRadius(5).shadow(radius: 10, x: 0, y: 10).padding()
}
Group {
HStack {
if nextDateLoginUpdate < 300 {
Text(LocalizedStringKey("Less than a week has passed since the last login change, or the account was just created. Please wait")).foregroundColor(Color(.systemGray3)).padding(.top)
}
Text(LocalizedStringKey("User name:")).fontWeight(.bold)
Spacer()
}.padding(.top, 50)
// проверка для изменения логина
if nextDateLoginUpdate < 300 {
HStack {
TextField(LocalizedStringKey("Current username"), text: $name).padding(.top)
.foregroundColor(Color(.systemGray2))
.disabled(nextDateLoginUpdate < 300)
}.padding(.bottom).padding(.horizontal)
.background(Color(.systemGray5))
.cornerRadius(10)
} else {
HStack {
TextField(LocalizedStringKey("Current username"), text: $name).padding(.top)
}.padding(.bottom).padding(.horizontal).background(Color("textFieldBackground")).cornerRadius(10)
}
Button(action: {
let currentUser = Auth.auth().currentUser
if (currentUser != nil) {
self.loadingView = true
let id = currentUser!.uid
// добавить в коллекцию ниже параметры когда получитсвя везде обновлять инфо
// "username" : self.name, "keywords" : self.name.splitStringToArray()
Ref.FIRESTORE_COLLECTION_USERS.document(id).updateData(["username" : self.name, "keywords" : self.name.splitStringToArray()]) { (err) in
//Конструкция: если err (ошибка) не nil, значит ест ьошибка и что-то пошло не так
// если nil, значит все хорошо
if let err = err {
//делаем что-то если ошибка
//например показываем надпись с сообщением об ошибке
print("Error updating document: (err)")
self.loadingView = false
} else {
self.sessionStore.userSession?.username = self.name
self.sessionStore.userSession?.loginUpdateDate = Int(NSDate().timeIntervalSince1970)
//обновление displayname
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = self.name
changeRequest?.commitChanges { (error) in
if error != nil {
print(error!.localizedDescription)
return
} else {
print("user has change his displayname to", Auth.auth().currentUser?.displayName)
}
}
//то же самое только если все получилось
print("Document successfully updated")
self.loadingView = false
self.showEditProfile = false
}
}
}
}) {
if nextDateLoginUpdate < 300 {
HStack {
Spacer()
Text(LocalizedStringKey("Change username")).foregroundColor(Color(.systemGray6)).fontWeight(.bold)
Spacer()
}.padding(.top).padding(.bottom).background(Color(.systemGray3))
} else {
HStack {
Spacer()
Text(LocalizedStringKey("Change username")).foregroundColor(Color("ButtonFont")).fontWeight(.bold)
Spacer()
}.padding(.top).padding(.bottom).background(Color("ButtonBackground"))
}
}.cornerRadius(5).shadow(radius: 10, x: 0, y: 10).padding(.top).disabled(nextDateLoginUpdate < 300)
//конец блока обновления логина
}.padding(.horizontal)
Spacer()
}.padding(.top)
if self.loadingView == true {
VStack {
lottieView(filename: "loading-profile")
}.background(Color("textFieldBackground").edgesIgnoringSafeArea(.vertical))
}
}.background(Color(UIColor.systemGray6).edgesIgnoringSafeArea(.vertical))
.keyboardSensible($offsetValue).animation(.spring())
.onTapGesture {
closeKeyboard()
}
.onAppear() {
let currentUser = Auth.auth().currentUser
if (currentUser != nil) {
if (self.loadImage == nil) {
getImageByName(name: currentUser?.uid) { (image) in
if image != nil {
self.loadImage = image
}
}
}
print(currentUser!.uid, "userid")
let id = currentUser!.uid
Api.User.loadUserById(id: id, onSuccess: {user in
if (user != nil) {
self.bio = user!.bio
self.name = user!.username
}
})
} else {
print("nil in editProfileView")
}
}
.sheet(isPresented: self.$showImagePicker, content: {
ImagePicker2(showImagePicker: self.$showImagePicker, pickedImage: self.$image, imageData: self.$imageData)
})
.actionSheet(isPresented: self.$showChoose, content: {
ActionSheet(title: Text(LocalizedStringKey("Take photo")), message: Text(LocalizedStringKey("Add photo from sourse")), buttons: [
.default(Text(LocalizedStringKey("Upload")), action: {
self.source = .photoLibrary
self.showImagePicker = true
// self.cameraViewModel.showImagePicker = true
}),
.default(Text(LocalizedStringKey("Take a photo")), action: {
self.source = .camera
self.showImagePicker = true
// self.cameraViewModel.showImagePicker = true
// self.showChoose = true
}),
.cancel(Text(LocalizedStringKey("Cancel")))
])
})
}
}
Комментарии:
1. Скорее всего, это связано с огромным представлением, попробуйте разделить его тело на более мелкие подвиды.
2. @Asperi может быть, создать функцию для этой операции? Может ли это помочь?
3. Аспери, скорее всего, прав. Это огромный взгляд. Чем больше вы отклоняетесь от него, тем меньше вы столкнетесь с этим. Да, перемещение этих 3 строк в отдельную функцию в отдельный файл должно исправить это … но … я предполагаю, что вы будете продолжать сталкиваться с этим, пытаясь делать все больше и больше.
Ответ №1:
Я думаю, что лучше изменить первую строку, как в приведенном ниже фрагменте кода:
let date = Date()
let timeInterval = date.timeIntervalSince1970
let currentDate = Int(timeInterval)
Протестируйте это, я надеюсь, это поможет, иначе вам придется сделать другой код меньшим фрагментом
Комментарии:
1. кроме того, компилятор не может проверить это выражение в разумные сроки; попробуйте разбить выражение на отдельные подвыражения…. пусть date = Date() пусть timeInterval = date.timeIntervalSince1970 пусть currentDate = Int(timeInterval) пусть loginUpdateDate = sessionStore.UserSession?. loginUpdateDate пусть nextDateLoginUpdate = currentDate — loginUpdateDate
2. пожалуйста, разместите здесь весь код для этой функции.
3. Выполнено. Добавлена полная структура. Также хочу сказать — иногда это вызывает сбой, если я вызываю let loginUpdateDate = sessionStore.UserSession! .loginUpdateDate И я не знаю, насколько безопасно его развернуть. Попробовали if statesments и gurad. Вот почему я пытаюсь ответить на другой вопрос, может быть, у вас есть какие-либо идеи, как его развернуть.
Ответ №2:
Попробуйте преобразовать loginUpdateDate в int
let currentDate = Int(Date().timeIntervalSince1970)
if let loginUpdateDate = sessionStore.userSession?.loginUpdateDate as? Int {
let nextDateLoginUpdate : Int = currentDate - loginUpdateDate }
Такого рода предупреждения компилятора появляются каждый раз, когда Swift не ясно, какой тип объявления «let» или «var» будет перед компиляцией.
Необязательная цепочка (если позволено … как? Int { … } ) не обязательно, но это может быть безопаснее. В качестве альтернативы;
let currentDate = Int(Date().timeIntervalSince1970)
let loginUpdateDate = Int(sessionStore.userSession?.loginUpdateDate)
let nextDateLoginUpdate = currentDate - loginUpdateDate
Редактировать 5 февраля 2021:
Вот еще одна идея: убедитесь, что currentDate и loginUpdate date являются двойными (я полагаю, что тип по умолчанию «timeInterval»), затем приведите к Int после операции, чтобы :
let currentDate = Double(Date().timeIntervalSince1970)
let loginUpdateDate = Double(sessionStore.userSession?.loginUpdateDate)
let nextDateLoginUpdate = Int(currentDate - loginUpdateDate)
Комментарии:
1. извините за дилетантский вопрос (я пытаюсь), где в коде следует добавить это решение? Если я пытаюсь вывести на передний план за пределами тела var: some View { (23 строка) — он не может найти nextDateLoginUpdate «в области видимости, если я пытаюсь пройти его без него, я снова получаю «Компилятор не может проверить это выражение в разумные сроки; попробуйте разбить выражениена отдельные подвыражения». кажется, я пытаюсь вставить его в неправильное место в коде..
2. Ваш вопрос в порядке, и я думаю, мне следовало уточнить. В первом примере, когда loginUpdateDate успешно преобразуется в Int в условном коде, «следующий DateLoginUpdate будет находиться в области действия оператора if else.