I have the following class
// LearningItem
class LearningItem : NSObject {
var id: String
var title: String
var subtitle: String?
var image: String
var uploadDate: Int
init(id: String, title: String, image: String, uploadDate: Int) {
self.id = id
self.title = title
self.image = image
self.uploadDate = uploadDate
}
I have another class
// Book.swift
class Book: LearningItem {
var publishDate: String?
var author: String?
var mediaUrl: String?
var video : String?
var tags: [String]?
var lists: [String: AnyObject]?
var readCount: Int
var categories: [String]?
var courses: [String]?
var amazonBuyUrl: String?
var starCount: Int
var read: Bool?
var completed = [String : Int]()
var stars = [String : Int]()
var completedDate : Int?
var desc: String
var epub: String
var authorDesc: String
init(id: String, title: String, desc: String, authorDesc: String, image: String, epub: String, readCount: Int, uploadDate: Int, starCount: Int) {
super.init(id: id, title: title, image: image, uploadDate: uploadDate)
self.id = id
self.desc = desc
self.authorDesc = authorDesc
self.title = title
self.epub = epub
self.image = image
self.readCount = readCount
self.uploadDate = uploadDate
self.starCount = starCount
}
I get the error "Property 'self.readCount' not initialized at super.init call"
where I call "super.init(id: id, title: title, image: image, uploadDate: uploadDate)" in Book.swift
Class initialisation not finished until it's designated initializers
not finished with initializing all properties
and after that you can call super class's designated initializers
Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.
SO
Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.
apple docs https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
so
class Book: LearningItem {
var publishDate: String?
var author: String?
var mediaUrl: String?
var video : String?
var tags: [String]?
var lists: [String: AnyObject]?
var readCount: Int
var categories: [String]?
var courses: [String]?
var amazonBuyUrl: String?
var starCount: Int
var read: Bool?
var completed = [String : Int]()
var stars = [String : Int]()
var completedDate : Int?
var desc: String
var epub: String
var authorDesc: String
init(id: String, title: String, desc: String, authorDesc: String, image: String, epub: String, readCount: Int, uploadDate: Int, starCount: Int) {
self.readCount = readCount
self.starCount = starCount
self.desc = desc
self.epub = epub
self.authorDesc = authorDesc
super.init(id: id, title: title, image: image, uploadDate: uploadDate)
}
}
Related
I create a default realm file to use it during first launching app as replacement (I want to have a file with initial data). I start with creating default realm file from csv files. The problem is that I am not sure if my structure is correct. When I import data from csv (in Realm Browser) and try to import next data for next class, I get this error
I have main class called Exercises
class Exercises: Object {
#Persisted var id: Int = 0
#Persisted var name: String = ""
#Persisted var category: Category?
#Persisted var equipment: Equipment?
#Persisted var instruction: String
#Persisted var muscle: List<Muscle>
#Persisted var gif: String?
#Persisted var image: String?
convenience init(id: Int, name: String, category: Category?, equipment: Equipment?, instruction: String, muscle: [Muscle], gif: String?, image: String?) {
self.init()
self.id = id
self.name = name
self.category = category
self.equipment = equipment
self.instruction = instruction
self.muscle.append(objectsIn: muscle)
self.gif = gif
self.image = image
}
}
and other classes for separate things
class Equipment: Object {
#Persisted(primaryKey: true) var equipmentID = 0
#Persisted var equipment: String = ""
convenience init(equipment: String) {
self.init()
self.equipment = equipment
}
}
class Category: Object {
#Persisted(primaryKey: true) var categoryID = 0
#Persisted var category: String = ""
convenience init(category: String) {
self.init()
self.category = category
}
}
class Muscle: Object {
#Persisted(primaryKey: true) var muscleID = 0
#Persisted var muscle: String = ""
convenience init(muscle: String) {
self.init()
self.muscle = muscle
}
}
Finally I want to receive structure like below. I wonder if it is correct way? Maybe better option is just set text in fields instead of reference to class (after all realm is non-relational)?
how one can fetch a JSON file in the following format:
https://developers.themoviedb.org/3/people/get-popular-people
Alamofire is used to fetch the data from online database.
I don't know exactly how to format the JSON file received so the nested array can have the elements saved in an instance MovieModel(poster: UIImage,
name: String,
rating: Double,
year: String,
posterLink: String,
id: Int)
ERROR: Fatal error: NSArray element failed to match the Swift Array Element type
My code looks like:
class MovieModel {
private var _poster: UIImage!
private var _background: UIImage!
private var _name: String! // original_title
private var _overview: String! // overview
private var _rating: Double! // vote_average
private var _year: String!
private var _posterLink: String!
private var _backgroundLink: String!
private var _genres: [Int]!
private var _id: Int!
init(poster: UIImage,
name: String,
rating: Double,
year: String,
posterLink: String,
id: Int){
_poster = poster
_name = name
_rating = rating
_year = year
_posterLink = posterLink
_id = id
getPosterImage()
}
}
class ActorModel {
private var _poster : UIImage!
private var _birthday : String?
private var _known_for_department : String?
private var _deathday : String?
private var _id : Int!
private var _known_for : [MovieModel]?
private var _name : String!
private var _also_known_as : [String]!
private var _gender : Int!
private var _biography : String?
private var _popularity : Double?
private var _place_of_birth : String?
private var _profile_path : String?
private var _adult : Bool!
private var _imdb_id : String!
private var _homepage : String!
init(poster : UIImage, id : Int, known_for: [MovieModel], name: String, popularity : Double, profile_path : String) {
_poster = poster
_id = id
_known_for = known_for
_name = name
_popularity = popularity
_profile_path = profile_path
getPosterImage()
}
}
func getPopularActors(){
let url = BASE_URL + "/person/popular?" + API_KEY + LANG + "&page=1"
self.actorList = []
Alamofire.request(url).responseJSON {response in
if let result = response.result.value as? Dictionary<String,Any> {
if let list = result["results"] as? [Dictionary<String,Any>] {
for i in list {
self.actorList.append(ActorModel(
poster: UIImage(),
id: i["id"] as! Int,
known_for: i["known_for"] as! [MovieModel],
name: i["name"] as! String,
popularity: i["popularity"] as! Double,
profile_path: "\(self.IMAGE_URL)\(i["profile_path"] as! String)"
))
}
if let del = self.actorDelegate {
del.transferActors(data: self.actorList)
}
}
}
}
}
You should really use Decodable for this. But building on your current solution:
for i in list {
var movieModels = [MovieModel]()
if let knownForArray = i["_known_for"] as? [[String: Any]] {
for knownFor in knownForArray {
movieModels.append(MovieModel(
poster: UIImage(),
name: knownFor["name"] as! String,
rating: knownFor["rating"] as! Double,
... //And so on
))
}
}
self.actorList.append(ActorModel(
poster: UIImage(),
id: i["id"] as! Int,
known_for: movieModels,
name: i["name"] as! String,
popularity: i["popularity"] as! Double,
profile_path: "\(self.IMAGE_URL)\(i["profile_path"] as! String)"
))
}
I am trying to receive number of properties of Now Playing item.
Per Apple documentation:
Anytime the app accesses more than one property, enumerating over a set of property keys is more efficient than fetching each individual property.
So I tried to use their method:
func enumerateValues(forProperties properties: Set<String>,
using block: #escaping (String, Any, UnsafeMutablePointer<ObjCBool>) -> Void)
But I just cannot understand how it should be used.
My code:
//MARK: Properties
var allProperties: [String: Any]
var albumTitle: String?
var albumArtist: String?
var title: String?
var artist: String?
var artwork: UIImage?
var genre: String?
var lyrics: String?
var releaseDate: Date?
var playbackDuration: TimeInterval?
var rating: Int?
var assetURL: URL?
var isExplicitItem: Bool?
var isCloudItem: Bool?
var hasProtectedAsset: Bool?
let propertiesSet: Set<String> = [MPMediaItemPropertyAlbumTitle,
MPMediaItemPropertyAlbumArtist,
MPMediaItemPropertyTitle,
MPMediaItemPropertyArtist,
MPMediaItemPropertyArtwork,
MPMediaItemPropertyGenre,
MPMediaItemPropertyLyrics,
MPMediaItemPropertyReleaseDate,
MPMediaItemPropertyPlaybackDuration,
MPMediaItemPropertyRating,
MPMediaItemPropertyAssetURL,
MPMediaItemPropertyIsExplicit,
MPMediaItemPropertyIsCloudItem,
MPMediaItemPropertyHasProtectedAsset]
func getAllMetadata() {
allProperties = nowPlaying?.enumerateValues(forProperties: propertiesSet,
using: //No idea what to put here
-> [String: Any])
}
How to use it properly?
Finally I figured out how to use it. So I re-wrote my function as follows:
func getAllMetadata() {
var allProperties: [String: Any] = [:]
nowPlaying?.enumerateValues(forProperties: propertiesSet, using: {key,value,_ in allProperties[key] = value})
albumTitle = allProperties["albumTitle"] as? String
//and so on
}
This documentation helps me to understand the proper usage -
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html
class AreaSectorLineOverlay: MKPolyline {
var id: String!
var nickName: String!
var locationName: String!
convenience init(coordinates coords: UnsafePointer<CLLocationCoordinate2D>, count: Int, id: String, nickName: String, locationName: String) {
self.init(coordinates: coords, count: count)
self.id = id
self.nickName = nickName
self.locationName = locationName
}
}
Why the code is wrong? error is ('self' used before self.init call) and at last of the function 'init(coordinates coords: UnsafePointer, count: Int, id: String, nickName: String, locationName: String)' the error is (Self.init isn't called on all paths before returning from initializer)
class A {
var a1: String!
init() {
}
convenience init(a1: String) {
self.init()
self.a1 = a1
}
}
class B: A {
var b1: String!
convenience init(a1: String, b1: String) {
self.init(a1: a1)
self.b1 = b1
}
}
let b = B(a1: "a1Test", b1: "b1Test")
print(b.a1, b.b1)
There is no error like this,and print result is (a1Test b1Test)
I wanted to create custom PFObject class, but it gives me a very confusing error "Property self.photo not initialized at super.init call"
here is code of my custom class :
import Foundation
import Parse
class Wish: PFObject, PFSubclassing {
var id: String?
var name: String?
var descriptionWish: String?
var photo: UIImage
var photoThumbnail: UIImage
var amount: Double?
var amountDonated: Int?
static func parseClassName() -> String {
return "Wish"
}
override init() {
super.init()
}
convenience init(id: String?, name: String?, descriptionWish: String?, photo: UIImage, photoThumbnail: UIImage, amount: Double?, amountDonated: Int?) {
self.init()
self.id = id
self.name = name
self.descriptionWish = descriptionWish
self.photo = photo
self.photoThumbnail = photoThumbnail
self.amount = amount
self.amountDonated = amountDonated
}
}
Any ideas how to make a custom initializer for this class ?
I want to call my wish class like this:
Wish(id: "123", name: "xxx", descriptionWish: "Lorem ipsum", photo: photoImage, photoThumbnail: photoImageThumbnail, amount: 22.20, amountDonated: 10)
and cast PFObject like this
let wish = myPfObject as Wish
Any help is appreciated!!!
Try updating your subclass to the following. Notice the NSManaged keywords for the Parse properties you've added to your Wish subclass and the removal of super.init()
You will probably also want to look into replacing the UIImage properties with the Parse-provided PFFile properties. You can easily store and load images using PFImageView included in the ParseUI framework.
import Foundation
import Parse
class Wish: PFObject, PFSubclassing {
// MARK: - Parse Core Wish Properties
#NSManaged var id: String?
#NSManaged var name: String?
#NSManaged var descriptionWish: String?
#NSManaged var photo: UIImage
#NSManaged var photoThumbnail: UIImage
#NSManaged var amount: Double?
#NSManaged var amountDonated: Int?
// MARK: - Lifecycle
override class func initialize() {
struct Static {
static var onceToken : dispatch_once_t = 0;
}
dispatch_once(&Static.onceToken) {
self.registerSubclass()
}
}
static func parseClassName() -> String {
return "Wish"
}
convenience init(id: String?, name: String?, descriptionWish: String?, photo: UIImage, photoThumbnail: UIImage, amount: Double?, amountDonated: Int?) {
self.init()
self.id = id
self.name = name
self.descriptionWish = descriptionWish
self.photo = photo
self.photoThumbnail = photoThumbnail
self.amount = amount
self.amountDonated = amountDonated
}
}