Hallo allerseits! Vor kurzem gab es einen Wettbewerb der VKontakte Mobile Challenge, und meine Arbeit wurde mit einem Preis ausgezeichnet. Auf Anweisung der zweiten Stufe musste ein Newsfeed für mobile Geräte entwickelt werden, und die Hauptbewertungskriterien waren reibungsloses Scrollen und Nachladen. Als ich teilnahm, entschied ich, dass ich unabhängig vom Endergebnis versuchen werde, einen Artikel über den Ansatz zur Implementierung des Bandes und über meine Emotionen und Gefühle während des Wettbewerbs zu schreiben. Was ich getan habe. Unter der Katze Tipps und Tricks zum Entwickeln von Newsfeeds im Storytelling-Modus.

Über den Wettbewerb
Zunächst lohnt es sich, ein wenig über die Konkurrenz zu erzählen. Wie ich weiß, organisiert VKontakte solche Veranstaltungen jährlich für mobile Entwickler. Ich selbst habe bereits 2012 und 2013 teilgenommen. Die Aufgaben waren die Entwicklung von Chat- bzw. Bildfiltern. 2013 schaffte ich es in die Endrunde und gewann 100.000 Rubel, was mir dann für 4 Tage ohne interessante Arbeit eine sehr gute Menge erschien.
Und als ich die Anzeigen in einem sozialen Netzwerk sah, entschied ich, dass ich es versuchen muss, denn das Coole ist, sich selbst zu beweisen, dass Sie in sehr kurzer Zeit immer noch hochwertigen Code schreiben können.
Der Wettbewerb bestand aus zwei Phasen: In der ersten Phase wurde vorgeschlagen, einen Test mit 30 Fragen zu bestehen, zwei Olympiadenprobleme und eine qualitativ hochwertige zu lösen (d. H. Eine Lösung besteht aus einer Reihe Ihrer Gedanken in Form von Text). In der zweiten Runde von mehr als 1000 Personen bestanden nur 112 (wir sprechen nur über iOS, auf Android etwas niedrigere Werte) und die Hauptphase begann - die Anwendungsentwicklung.
Bei der Zuweisung mussten Sie einen Newsfeed erstellen, die Integration in die VK-API selbst schreiben, der Feed sollte auf allen Geräten sehr reibungslos verlaufen sein, es gab bestimmte Anforderungen für die Anzeige von Inhalten (Beiträge mit Bildern und einem Karussell, Zähler für Likes, Freigaben, Anzahl der Aufrufe sowie die Möglichkeit zur Minimierung) und den Beitrag unter bestimmten Bedingungen bereitstellen).
Layouts wurden in Figma angelegt. Dies ist eine gute Wahl für den Wettbewerb - aufgrund der Anzahl der aktiven Benutzer ist der Wettbewerb sofort zu spüren (und wurde sogar am Samstag ausgeschaltet, weil das gleichzeitige Limit von 50 Verbindungen überschritten wurde).
Im Allgemeinen verlief die Organisation des Wettbewerbs bis auf einige Punkte reibungslos: Unmittelbar nach der Veröffentlichung des Auftrags stellte sich heraus, dass die Verknüpfung zu den Layouts unterbrochen war. Dann wurde, wie oben erwähnt, am Samstag der Eingang zu Figma blockiert (dieses Problem wurde sehr schnell behoben). Nun, nach der Veranstaltung dauerte es eine Weile Ergebnisse erwarten. Aber all das Negative glättet einen ähnlichen Beitrag:
Siegesplan und Strategie
Ein sehr wichtiger und interessanter Block, wenn Sie an Wettbewerben teilnehmen oder es versuchen möchten. Vor der Teilnahme empfehle ich jedem, darüber nachzudenken, welches Ziel Sie verfolgen und welches Ergebnis Sie auf dem Weg nach draußen erzielen möchten. Bevor ich mit dem Wettbewerb anfing, habe ich selbst entschieden, dass ich ihn gewinnen möchte (d. H. Den Preis annehmen). Und dazu brauchen Sie eine Strategie:
Das Folgende ist die Formel für eine Gewinnstrategie (sie scheint mir universell und einfach zu sein, aber ich bin sicher, dass die meisten Teilnehmer sie nicht befolgen):
- Lesen Sie die Aufgabe sehr sorgfältig durch . Lesen Sie es nach einigen Stunden noch einmal durch (ich bin mehrmals in eine Situation geraten, in der ich Aufgaben beim ersten Mal nicht wahrgenommen habe). Und ein paar Stunden vor der Lieferung noch einmal für alle Fälle.
- Stellen Sie Fragen und stellen Sie sie den Organisatoren (normalerweise berücksichtigen die Anforderungen für den Auftrag nicht viele Situationen oder sind sehr oberflächlich). Ich habe genau das getan und Antworten im Stil "Ihrer Wahl" erhalten.
- Machen Sie einen Projektplan. Ja, die Teilnahme an einem Wettbewerb oder Hackathon ist ein Projekt. Das Projekt hat ein Ziel, einen Zeitplan, Ressourcen und ein Budget. Die Zeit ist streng begrenzt und es ist unmöglich, das Ende der Veränderung zu verschieben. Zusätzliche Personen können nicht eingeladen werden - der Wettbewerb ist kein Teamwettbewerb. Alles was du hast sind deine eigenen Leute. / Uhr. Bestimmen Sie sofort, wie viel Sie bereit sind, auszugeben (denken Sie gut darüber nach, wie viel Schlaf, Essen, Kastration, Pausen und ja, Ihre Produktivität aufgrund von Müdigkeit und Nerven aufgrund eines Gefühls der Hilflosigkeit vor einem unaufhaltsam nahenden Zeitrahmen sinken wird).
- Der Plan sollte Aufgaben, ihre Prioritäten und Gewichte enthalten (ich habe Schätzungen der Form 1, 2, 4, 8 verwendet). Die Bewertung umfasst die Dauer, die mangelnde Bereitschaft zur Erfüllung und potenzielle Risiken (Komplexität, unverständliche Bedingungen, keine Erfahrung mit einer solchen Entwicklung usw.). Als nächstes erstellen Sie einen detaillierten Plan (oder Roadmap-Aufgaben) - zuerst die wichtigsten und komplexesten (lassen Sie am Ende einfach und verständlich).
- Wählen Sie einige große Intervalle oder Meilensteine (Tage sind großartig - wir hatten 3 Tage). Und während Sie die einzelnen Schritte durchgehen, sehen Sie sich Ihren Arbeitsplan an, zerlegen Sie die Aufgaben, sortieren Sie sie und streichen Sie vor allem die Aufgaben durch, die Sie bereits mit Vergnügen erledigt haben.
Nun der Rat (genau das habe ich getan): Schauen Sie sich genau an, wie die Aufgabe formuliert ist, ob sie die Wörter „erforderlich“ und „zusätzlich“ enthält. Und was sind die Bewertungskriterien für die Elemente aus dem "zusätzlichen", d.h. ob sie ihren Mangel an umgesetzten Anforderungen aus dem Abschnitt „obligatorisch“ außer Kraft setzen. Ich bezweifle. Konzentrieren Sie sich daher auf den Abschnitt „Erforderlich“. Für mich selbst habe ich den Abschnitt „Fortgeschrittene“ im Allgemeinen bewusst durchgestrichen und wollte ihn nicht einmal starten. - Achten Sie bei der Implementierung auf die Details . Wenn die Aufgabe beispielsweise viele Schnittstellenformulare enthält, führen Sie diese so aus, wie sie in den Layouts angezeigt werden. Achten Sie auf Einrückungen, Schriftarten, Schatten, Zeilenabstände usw. Dies wird Ihnen sicherlich Punkte für Genauigkeit und Konsistenz hinzufügen. Übrigens gibt es in Figma im Gegensatz zu Zeplin einen sehr breiten Export von Einstellungen, zum Beispiel können Sie einen guten NSAttributedString erhalten.
Die Mission wurde in der Nacht von Donnerstag auf Freitag eröffnet. Freitag ist ein Arbeitstag und es gab keine Gelegenheit und keinen Wunsch, an einem Wettbewerb bei der Arbeit teilzunehmen. Nachdem ich am Freitagabend von der Arbeit zurückgekehrt war, plante, bewertete und berechnete ich zunächst, wie viel Echtzeit ich verbringen kann.
Der ursprüngliche Plan war wie folgt:
Tag | Zeit | Die Aufgaben |
Freitag | 4 Stunden | Autorisierung, Abrufen von Daten für das Profil und das Band. |
Samstag | 9 Stunden | Der Prototyp des Bandes mit der Anzeige von roten Quadraten unterschiedlicher Höhe, die durch Ziehen zum Aktualisieren und endloses Laden in den Verlauf oben geladen werden, Vorbereitung aller Modelle und Dienste (Arbeiten mit der API, Anforderungs-Caching, Bild-Caching).
|
Sonntag | 9 Stunden | Ausgabe von realen Daten (Text, Einzelbilder und Karussells), Zählern von Likes, Ansichten und endgültiger Abstimmung nach Layouts. |
Bandimplementierungstechnik
Hurra! Meine Herren, Entwickler, Sie haben den richtigen Block gefunden. Hier werden wir über die Implementierung des Hauptteils der Aufgabe sprechen - des Newsfeeds.
Wenn wir den Newsfeed deaktivieren, handelt es sich im Allgemeinen nur um eine angewendete Implementierung. Im Allgemeinen wird über das Erstellen einer Liste heterogener Entitäten gesprochen (dh jede kann eine eigene Anzeige haben, die zusätzliche Berechnungen erfordert, und ihre eigene Höhe, die sich auch nach der Anzeige des Posts dynamisch ändern kann.) Außerdem kann die Liste per Pull-to-Refresh aktualisiert und Daten von unten unendlich geladen werden.
Es war das allgemeine Problem, das ich überhaupt lösen wollte. Der erste Schritt besteht darin, vorhandene Lösungen zu analysieren. Sie müssen sich auf die Stärksten konzentrieren, daher habe ich 3 Anwendungen zum Vergleich ausgewählt: Vkontakte, Facebook, Instagram.
Also wollte ich eine Studie über die 6 akutesten und kritischsten Probleme durchführen:
- Pull-to-Refresh (am Anfang der Liste hinzufügen)
- Reibungsloses Laden des Verlaufs (am Ende der Liste hinzufügen)
- Schnelles Scrollen (abwechselnd mit den Fingern beschleunigen wir das Band so weit, wie es die Reibungskraft zulässt)
- Scrollen Sie nach oben (sammeln Sie eine große Geschichte und klicken Sie auf die Statusleiste)
- Gibt es eine dynamische Offenlegung (Erhöhung) des Beitrags und was ist die Animation?
- Wie das Band im Modus des fast vollständigen Paketverlusts funktioniert (Entwickler -> Network Link Conditioner -> Sehr schlechtes Netzwerk)

