Aus mir nicht erfindlichen Gründen wurde bei einem SwiftUI File einfach die Leinwand (von Canvas) nicht mehr angezeigt. Googeln half auch nicht. Catalina 10.15 setze ich ein. Schließlich hat es ja auch vorher funktioniert. Im gleichen Projekt mit anderen SwiftUI Files wurde die Preview auch angezeigt. Also empfehle ich einen flotten Workaround. Copy + Paste ist hier die Lösung. Einfach ein neues File anlegen und das alte Löschen. Quellcode wieder einfügen und schwups…die Preview ist wieder da. Natürlich sollte man vorher prüfen, ob die Leinwand überhaupt eingeblendet wird.
Über das Menü Editor + Canvas kann die Leinwand ein- bzw. ausgeblendet werden. Eine weitere Möglichkeit ist die Tastenkombination: ALT – Command – RETURN
Hier im Bild kann man auf das Symbol rechts oben, 2. von rechts bemühen.
SwiftUI ist meiner Meinung nach ein absoluter Meilenstein in der Softwareentwicklung. Sicherlich kostet es Zeit sich in diese neue Art des Entwickelns einzufinden, aber der Zeitaufwand, den man bei weiteren Projekten einspart, kann man hier gut investieren. Hier findest Du ein einfaches Beispiel für ein SwiftUI TableView. Das Sample Project kannst Du einfach runterladen und frei verwenden. In dem Projekt ist bewusst nicht mehr enthalten, damit die wesentlichen Funktionen zum Verständnis beitragen.
Es ist schon beeindruckend, mit wie wenig Zeilen Code man ein TableView / ListView mit SwiftUI zaubern kann. Einfach ein neues Projekt anlegen und darauf achten, daß als User Interface SwiftUI ausgewählt wird.
Natürlich benötigst Du noch 3 Bilder für diese Beispiel, die sind ebenfalls in dem Beispielprojekt enthalten.
Der eigentliche Code für das Projekt.
import SwiftUI
struct ContentView: View {
var oListArray: [oListenEntries] = testData
var body: some View {
List(oListArray) { item in
Image(item.imageName).resizable().frame(width: 32.0, height: 20.0)
VStack(alignment: .leading){
Text(item.make)
Text(item.model)
.font(.subheadline)
.foregroundColor(Color.gray)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(oListArray: testData)
}
}
}
Hier noch der Code für das zugrundeliegende Array. Dafür habe ich ein SwiftUI View mit dem Namen oListEntries.swift angelegt.
import SwiftUI
struct oListenEntries : Identifiable {
var id = UUID()
var make: String;
var model: String;
var imageName: String { return make }
}
let testData = [
oListenEntries(make: "Flaschenhalter", model: "für Balkon oder Pool"),
oListenEntries(make: "Pooladapter", model: "32 mm auf 12 mm"),
oListenEntries(make: "Sektglashalter", model: "schwimmend")
]
Bei den ersten Gehversuchen mit Swift UI habe ich krampfhaft versucht herauszufinden, wie man das aktive Tab programmatisch auswählt. Der Trick liegt im Binding.
@State public var selection = 0
Mit Klick auf den Button erzählt selection den Wert eins. Da Selection direkt an die Tabbar gebunden ist, ändert sich das aktive Tabitem wunschgemäß.
Button("Go",action: {self.selection = 1})
Binding ist das Zugriffstoken, das Sie weitergeben können, um direkten Lese- und Schreibzugriff auf den Wert zu ermöglichen, ohne den Besitz (im Sinne der Beibehaltung eines Referenztyps) oder das Kopieren (für einen Werttyp) zu gewähren.
Wenn der Benutzer eine Registerkarte in der Registerkartenansicht auswählt, ändert er den Wert einseitig über Bindung und weist der ausgewähltenTab-Variablen das zugehörige .tag(…) zu. Dies funktioniert für @State und ObservableObject auf die gleiche Weise.
Der Programmierer kann dieser ausgewähltenTab-Variablen auch jederzeit einen Wert zuweisen – und die TabView schaltet die angezeigte Registerkarte sofort um. Dies ist der Schlüssel zur programmatischen Navigation in SwiftUI.
Hier ist ein Beispiel, daß man direkt Copy / Paste übernehmen kann um damit rumzuspielen.
Hier findest Du die wesentlichen Dinge, die Du brauchst um ein TableView zu durchsuchen. Zuerst ziehst Du mal eine Searchbar aus dem Objektkatalog und erstellst im Code ein Outlet.
Nachdem Du das Outlet im Quelltext gesetzt hast, setze das delegate.
Jetzt benötigen wir noch eine Variable „searching“ sowie ein weiteres 2-dimensionales Array. Die Variable searching bekommt den Wert true, während eine Suche stattfindet. Hier im Beispiel siehst du die Variable für das 2. Array, dass baugleich mit dem Array results ist. In das 2. Array wird jeweils das Filterergebnis gesetzt. Jetzt weißt Du, warum wir die Boolean Variable „searching“ benötigen. So kann man für alle weiteren Aktionen im Code abfragen, aus welchem Array man sich gerne bedienen möchte. Je nachdem ob halt gerade gesucht wird oder die Komplette Liste im Tableview dargestellt wird.
var searching = false
var filteredresults: [[String: String]]? = [[String: String]]()
Nun diese extension hinzufügen. Hier wird das 2. Array filteredresults mit dem Filterergebnis gefüllt und festgelegt ob unsere Variable searching true oder false gesetzt wird. Logischerweise wird
Ich berichte hier einfach mal aus Erfahrung. Die Theorie sagt, dass App’s im App Store von Apple nach 24 Stunden in der Suche aufgefunden werden. In der Praxis durchaus nach wenigen Minuten. Wir sprechen hier von App’s, die gerade das Approval erhalten haben und zum ersten mal im App-Store zur Verfügung stehen. Wenn Deine App gerade frisch das Approval erhalten hat, ist Sie nicht automatisch sofort auffindbar.
Trotzdem darfst Du Dich freuen, wenn Du diese Mail bekommst. Das Approval kann doch manchmal ein nervender Prozess sein. Am Ende entscheiden Menschen und keine Algorithmen. Menschen sind in Ihren Entscheidungen nun einmal subjektiv. Sicherlich kann jeder App-Entwickler von seinen Erfahrungen berichten. Hier gilt aber, einfach nicht aufgeben. Eine App kann durchaus auch mal abgelehnt werden, obwohl Sie schon lange zugelassen wurde. Der nächste Mitarbeiter von Apple schaut vielleicht auch mal etwas genauer hin und hat etwas zu meckern. In den meisten Fällen haben Sie bei genauer Betrachtung recht – nur manchmal wird es etwas merkwürdig. Dann gilt stumpf…App an die Anforderungen anpassen.
Hier jetzt mal in ganz einfach. In diesem Beispiel habe ich mit Swift 5.1 gearbeitet.
Wir möchten das Datum im Format: 2020-01-06T19:23:43.97+01:00 – ISO8601 in das Format: 06.01.2020 07:23:43 konvertieren.
let dateFormatter = DateFormatter()
//Wir erhalten das Ausgangsformat ISO8601
//Beispiel: 2020-01-06T19:23:43.97+01:00
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
//Das Datum wird aus einem XML Stream geladen
let stringDate : String = oAMZXMLParser.results![0]["Logdatum"]!
print(stringDate)
//Aus dem String wird in das Date Format konvertiert
let date = dateFormatter.date(from: stringDate)
let df = DateFormatter()
//Nun legen wir das in Deutschland übliche Format fest
df.dateFormat = "dd.MM.yyyy hh:mm:ss"
//aus dem Date erzeugen wir wiederum ein String
let sNewDateFormat = df.string(from: date!)
print(sNewDateFormat)
Herrjeh…diese String-Operationen in Swift können einen schon wahnsinnig machen, wenn man aus C# ein einfaches gewohnt ist. Deshalb habe ich mich damit auseinander gesetzt und hier ein wenig zusammengetragen. Getestet wurde das mit Swift 5.1
startIndex ist der Index des ersten Zeichens
endIndex ist der Index nach dem letzten Zeichen
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let str = "Hello, playground"
print(str[str.startIndex]) // H
//print(str[str.endIndex]) // error: after last character
let rangeStartToEnd = str.startIndex..
before bezieht sich auf den Index des Zeichens direkt vor dem angegebenen Index.
// character
let index = str.index(before: str.endIndex)
str[index]
// range
let range = str.startIndex..
Der OffsetBy-Wert kann positiv oder negativ sein und beginnt ab dem angegebenen Index. Obwohl er vom Typ String.IndexDistance ist, können Sie einen Int Wert übergeben.
// character
let index = str.index(str.startIndex, offsetBy: 7)
str[index]
// range
let start = str.index(str.startIndex, offsetBy: 7)
let end = str.index(str.endIndex, offsetBy: -6)
let range = start..
Das limitedBy ist nützlich, um sicherzustellen, dass der Offset nicht dazu führt, dass der Index über die Grenzen hinausgeht. Es ist ein Begrenzungsindex. Da es möglich ist, dass der Offset die Grenze überschreitet, gibt diese Methode ein Optional zurück. Sie gibt null zurück, wenn der Index außerhalb der Grenzen liegt.
if let index = str.index(str.startIndex, offsetBy: 7, limitedBy: str.endIndex) {
str[index]
}
Wäre der Offset 77 statt 7 gewesen, dann wäre die if-Anweisung übersprungen worden.
Warum denn nun der ganze Umstand?
Es wäre viel einfacher, einen Int-Index für Strings zu verwenden. Der Grund dafür, dass Sie für jeden String einen neuen String.Index erstellen müssen, ist, dass die Zeichen in Swift nicht alle gleich lang unter der Haube sind. Ein einzelnes Swift-Zeichen kann aus einem, zwei oder sogar mehreren Unicode-Codepunkten bestehen. Daher muss jeder eindeutige String die Indizes seiner Zeichen berechnen.
Es ist möglich, diese Komplexität hinter einer Int-Indexerweiterung zu verbergen, aber ich zögere, dies zu tun. Es ist gut, an das erinnert zu werden, was tatsächlich passiert.
Übersetzt mit www.DeepL.com/Translator (kostenlose Version)
Eine hilfreiche Extension
Folgende Extenson muss noch unter Deine Klasse im Code gehängt werden. Diese Extension bietet Dir die Möglichkeit innerhalb eines String gleich den Index einer ganzen Zeichenfolge zu ermitteln. In meinem Beispiel "ground".
String-Operationen werden also über Indices und Ranges angesprochen. Der Index ist also keine einfache Integervariable.
So konvertiert man einen Substring in einen String Swift: 5.1
Swift hat einen dedizierten Substring-Typ (String.SubSequence), der für die Aufnahme von Teilen eins Strings ausgelegt ist, was eine Leistungsoptimierung darstellt: Wenn Sie einen Teil eines Strings in einer anderen Variablen speichern, kann Swift den Substring einfach auf den übergeordneten String zeigen, anstatt alle Daten zu kopieren.
Obwohl Teilzeichenketten auf viele der gleichen Arten wie normale Zeichenketten verwendet werden können, sind sie nicht gleich – wenn Sie eine Funktion haben, die eine Zeichenkette als Parameter akzeptiert, können Sie ihr einfach keine Teilzeichenkette senden.
Um dies zu beheben, können Sie Ihren Substring in einen String-Initialisierer wie folgt einpacken:
let quote = "The revolution will be Swift"
let substring = quote.dropFirst(23)
let realString = String(substring)
This website uses cookies to improve your experience while you navigate through the website. Out of these cookies, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may have an effect on your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.