Suppose I have the following struct inside a StorageService framework :
struct Post {
public let author: String
public let description: String
public let image: String
public let likes: Int
public let views: Int
}
So to access its fields from another module I mark all fields with public keyword - it's clear. But should I mark the name Post itself to be public :
public struct Post ...
I tried both ways but I see no differences (with public struct Post and struct Post).
What is the right way to follow here?
The access modifier of the type itself will control the accessibility of the type and hence making any properties more accessible than the type itself is useless, since you cannot access properties of a type that you don't know about.
In order to be able to use the Post type from outside your framework, you need to declare Post as public.
This makes the type itself and all of its properties accessible from outside your framework:
public struct Post {
public let author: String
public let description: String
public let image: String
public let likes: Int
public let views: Int
}
On the other hand, if you don't want to expose some specific properties/methods publicly, you can always use an accessibility modifier that is stricter than the type's modifier.
public struct Post {
public let author: String
public let image: String
public let likes: Int
let description: String // can only be accessed from inside the module
private let views: Int // can only be accessed from the Post type itself
}
Related
I am building a simple REST API for my blog using Golang. I store my posts in MongoDB, so, when I retrieve some record, I have to serialize (not sure if it's a right term) to native Golang type (struct). Since I have multiple endpoints with different return types, it seems like I have to have a bunch of similar types with difference in only one field. This needed when I perform $lookup operation, which is basically the analog of join operation in relational DBs.
I think the problem I meant will be clear from example:
type Post struct {
title string
author string
category string
}
type Author struct {
firstname string
lastname string
}
type Category struct {
name string
parent Category
}
type PostWithAuthor struct {
title string
author Author
category string
}
type PostWithCategory struct {
title string
author string
category Author
}
type PostWithAuthorAndCategory struct {
title string
author Author
category Category
}
func getPost() (Post) {
}
func getPostWithCategory() (PostWithCategory) {
}
func getPostWithAuthor() (PostWithAuthor) {
}
func getPostWithAuthorAndCategory() (PostWithAuthorAndCategory) {
}
You can use a struct inside another struct.
type Post struct {
Title string
Author Author
Category Category
}
type Author struct {
FirstName string
LastName string
}
type Category struct {
Name string
Parent *Category
}
// Query via `gorm`
var posts []Post
db.Where(&Post{Category: Category{Name: "food"}}).Find(&posts)
I need help with converting one object to another. Might have searched 10-20 website didn't find any good answer.
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
I did this:
let say I have value UniversityGroupChatItem in variable universityGroupChatItem and my universityGroupChatItem contains is not nil and contains value. I tried this it did not work.
universityJoinChatViewModel = (universityGroupChatItem) as! UniversityJoinChatViewModel
The app crashed.
Then I tried:
map and
compactmap
None worked.
I am not getting how to convert UniversityGroupChatItem struct to UniversityJoinChatViewModel struct.
I do not understand how to convert one struct to another struct both has same number name variables.
You can't force cast one object into another (no matter struct, class, enum ect.) even if they are fully the same inside
You need to implement inits where one object takes fields from another one.
map is function to sequences, if You have only 1 object just init it with another one
Examples:
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
let universityGroupChatItem = UniversityGroupChatItem(id: 0, name: "name")
let universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)
let groupArray = Array(repeating: universityGroupChatItem, count: 10)
let joinArray = groupArray.map(UniversityJoinChatViewModel.init(nameOfModel:))
In your case, you already have the constructor that can help you to achieve what you want, so instead of trying to cast the object, create a new one:
universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)
I am trying to define a wrapper around objects I want to store in Realm. The wrapper should contain an additional date object so that I can filter old objects. So far I have this
public final class RealmDateTaggedRealmObject: ObjectFacade {
#objc public dynamic var date: Date?
#objc public dynamic var value: ObjectFacade?
#objc private dynamic var id: String = ""
public override class func primaryKey() -> String? {
return #keyPath(id)
}
public convenience init<T: RealmMappable>(from object: RealmDateTagged<T>) {
self.init()
date = object.date
value = object.value.asRealmObject
id = object.primaryKey
}
}
The RealmMappable protocol enables transforming implementing entities into ObjectFacade. The ObjectFacade class is an empty class that inherits from Object, because I got an exception if I declared
#objc public dynamic var value: Object?
So I tried to be smart and created ObjectFacade. Turns out I'm not so smart cause it always stores nil. Also, value can't be a generic type because it is not supported in Objective-C.
Any suggestions?
Thanks!
I have generated classes for two core data entities. The first is called Address and is an abstract entity. The second is called Person, and it inherits from Address. I've added a few example managed attributes for the purpose of this test. And i've added a non-managed String property to the Person class. Accessing the string property of the Person class will crash. Why does this crash?
The Address and Person classes are automatically generated by Xcode, with the exception of the extra parameter: let foo = "Foo"
If i modify the code to make Person inherit from NSManagedObject directly instead of Address, then the code works and doesn't crash.
Automatically generated Address class:
#objc(Address)
public class Address: NSManagedObject {
}
extension Address {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Address> {
return NSFetchRequest<Address>(entityName: "Address")
}
#NSManaged public var street: String?
#NSManaged public var city: String?
}
Automatically generated person class with the exception of the "foo" parameter:
#objc(Person)
public class Person: Address {
public let foo = "Foo" //added this parameter
}
extension Person {
#nonobjc public class func fetchRequest() -> NSFetchRequest<Person> {
return NSFetchRequest<Person>(entityName: "Person")
}
#NSManaged public var name: String?
}
problem code
let person = Person(context: context)
print(person.foo) //doesn't crash, but prints empty line instead of value
print("VALUE:\(person.foo):") //crashes with Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)
UPDATE:
if foo is defined as
public let foo: String? = "Foo"
then the print statements don't crash, instead they interpret the value as 'nil' and print that.
So my question becomes: Why is this value which is assigned as a constant being reset to nil under the covers?
I have two hand-waving explanations why you are getting nil:
Managed objects don't function very well until they are inserted.
Your foo is a what I would call a constant stored property. I made up the name because, red flag, I cannot find any examples of it in the Swift book chapter on Properties
Put these two together and you get an edge case that doesn't work.
That being said, I'm kind of surprised that your foo setting does not work, because foo is not a managed property (that is, it is not in the data model). If I make such a constant stored property in a regular, non-managed object…
public class Animal {
public let foo: String! = "Foo"
}
it reads back later as expected.
So, if you can accept that this edge case just doesn't work in Core Data, you can move on to several more normal ways that do work.
One way is to declare foo as a var and assign a value to in awakeFromInsert() which is, as I alluded to earlier, after insertion. In Core Data, awakeFromInsert() is one of your friends…
#objc(Person)
public class Person: Address {
public var foo: String!
override public func awakeFromInsert() {
foo = "Foo"
}
}
Another way that works is as a computed property…
#objc(Person)
public class Person: Address {
public var foo : String { return "Foo" }
}
And, finally, the most logical way, since foo is constant for all instances, is to make it a type property…
#objc(Person)
public class Person: Address {
static var foo: String = "Foo"
}
but of course if you do this you must reference it as Person.foo instead of person.foo.
I have a sample code:
public struct MyOptions: OptionSet {
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
public static let one = MyOptions(rawValue: 1 << 0)
public static let two = MyOptions(rawValue: 1 << 1)
}
In other module I can do:
print(MyOptions.one)
print(MyOptions(rawValue: 10))
How can I do public struct with private constructor and public static properties(like a one, two) to limit manual creation?
You can't. When you conform a type to a protocol, all the required stubs' protection levels must be at least equal to the type's protection level. I'll try to explain why.
Let's say I have a type Foo that I conform to Hashable. I then assign an instance as a Hashable type:
let foo: Hashable = Foo()
Because the instance is of type Hashable, I am guaranteed to have access to the hash(into:) method. But what if I make the method private? At that point you end up with unexpected behavior. Either for some reason I can't access a method that I was guaranteed access to, or I have access to a method that I shouldn't be able to reach. It's a conflict of access levels.
So yeah, what you want to do isn't possible.