Im Allgemeinen verhalten sich alle Anwendungen gut, aber ich habe immer noch einige Probleme festgestellt.
Sehen Sie sich beispielsweise an, wie sich das Pull-to-Refresh-Verhalten in VKontakte verhält, wenn Sie Ihren Finger während des Updates nicht loslassen und das Menüband vorsichtig nach oben ziehen (siehe GIF links).
Sehen Sie diesen Sprung auch?
Instagram und Facebook zeigten kein solches Verhalten.
Und es gibt auch einen spürbaren Unterschied bei der Offenlegung nach der Veröffentlichung. Bei Facebook und Instagram geschieht dies mit einer reibungslosen Animation, und VKontakte aktualisiert die Größe einfach durch Klicken.



Unsere Aufgabe ist es also, eine reibungslose Schriftrolle zu erstellen, Beiträge herunterzuladen und auch mit Animation zu enthüllen.
Der erste Schritt besteht darin, ein Konzept auszuwählen und einen Prototyp auf roten Quadraten zu erstellen (ich frage mich, warum ich für Prototypen immer intuitiv eine rote Farbe wähle. Ist dies bei allen der Fall?).
Meine Hauptidee bei der Verbesserung der Produktivität war es, alle Schnickschnack, die Apple seit vielen Jahren eingeführt hat, aufzugeben und buchstäblich auf die Entwicklung für iOS 3 zurückzugreifen. Und das bedeutet:
- Ablehnung von AutoLayout (ja, es ist langsam, glaube es nicht - ich kann es in den Kommentaren beweisen)
- Weigerung, die Höhe von Tabellenzellen automatisch zu berechnen
Als Ergebnis wurde das folgende Konzept gewählt:
Lassen Sie uns etwas detaillierter werden.
Im Hauptthread aktualisieren wir die Benutzeroberfläche, verarbeiten Benutzeraktionen (nach unten scrollen und zum Aktualisieren ziehen, auf einen Beitrag klicken, um ihn zu vergrößern) und lösen ein Servicemodell zum Empfangen und Vorbereiten von Daten aus.
API-Aufruf . Hier ist alles einfach - NSURLSession mit konfiguriertem NSURLCache. Es ist wichtig, dass wir beim Laden des Verlaufs den Cache verwenden und ihn beim Pull-to-Refresh deaktivieren. Genau dieses Verhalten habe ich auf VK und Facebook ausspioniert.
Parsen und Erstellen von Modellen . Hier ist die Logik zum Verarbeiten einer bestimmten Anforderung, zum Auslösen von Fehlern und zum Zurückgeben von Transportmodellen mit Daten.
Berechnung von Präsentationsmodellen . Der wichtigste Schritt zur Leistungsoptimierung. Hier werden Transportmodelle mit dem PostModel-Postfix in Entitäten umgewandelt. ViewModel speichert vollständig vorbereitete Daten für die Anzeige - AttributedString, berechnete Zellenhöhe (für 2 Zustände: reduziert und erweitert), vollständiger Name als Zeichenfolge, Datumszeichenfolge (bereits aus DateFormatter konvertiert).
Erst danach kehren die Daten zum Hauptstrom zurück. Die Implementierung einer solchen Logik in Swift ist sehr bequem und einfach. Wir machen ViewModel Struktur. Strukturen werden beim Übertragen in einen neuen Stream kopiert.
Ausgezeichnetes Konzept fertig, jetzt sprechen wir über den Ausgabemechanismus selbst.
Zuerst mussten Sie auswählen, auf was das Band implementiert werden soll - UITableView oder UICollectionView (es würde definitiv nicht genügend Zeit für Ihre Implementierung zur Verfügung stehen). Natürlich eignet sich UITableView zum Auflisten von Ausgaben, aber ich war sehr besorgt, ob es Probleme beim Vergrößern der Liste von oben nach unten und beim Vergrößern der Inhaltszelle geben würde. Daher habe ich mich entschieden, von einfach zu komplex zu wechseln - d. H. Wenn die UITableView keine Probleme hat, lassen wir es.
Das erste, was ich beschlossen habe, war, mich für Pull-to-Refresh zu entscheiden. Um dieses Muster zu implementieren, gibt es ein UIRefreshControl. Vor ungefähr 5-6 Jahren habe ich meine Implementierung einmal mit dem UIActivityIndicator geschrieben und das contentInset der Tabelle geändert. Also, bitte mach es jetzt nicht! UIRefreshControl verfügt über eine praktische, kompakte Oberfläche und nimmt eine Wolke von Krücken auf, die Sie sicherlich herstellen müssen. Die Verwendung ist sehr einfach:

