Ваша текущая структура данных отлично подходит для поиска участников определенного чата. Это не очень хорошая структура для поиска обратного: чаты, в которых участвует пользователь.
Несколько проблем здесь:
Чат может иметь несколько участников, поэтому вы смоделировали это как массив. Но на самом деле это не идеальная структура данных. Вероятно, каждый участник может быть только в чате один раз. Но, используя массив, я мог бы:
participants: ["puf", "puf"]
Это явно не то, что вы имеете в виду, но структура данных позволяет это. Вы можете попытаться обеспечить это в коде и правилах безопасности, но было бы проще, если бы вы начали с структуры данных, которая неявно соответствует вашей модели.
Мое эмпирическое правило: если вы обнаружите, что пишете array.contains()
, вы должны использовать набор.
Набор представляет собой структуру, в которой каждый ребенок может присутствовать не более одного раза, поэтому он естественным образом защищает от дубликатов. В Firebase вы моделируете набор как:
participants: {
"puf": true
}
Здесь true
здесь действительно просто фиктивное значение: важно то, что мы переместили имя на ключ. Теперь, если я попытаюсь снова присоединиться к чату, это будет noop:
participants: {
"puf": true
}
И когда вы присоединитесь:
participants: {
"john": true,
"puf": true
}
Это самый прямой представление вашего требования: коллекция, которая может содержать только каждого участника один раз.
. С указанной структурой вы могли запросить для чатов, в которых вы находитесь:
ref.child("chats").orderByChild("participants/john").equalTo(true)
Проблема заключается в том, что для этого требуется, чтобы вы определяли индекс для `members / john ':
{
"rules": {
"chats": {
"$chatid": {
"participants": {
".indexOn": ["john", "puf"]
}
}
}
}
}
Это будет работать и но теперь каждый раз, когда кто-то новый присоединяется к чат-приложению, вам нужно добавить еще один индекс. Это явно не масштабируемая модель. Нам нужно будет изменить нашу структуру данных, чтобы разрешить требуемый запрос.
Второе правило: моделируйте ваши данные, чтобы отразить то, что вы показываете в своем приложении.
Поскольку вы ищете показать список чатов для пользователя, сохранить чаты для каждого пользователя:
userChatrooms: {
john: {
chatRoom1: true,
chatRoom2: true
},
puf: {
chatRoom1: true,
chatRoom3: true
}
}
Теперь вы можете si просто определите свой список чатов с помощью:
ref.child("userChatrooms").child("john")
И затем перейдите по клавишам, чтобы получить каждую комнату.
Вам понравится иметь два соответствующих списка в вашем приложении:
Кроме того, в базе данных есть оба списка.
chatroomUsers
chatroom1
user1: true
user2: true
chatroom2
user1: true
user3: true
userChatrooms
user1:
chatroom1: true
chatroom2: true
user2:
chatroom1: true
user2:
chatroom2: true
Я вытащил оба списка на верхний уровень дерева, так как Firebase рекомендует против вложенных данных.
Наличие обоих списков совершенно нормально в решениях NoSQL. В приведенном выше примере мы будем ссылаться на userChatrooms
как инвертированный индекс chatroomsUsers
.
Проблема заключается в вызове метода customStyle
перед заданным текстом на метке. поэтому изменение - это вызов метода customStyle
.
@IBDesignable class JWLabel: UILabel {
@IBInspectable open var style: Int = 0
func customStyle(style: Int){
var font = UIFont(name: "HelveticaNeue-Bold", size: 12)
var color = UIColor(hexString: "#8E8E8E")
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 3
switch style {
case CustomLabelStyle.ScreenTitle.rawValue:
font = UIFont(name: "HelveticaNeue", size: 18)
color = UIColor(hexString: "#404040")
break
case CustomLabelStyle.H2.rawValue:
font = UIFont(name: "HelveticaNeue-Bold", size: 20)
color = UIColor(hexString: "#404040")
paragraphStyle.lineSpacing = 5
break
case CustomLabelStyle.H3.rawValue:
font = UIFont(name: "HelveticaNeue-Bold", size: 16)
color = UIColor(hexString: "#404040")
paragraphStyle.lineSpacing = 4
case CustomLabelStyle.BodyText.rawValue:
font = UIFont(name: "HelveticaNeue-Bold", size: 13)
color = UIColor(hexString: "#404040")
paragraphStyle.lineSpacing = 3
break
case CustomLabelStyle.BodyTextGray.rawValue:
font = UIFont(name: "HelveticaNeue-Bold", size: 13)
color = UIColor(hexString: "#8E8E8E")
paragraphStyle.lineSpacing = 3
break
case CustomLabelStyle.DescriptionText.rawValue:
font = UIFont(name: "HelveticaNeue-Bold", size: 12)
color = UIColor(hexString: "#8E8E8E")
paragraphStyle.lineSpacing = 2
break
default:
break
}
let attribute = [NSAttributedString.Key.font : font,
NSAttributedString.Key.foregroundColor : color,
NSAttributedString.Key.paragraphStyle : paragraphStyle]
self.attributedText = NSAttributedString(string: self.text ?? "", attributes: attribute)
}
override func layoutSubviews() {
super.layoutSubviews()
self.customStyle(style: style)
}
}
//Set text on a label
lblTest.text = "This is the dummy text for test"