Swift

Olvastam a CryptoScript fejlesztőjének egy blogbejegyzését, hogy hogyan is próbálta meg a projektjéből egy library-t készíteni, amit le lehet majd tölteni a Package menedzserrel. Bár igaz azóta sem haladt előre a dolog, de beadott egy bug reportot, amire szépen jöttek is a hozzászólások. Az utolsó előtti az az, hogy valaki egy probléma megoldására csinált egy javítást, és az már elvileg be is került a kódba az Apple ígérete szerint. Tehát tényleg működik a közösség formáló hatása!

ja, a bugreport linkje, ahol ez olvasható: [SR-29] Support custom directory layouts · Issue #5339 · apple/swift-package-manager · GitHub

Úgy látom nem csak engem nem hagyott nyugodni a téma :D
Ma olvastam az Apple RSS között, hogy valaki csinált erre a problémára egy teljesen más megközelítést :D
https://medium.com/swift-programming/uistoryboard-safer-with-enums-protocol-extensions-and-generics-7aad3883b44d#.w2vl7vsqe

Az Apple kiadta a Swift 3.0 előzetesét. Akit érdekel, itt vethet rá egy pillantást:

A változások listája itt nézhető meg:

Végleges verzió valamikor az év vége fele várható.

Szerintem azért adhatta ki most az előzetest, hogy a WWDC-n meg lehessen vitatni dolgokat belőle.

Egyetértek. :)

Egyébként én szeretem nagyon. Az előző commentemben leírt problémával sem volt semmi gond amúgy, mert saját cuccról van szó, szóval könnyen túllendültem rajta :).
Amúgy tudom a legnagyobb baja a namespace hiánya. Valamint a visszamenőleg kompatibilitás hiánya. Bár ez utóbbit úgy tudom, hogy a 4-es verziótól meg fogják oldani. Legalábbis nagyon remélem.
Amúgy legalább most már extension-öknél elfogadja típusként az struct.typealias nevet, a korábbi verzió nekem hibát dobott erre. Szóval nekem már ez is jelentős előrelépés :slight_smile:

Ez a sztori ide illik a legjobban, de félek, hogy topic címe miatt kevesen olvassák el.
Nyilván a cikk eleje a lényeg, halálra röhögtem rajta magam. Bár az is igaz, hogy sokan valószínűleg nem fogják érteni. Mindegy, nekem bearanyozta a napom:
https://medium.com/swift-programming/the-inheritance-curse-3402b9929454

Van egy kérdésem a DispatchQueue-vel kapcsolatban.
Most készítem első SpriteKit alapú alkalmazásomat. Most kezdek rájönni, hogy mit szabad csinálni és mit nem ahhoz, hogy folyamatos legyen az animáció.
Adódott egy olyan problémám, hogy elindul egy időigényesebb process a háttérben, mikor a user rákattint egy gombra, miközben megy az animáció. Emiatt ennek a szálnak a prioritását levettem kicsire, hogy folyamatos legyen az animáció. Ugyanakkor, ha a user rákattint egy másik gombra, akkor ennek a szálnak minél hamarabb be kellene fejeződnie. Lehetőség van utólag DispatchQueue qos prioritását állítani?
Vagy milyen módszerek vannak az ilyen feladatokra?
Az egyetlen egy ami eszembe jut az az, hogy a háttér feladatot több kisebb feladatra osztom. Ezeket sorban indítom el egymás után. És ha a user megnyomja a gombot, akkor az új feladatok nagyobb prioritással indulnának el. Van még valamilyen más lehetőség?

Lécci segítsetek!

Most először próbálkozom az On Demand Resources lehetőséggel.
Projektben természetesen bejelöltem, hogy használni szeretném a Build Settings-ben.
Valamint azt is beállítottam, hogy a Debug alatt másolja be a main bundlebe, hogy tudjam tesztelni anélkül, hogy feltölteném a Test Fligthra. (EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE)
Megjelöltem kb 50mp3-mat egy taggel.

Be is tölti a tag alapján a könyvtárat, vissza is tér a beginAccessingResources éa persze atz első után conditionallyBeginAccessingResources, hogy betölötte a fájlokat.
Simulátorban meg is tudom nézni, hogy ott van, ahol lennie kell, mindegyiknek.
Megtaláltam a hozzá tartozó plistet, az is helyesnek látszik.
És miután ellenőrzöm, hogy betöltötte-e a fájlokat tag alapján, utána a
Bundle.main.url(forResource: fajl, withExtension: “mp3”) nem talalja.
És van, hogy random 1-1 fájlt megtalál, de a többit nem, pedig mind létezik.