Bei der Verwendung wird jedoch deutlich, woher die oben für den VK-Client gezeigten Probleme stammen. Es scheint, dass sie in der Komponente selbst existieren. Ich habe schnell versucht herauszufinden, was der Grund sein könnte und welche Lösungen es gibt.
Internet-Tipps sagen (
so oder
so ):
- Überprüfen Sie beim Aufruf von endRefreshing, ob das Steuerelement jetzt aktualisiert wurde (isRefreshing).
- Verwenden Sie genau UITableViewController (da in diesem Fall die magische private Methode aufgerufen wird).
Ich habe dies und das versucht - ich hatte keine positive Wirkung. Ich war verärgert, beschloss aber, keine Zeit zu verschwenden und weiterzumachen. Übrigens, wenn jemand weiß, wie man dieses Problem löst - schreiben Sie bitte in die Kommentare.
Der nächste Schritt besteht darin, das Laden von Daten von unten zu implementieren.
Zuerst wurde ich nicht sehr cool - beim Laden von unten gab es eine schreckliche Verzögerung (ich habe anscheinend die contentSize von der Tabelle gesprungen):
Und das ist die Hölle :-) Mit diesem Ergebnis können Sie definitiv nicht gewinnen. Aber eine schnelle Suche gab mir einen tollen Hinweis, den ich vergessen hatte:

