Проблема с использованием точки (.) в названии child Firebase


#1

Столкнулся с очень на мой непрофессиональный взгляд проблемой. В приложении использую Firebase. Есть экран Регистрации пользователя и экран Настроек персональных данных пользователя. И там и там есть поле Логин, на экране Регистрация ввожу при регистрации, на экране Настроек можно его сменить. И там и там стоит проверка на наличие уже такого же логина у другого пользователя. Вот например код из экрана Настроек, где можно сменить логин, аватар и пр.:

@IBAction func saveButton(_ sender: UIBarButtonItem) {
    guard let username = loginTextField.text, username != "" else {
        displayWarningLabel(withText: "Придумайте Логин")
        return
    }
    if username != currentUsername {
            let databaseRef = Database.database().reference()
            databaseRef.child("logins").observeSingleEvent(of: DataEventType.value, with: { (snapshot) in
                if snapshot.hasChild(username){
                    self.displayWarningLabel(withText: "Логин уже занят")
                    print("Login exists")
                    return
                } else {
                    self.changeUsersData()
                    self.profileImageUpdate()
                    self.dismiss(animated: true, completion: nil)
                    print("Login does not exist")
                }
            })
    }
    if aboutTextView.text != currentAbout {
        changeUsersData()
        self.profileImageUpdate()
        self.dismiss(animated: true, completion: nil)
    }
    self.profileImageUpdate()
}

Если при изменении логина при написании использовать простую точку, то при попытке сохранить изменение, приложение вылетает на строке snapshot.hasChild(username).
В консоле значится:

libc++abi.dylib: terminating with uncaught exception of type NSException
warning: could not execute support code to read Objective-C class data in the process. This may reduce the quality of type information available.

Если использовать в написании логина любой другой символ: запятую, тире, вопросительный знак и пр., все сохраняется нормально.
В чем может быть проблема, почему именно точка?


#2
  1. Возможно потому, что ваш логин - это всего лишь один из параметров в вашей БД. Посмотрите правила наименования полей(ключ) - скорее всего точка в ключе запрещена, тк видимо нарушает иерархию адреса, выполненного через точку в этой БД (хотя это неточно).
  2. В стандартном модуле аутентификации Auth есть все необходимые вам инструменты: смена имейла (если его используете как логин), либо смена displayName, который как раз, видимо, предназначен для кастомных логинов.

#3

Спасибо. По первому пункту, видимо, достаточно исключить возможность ввести точку в логине, сейчас попообовал в Твиттере использовать точку в логине, система не позволила. Так что вы скорее всего правы. Что касается второго, про проверку email и password в Firebase знаю и использую, а вот про displayName - пока нет.


#4

Обновление данных учёток в Auth


#5

Спасибо. Эту документацию видел, а вот именно на эту часть не обратил внимания)


#6

Возник еще один вопрос, чтобы не создавать отдельную тему. Проверку на наличие точки я сделал, все работает, но я решил пойти дальше. Вы не подскажите как оптимальнее выполнить проверку, чтобы при вводе использовались только латинские буквы заглавные, строчные, цифры и нижнее подчеркивание(_) и не использовались все остальные символы и языки.
То есть, если loginTextField.text содержит что либо кроме "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLKMNOPQRSTUVWXYZ0123456789", то всплывает предупреждение и код дальше не идет.
В сети много вариантов, в должной степени у меня не получается их правильно реализовать.


#7

Сам пока на практике не применял. Но вот вроде нормальное решение. Также на форуме нашлось похожее решение.


#8

Спасибо за ссылки. Если использовать первый вариант, то как сделать так, чтобы это условие применялось только к одному textField, в моем случае к loginTextField, а не ко всем на экране?


#9

Видимо в методе делегата указать конкретный филд (аутлет), который принимает метод, вместо общего типа

func textField(_ textField: YourTexField

Либо делать проверку входного параметра textField внутри метода через if или switch и там выдавать конкретику.


#10

func textField(_ textField: YourTexField не работает. А какое условие можно придумать для if?
Попробовал вот так:

let allowedCharacters = CharacterSet(charactersIn:"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz").inverted

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
    
    if loginRegisterTextField.text != "" {
    let components = string.components(separatedBy: allowedCharacters)
    let filtered = components.joined(separator: "")
    
    if string == filtered {
        print("Латиница")
        return true
    } else {
        print("Не Латиница")
        return false
    }
    }
    return true
}

Но это срабатывает после ввода второго символа в поле loginRegisterTextField, а первый можно ставить какой угодно


#11

Странно, а вы как делали?

У вас должен быть аутлет ТФ, например:

@IBOutlet weak var yourTF: UITextField!

И тут, вроде, нет разницы передавать один объект:

func textField(_ textField: yourTF,

либо ловить его внутри:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

    if textField == yourTF {
        ...
    }
}

#12

Аутлет, конечно, есть. Сработал второй вариант. Ну и финальный вопрос), как это правило применить к 2м textField, а всего их на экране 3?


#13

ну очевидно же - ловить входные объекты через switch:

switch textField {
    case yourTF1: ...
    case yourTF2: ...
}

либо

if textField  == yourTF1 {
...
} else if textField  == yourTF2 {
    ...
}

но это не камильфо ))


#14

Спасибо. Вы очень помогли!