Van valami ötletetek? Mert így hogyan töltssem fel a test Flightba, ha nem is látom, hogy működik-e.

Úgy néz ki már tárgytalan.
Írta a dokumentáció, hogy hozzáférés előtt le kell kérdezni, hogy le van-e töltve, csak azt nem olvastam sehol sem, hogy a hozzáférés előtt közvetlenül kell lekérni. És így már azt is értem, hogy miért volt az, hogy néha működött. Azt hittem csak arra kell odafigyelni, hogy legyen letöltve és teljesen mindegy mikor férünk hozzá. És ha esetleg nincs letöltve, akkor meg csak hibát dob. Mindegy, jó kis tanuló lecke volt ez. :)

Megint lenne egy kérdésem.
Van egy Set típusú tömböm, ami struct típusú elemeket tartalmaz. És szeretném módosítani az egyik elem egyik értékét ( ahol egyezik a keresés eredménye).
Hogy lehet ezt egyszerűsíteni? Most úgy oldom meg, hogy megkeresem az indexet, kiveszem (és eltávolítom) az elemet, módosítom az értéket, majd visszarakom.
A subscript sajnos azt mondja, hogy read-only, így nem engedi közvetlen módosítani.
Szóval hogy lehet ezt egyszerűsíteni?

struct RequestItem {
	var content: String
	var identifier: String
}

var requests = Set<RequestItem>()
...
if let index = self.requests.firstIndex(where: { $0.content == anContent }) {
	var item = self.requests[index]
	item.identifier = anIdentifier
	self.requests.remove(at: index)
	self.requests.insert(item)
}

Ha jól értem a problémát, akkor szerintem így lehet egyszerűbben:
A RequestItem-nek definiáld felül a == operátorát, és a hashValue-t. A Set (halmaz) az hash alapján működik, és a kódodban én úgy értelmeztem, hogy elég csak az egyik field-nek azonosnak lennie, hogy a Struct megegyezzen egy másikkal. Szóval ha nálad a content-re kell vizsgálni és az identifier-t cserélni (nem fordítva lenne logikus?) akkor ez szerintem működik:

struct RequestItem: Equatable, Hashable {
var content: String
var identifier: String

var hashValue: Int {
	 return content.hashValue
}

static func ==(lhs: RequestItem,rhs: RequestItem) -> Bool{
	  return lhs.content == rhs.content
}  
}

Nem kell az index, így hogy meg van írva a hash és a ==, “jól” működik a Set contains metódusa. (alapból ha nem írod felül, ugye akkor a Struct minden mezőjét megnézi, hogy egyezik e)

var requests = Set<RequestItem>()
requests.insert(RequestItem(content: "content", identifier: "indentifier"))
let item = RequestItem(content: "content", identifier: "ok")
requests.update(with: item)

Mivel ugye a content alapján vizsgálja az egyenlőséget, így az update felül fogja írni a régi értéket.

A contains egyébként opcionális, mert ha nincs benne a régi érték a Setben, akkor csak szimplán berakja az újat mint az insert.

https://developer.apple.com/documentation/swift/set/1786980-update

ui: nem is kell az Equatable conform, a Hashable az az Equatable-ből származik

1 kedvelés

Köszi! Ahogy jobban átgondolom, az volt a hibám, hogy az identifier volt az azonosító, amivel a hashable-nél azonosítottam, és azt a contentre kellett volna állítanám.

Egyébként alapvetően abból indult ki a problémám, hogy azt hittem, hogy az azonosítót az Apple adja. De utólag így, hogy én adom, így semmit sem kell felül írnom a Setben. És azért fontos ez, mert a Content néha, nagyon ritkán megváltozhat… mindegy, köszi még egyszer…

Hát az azonosítót alapból az Apple adja, mármint, Struct-okat alapból ha csak nem írod felül, mezőnként hasonlít össze.
Viszont vagy egy másik ötletem a subscript immutable problémára:
requests = Set(requests.map({ (item) -> RequestItem in return item.content == "content" ? RequestItem(content: "your new value", identifier: "identifier") : item }))
Content alapján vizsgálod melyik azonos, aztán felülírod a contentet ahol az. Ez működik így, annyi van hogy a műveletigény mindig o(n). Viszont működik ugyanúgy sima tömbre is. Bár a te megoldásod is ennyi, mert egyszer ott is végig kell iterálni az összes elemen.

1 kedvelés