Und voila:
Es bleibt zu entscheiden, wie die Höhe der Zelle animiert werden soll.
Die erste Idee, die mir in den Sinn kam, war, entlang sichtbarer Zellen zu laufen und die Höhe im Animationsblock zu erhöhen. Aber auch in der Phase der Analyse sollte diese Idee verworfen werden - das Problem ist, dass es notwendig sein wird, die in der UITableViewDataSource angegebene Höhe zu synchronisieren und etwas mit contentSize zu tun (und dies wird von Apple dringend empfohlen).
Der zweite Gedanke, der mir in den Sinn kam, stellte sich als richtig heraus: UITableView verfügt über Methoden zum Einfügen / Neuladen / Löschen, die im Animationsblock ausgeführt werden können:

Vergessen Sie nicht, dass wir in heightForRowAt auch eine neue Höhe hinzufügen müssen:

Alles scheint zu sein, aber nicht ganz! In der Animation des Einsatzes des Beitrags gab es einen subtilen Punkt. Suchen Sie nach dem Text im Intagram oder Facebook - er wird mit zunehmender Höhe sofort reibungslos angezeigt. Was zu tun ist? Zeile für Zeile rendern? Wenn Sie die Stufe von NSTextContainer erreichen, wird möglicherweise eine ähnliche Gelegenheit angezeigt. Aber es schien mir, dass es (für eine solche Zeit) keine so schlechte Idee war, den gesamten Text auf einmal anzuzeigen. Setzen Sie einfach clipToBounds auf superView, in dem sich UILabel befindet und unseren Text anzeigt. Und der Ansatz hat funktioniert! Oh, diese Animation hat mich sehr inspiriert und ein zweiter Wind öffnete sich. Schließlich gibt es im nativen Client von VK keine solche Animation. Also sollte sie Gewinnchancen hinzufügen :-)
Die restlichen Details bei der Implementierung des Bandes sind nicht so interessant. Aber Sie können sie in den Kommentaren fragen. Und es ist nichts Falsches daran, den Code zu gestalten. Hier ist es -
github.com/katleta3000/vkmobilechallenge . Es tut mir leid, dass ich nicht gekämmt bin und es an einigen Stellen magische Zahlen gibt (aber dies ist ein Geschwindigkeitswettbewerb, ich musste etwas opfern). Übrigens können Sie dort auf Commits springen (die Namen sind ziemlich klar).
Das Ergebnis ist hier zu sehen -
www.youtube.com/watch?v=Md8YiJxSW1M&feature=youtu.be (die Qualität ist natürlich stark verloren, aber besser als im GIF, um genau glattes Scrollen zu demonstrieren)
Statistiken, Ergebnisse, Schlussfolgerungen
Die ganze Zeit arbeitete der Wettbewerb an einem Timer. Es kamen 20 ½ Stunden reine Codierungszeit heraus. Die Nachverfolgungszeit hat in zweierlei Hinsicht geholfen: Wie Sie sich erinnern, gab es Schätzungen in abstrakten Einheiten, sodass es Mitte des letzten Tages bereits gute Nachverfolgungsstatistiken gab und es möglich war, die verbleibenden endgültigen Aufgaben viel genauer zu planen. Und zweitens konnte das Muster der „Konzentration in einer Sitzung“ identifiziert und bewiesen werden. Jede Dimension ist eine neue Iteration, daher stellte sich heraus, dass ich 68 Iterationen zum Schreiben von Code hatte. Wenn Sie durchschnittlich sind, erhalten Sie 18,5 Minuten. Tatsächlich gab es am ersten Tag der Iteration durchschnittlich 25 Minuten und am Ende des zweiten Tages jeweils 7 Minuten :-) Sie werden verrückt, werden sehr nervös, werden müde und die Leistung sinkt. Solche Daten werden beim nächsten Mal gut helfen.
Persönlich habe ich das
Stundenprogramm verwendet (Sie können es herunterladen und ausprobieren) - es löst einfach und löst die notwendige Aufgabe (und entwickelt es sogar selbst):
Von den netten Boni - für jedes geschlossene Puzzle wird ein sehr schöner beruhigender Bildschirm wie dieser angezeigt:
Es ist lustig, dass mir nach Abschluss der Aufgabe „VK Mobile Challenge“ der folgende Bildschirm angezeigt wurde:
Und ja! Und so geschah es :-) Wir fahren mit den Ergebnissen fort.
Lassen Sie uns nicht Peach für den Plüsch ziehen. Peach, der es nicht wusste, ist der Name der Katze - die Hauptfigur von VK. Sehr cooler Geschenkartikel:
Ich nahm den 4. Platz ein und bekam 175k Rubel. (Ja, und Sie haben das Bild wahrscheinlich bereits auf Habra-kat gebrannt). Und ja, ich bin auf jeden Fall zufrieden. Ich habe mein Ziel erreicht :-) Und das ist zweifellos wahnsinnig angenehm.
Am Ende möchte ich mich bei
vkontakte bedanken - schließlich war der Wettbewerb cool und gut organisiert. Und ich empfehle allen Lesern, an Herausforderungen und Hackathons teilzunehmen - dies ist eine großartige Möglichkeit, sich selbst herauszufordern und mit Top-Entwicklern auf der ganzen Welt (zumindest der russischsprachigen Community) zu konkurrieren.