Tetszik nagyon ez a megoldás, mert “egy sorból áll”. Őszintén, fogalmam sincs, hogy mennyi memóriát vagy processzort igényel egy nagyobb életmű tömbnél.
Bár a find first index első körben biztos gyorsabban találja meg az elemet, de ott meg ott van pluszban a remove at index és az insert.
Amúgy gondolkodtam egy saját extensiönön: replaceAt függvények, de az meg csak egy sorral lenne rövidebb, tehát nem sokat nyernék.
Az Update amúgy ami jó lenne, csak ott meg az volt a baj, hogy pont sz egyedi azonosítót nem tudtam.

Egyébként nyilván nem volt teljes a kód, amit leírtam, mert az komplexebb lett volna. Local notification kiküldése, majd az alkalmazás újra indítása után (vagy előtérbe kerülésekor) a visszaellenőrzés volt a cél, hogy tudjam mi van függőben. És nem tudtam, hogy a notification kiküldésekor nekem kell megadnom az identifiert. Így már nincs szükség a fentebbi kódra. :)

1 kedvelés

Hát ugye az mondjuk egy normál tömbre O(n). Mert a first index gondolom addig iterál a tömbben amíg meg nem találja a keresett dolgot, nem tovább. Ez ugye lehet 1 de 100 is legrosszabb esetben egy n=100 elemű tömbnél. Maga a törlés az O(1), viszont utána a maradék elemet shiftelni kell eggyel balra. Ha az utolsót töröltük akkor nincs mit shiftelni de előtte ugye végig kell menni a tömbön. Ez eddig n. Viszont ha be is akarsz szúrni egy új elemet az még ugye megint járhat shifteléssel, ha ugyan oda szeretném berakni és nem csak a tömb végére. szóval legrosszab esetben ez + n tehát összesen 2n ami O(n).
Setnél kicsit más a helyzet, mert az elemek nem egymás mellett vannak a memóriában így ott a shiftelés nem szükséges. Viszont épp ezért az indexeléssel is vigyázni kell, mert az index csak akkor biztosan valid amikor lekérdezed, később lehet, hogy ott nincs adat, és nem definiált viselkedéshez vezet. Valahol a doksiban volt ez bővebben leírva, de most nem találom.
Utólag belegondolva az én megoldásom is 2n, mert van egy Set konstruktor hívás is ami gondolom úgy működik, hogy n szer meghívja az insert-et.

1 kedvelés

Belefutottam egy érdekes problémába. Szerintem a Swift fordító ott ad hibát, ahol nagyon nem kéne, főleg nem az alábbi hibaüzenettel: “Use of local variable ‘images’, before its declaration.”
Itt az adott kódrészlet:


Elég egyértelmű, hogy a 34.sorban létrehozott változó elérhető a viewDidLoad() metóduson belül. Viszont abban a pillanatban, ahogy a 41. sorban létrehozok egy újabb images nevű változót, (ugye ez teljesen valid, szimplán csak elfedi az előzőt) a fordító feldobja ezt a hibát, aminek egyszerűen semmi értelme nincsen. (Nyilván ha a 38.sorban self.images-el hivatkoznék a változóra, akkor működne, de ennek így is kéne.) Olyan mintha a fordító először a függvényen belüli változókat nézné, és nem látná a külsőt, hiszen akkor teljesen igaza lenne, de így ez értelmezhetetlen.

Minden normális nyelvben (pl JAVA-ban) ez teljesen valid:

class A {
	
	public static void main(String[] args) {
		new B();
	}
	
}

class B {
	
	int a = 20;
	B() {
		a = 2;
		int a = 10;
		System.out.println(a); // a = 10
	}
}

Kérdés: vajon ez szándékosan működik ilyen hülyén (most attól tekintsünk el, hogy ritkán csinál ilyet az ember, én is teljesen véletlenül futottam bele.), vagy hiba van a fordítóban?

En azt mondanam, hogy igaza van. A valtozo deklaracio blokk-szintu, tehat a 41. soros let a viewDidLoad scope-jaba tartozik, ugyhogy azon a szinten valoban duplikalt a valtozo.
(Modern) javascriptben ugyanigy van, hagyomanyosban meg rosszabb :)

let a = 5;
(function(){
   console.log(`a before: ${a}`); // undefined
   let a = 7;
   console.log(`a after: ${a}`); // 7
})();

De a blokk szintűség csak annyit jelent, hogy létrejön a 41.sorban és a metódus végén megszűnik. Attól még a 41.sor előtt a metódusban a másikkal azt csinálok amit szeretnék. A 41. sor után annyi történik, hogy onnantól az images az a lokális images-t jelenti. A self.images viszont jó. Ez így szerintem ebben a formában furcsa.

A blokk a {-tol a }-ig tart. azon belul nincs ujabb egyseg. A java megoldasa a furcsa szerintem, de ugye izlesek es pofonok… :)