I'm trying to write a simple app in Swift, backed with Realm. When I write vars within classes, I keep getting errors such as "Property cannot be implicitly #objc because its type cannot be represented in Objective-C". Sometimes these errors (which seem to involve Objective-C, which I'm not using) appear and sometimes they don't--See screenshots below.
I'm an admitted Newbie to Swift, but I thought I understood enough to get started. Specifically:
1) Should I add "#objc" before the class declaration?
2) Should I add "#objc" before the dynamic var declaration?
3) It seems that a Float var must be initialized, but not so for String?
4) Why does the compiler complain about a declaration on one line, but not about identical syntax in the next line?
Would sure appreciate some guidance, or pointers to specific instructions for creating Realm object classes!
I reckon the error comes from calling #objc instead of #objcMembers.
Try change
#objc class Transaction: Object
to
#objcMembers class Transaction: Object
And remove all #objc in front of your dynamic variables. So your final code should look like:
import Foundation
import RealmSwift
#objcMembers class Transaction: Object {
dynamic var picPath: String?
dynamic var transAmount: Float = 0.0
}
#objcMembers class Transaction: Object {
dynamic var currentBalance: Float = 0.0
dynamic var highWaterBalance: Float = 0.0
dynamic var acctName: String?
}
Our fellow Paul Hudson has described this attribute on his site hackingwithswift.
Related
I'm working on a KMM app. The shared module has a helper class, that relies on different native libraries for the android part and for the iOS part. This is implemented with the already know "expected/actual" pattern.
As said, the iOS actual class makes use of an iOS framework, that performs some calculations, and returns an array of objects. The ios framework that creates the list of objects works correctly (it was tested with unit tests). A simplified example follows below.
This is the class of the objects that are inside of the array:
public class ChildNodeIos: NSObject{
public let content:String
public let isTextNode:Bool
public init(content:String,isTextNode:Bool=false){
self.content=content
self.isTextNode=isTextNode
}
}
The helper class on the iOS side that returns the list of objects would be something like that:
#objc public class IOSCoolHelper: NSObject {
#objc public func getChildNodes(message: String) -> [ChildNodeIos] {
//build the array of child nodes here and return them
}
}
In the kotlin shared module, inside the iOS expected class, the function is called like the following:
#Serializable
data class ChildNodeKN(val content :String,val isTextNode :Boolean=false)
import com.mydomain.iosframeworks.IosCoolHelper
actual class CoolHelper actual constructor(private val someStuff: String) : ICoolHelper {
actual override fun getChildNodes(message: String): List<ChildNodeKN> {
val iosHelper= IOSCoolHelper()
val swiftarray:List<ChildNodeIos> = iosHelper.getChildNodes(message)
//I was expecting to do something like that but it does not work (the content of "array is always empty"):
val kotlinList:List<ChildNodeKN> = swiftarray as List<ChildNodeIos>
return kotlinList
}
}
}
Or maybe if the list of swift objects can not be direct be casted to the equivalent kotlin object list, I was expecting to be able to iterate over the swift list and convert it to the kotlin list, something like that:
val kotlinList=mutableListOf<ChildNodeKN>()
swiftArray.foreach{
kotlinList.add(ChildNodeKN(it.content,it.isTextNode))
}
But again, the content of the swift Array is empty. Doing a lot of tests (I can no reproduce them now), I managed to access something inside the array, but it was not an object of type ChildNodeIos, nor something I could read on the kotlin side.
Well, the question is, how to receive on the kotlin side, a list with more or less complex objects inside, that was generated on the iOS side?
I have to say, that this swift helper class has many other functions that return primitive values (strings, booleans, or int), and that is working very well.
I suppose a workaround would be instead an array with objects, to return an array with primitive types and two dimensions from the Swift side, but I would like to work with an array of objects if it is possible.
Thank you for your help
I managed to find the solution by myself. The problem was the declaration of the Swift class of the object contained in the list. I forgot the #objc declaration for the properties of the class, because if that I was not able to read the objects inside the returned array.
public class ChildNodeIos: NSObject{
#objc public let content:String
#objc public let isTextNode:Bool
public init(content:String,isTextNode:Bool=false){
self.content=content
self.isTextNode=isTextNode
}
}
And then, on the Kotlin side, I did not achieve to cast it directly to a list, but with a foreach loop it is very easy to write the iOS objects in Kotlin objects:
Xcode won't compile the creation of the dictionary, must i update anything or is there something that i am missing?
import Foundation
import UIKit
var dictionary: [String:Int]()
You have combined a type declaration (the colon) and a call to initializer (the empty parentheses after the type).
If you would like to keep the explicit type, you could do it like this:
var dictionary: [String:Int] = [String:Int]()
However, specifying the type is not necessary, because Swift figures out the type for you. This declaration is identical, but takes less space:
var dictionary = [String:Int]()
I have such class setup. In my methods I want to work with specific array depending on what parameter is passed. My question is : is "array" variable a copy of selected array or a reference to it? If it is a copy, how does one pass a reference to an array? I don't want to copy it becuase it is quite long.
I heard that in times of Swift 1 arrays were copied only when needed (compiler decides when). How things are now in Swift 2?
class ... {
private var currentVertexes = [CCVertex]()
private var mainVertexes : [CCVertex]!
private var leftVertexes : [CCVertex]!
private var rightVertexes : [CCVertex]!
private var topVertexes : [CCVertex]!
private var bottomVertexes : [CCVertex]!
...
internal func method(var factor: Float) {
let array = factor < 0.0 ? leftVertexes : rightVertexes
...
}
Depends on whether CCVertex is a struct or a class. If it's a struct it will be copied, not if it's a class.
From Apple's documentation (and with good examples too):
Copying an array also copies all of the elements of that array that are value types. This means that changing one of the elements of an array does not change the elements of any of the copies of the array
If the elements in an array are instances of classes, changing the class does affect other copies, because classes have reference semantics
Arrays are value types, but use copy-on-write to prevent unnecessary copies when you merely access them in a read-only fashion (see SwiftDocs)
So if the rest of your method only reads from the array, then you don't need to worry about copies (irrespective of whether CVVertex is a struct or a class).
Does Swift support reflection? e.g. is there something like valueForKeyPath: and setValue:forKeyPath: for Swift objects?
Actually does it even have a dynamic type system, something like obj.class in Objective-C?
Looks like there's the start of some reflection support:
class Fruit {
var name="Apple"
}
reflect(Fruit()).count // 1
reflect(Fruit())[0].0 // "name"
reflect(Fruit())[0].1.summary // "Apple"
From mchambers gist, here:
https://gist.github.com/mchambers/fb9da554898dae3e54f2
If a class extends NSObject, then all of Objective-C's introspection and dynamism works. This includes:
The ability to ask a class about its methods and properties, and to invoke methods or set properties.
The ability to exchange method implementations. (add functionality to all instances).
The ability to generate and assign a new sub-class on the fly. (add functionality to a given instance)
One shortcoming of this functionality is support for Swift optional value types. For example Int properties can be enumerated and modified but Int? properties cannot. Optional types can be enumerated partially using reflect/MirrorType, but still not modified.
If a class does not extend NSObject, then only the new, very limited (and in progress?) reflection works (see reflect/MirrorType), which adds limited ability to ask a instance about its class and properties, but none of the additional features above.
When not extending NSObject, or using the '#objc' directive, Swift defaults to static- and vtable-based dispatch. This is faster, however, in the absence of a virtual machine does not allow runtime method interception. This interception is a fundamental part of Cocoa and is required for the following types of features:
Cocoa's elegant property observers. (Property observers are baked right in to the Swift language).
Non-invasively applying cross-cutting concerns like logging, transaction management (i.e Aspect Oriented Programming).
Proxies, message forwarding, etc.
Therefore its recommended that clases in Cocoa/CocoaTouch applications implemented with Swift:
Extend from NSObject. The new class dialog in Xcode steers in this direction.
Where the overhead of of a dynamic dispatch leads to performance issues, then static dispatch can be used - in tight loops with calls to methods with very small bodies, for example.
Summary:
Swift can behave like C++, with fast static/vtable dispatch and limited reflection. This makes it suitable for lower level or performance intensive applications, but without the complexity, learning curve or risk of error associated with C++
While Swift is a compiled language, the messaging style of method invocation adds the introspection and dynamism found in modern languages like Ruby and Python, just like Objective-C, but without Objective-C's legacy syntax.
Reference data: Execution overhead for method invocations:
static : < 1.1ns
vtable : ~ 1.1ns
dynamic : ~4.9ns
(actual performance depends on hardware, but the ratios will remain similar).
Also, the dynamic attribute allows us to explicitly instruct Swift that a method should use dynamic dispatch, and will therefore support interception.
public dynamic func foobar() -> AnyObject {
}
The documentation speaks about a dynamic type system, mainly about
Type and dynamicType
See Metatype Type (in Language Reference)
Example:
var clazz = TestObject.self
var instance: TestObject = clazz()
var type = instance.dynamicType
println("Type: \(type)") //Unfortunately this prints only "Type: Metatype"
Now assuming TestObject extends NSObject
var clazz: NSObject.Type = TestObject.self
var instance : NSObject = clazz()
if let testObject = instance as? TestObject {
println("yes!") //prints "yes!"
}
Currently, there is no reflection implemented.
EDIT: I was apparently wrong, see stevex's answer. There is some simple readonly reflection for properties build in, probably to allow IDEs to inspect object contents.
No reflect keyword in Swift 5, now you can use
struct Person {
var name="name"
var age = 15
}
var me = Person()
var mirror = Mirror(reflecting: me)
for case let (label?, value) in mirror.children {
print (label, value)
}
It seems that a Swift reflection API is not a high priority for Apple at the moment. But besides #stevex answer there is another function in the standard library that helps.
As of beta 6 _stdlib_getTypeName gets the mangled type name of a variable. Paste this into an empty playground:
import Foundation
class PureSwiftClass {
}
var myvar0 = NSString() // Objective-C class
var myvar1 = PureSwiftClass()
var myvar2 = 42
var myvar3 = "Hans"
println( "TypeName0 = \(_stdlib_getTypeName(myvar0))")
println( "TypeName1 = \(_stdlib_getTypeName(myvar1))")
println( "TypeName2 = \(_stdlib_getTypeName(myvar2))")
println( "TypeName3 = \(_stdlib_getTypeName(myvar3))")
The output is:
TypeName0 = NSString
TypeName1 = _TtC13__lldb_expr_014PureSwiftClass
TypeName2 = _TtSi
TypeName3 = _TtSS
Ewan Swick's blog entry helps to decipher these strings:
e.g. _TtSi stands for Swift's internal Int type.
Mike Ash has a great blog entry covering the same topic.
You might want to consider using toString() instead. It is public and works just the same as _stdlib_getTypeName() with the difference that it also works on AnyClass, e.g. in a Playground enter
class MyClass {}
toString(MyClass.self) // evaluates to "__lldb_expr_49.MyClass"
The documentation only mentions nested types, but it's not clear if they can be used as namespaces. I haven't found any explicit mentioning of namespaces.
I would describe Swift's namespacing as aspirational; it's been given a lot of advertising that doesn't correspond to any meaningful reality on the ground.
For example, the WWDC videos state that if a framework you're importing has a class MyClass and your code has a class MyClass, those names do not conflict because "name mangling" gives them different internal names. In reality, however, they do conflict, in the sense that your own code's MyClass wins, and you can't specify "No no, I mean the MyClass in the framework" — saying TheFramework.MyClass doesn't work (the compiler knows what you mean, but it says it can't find such a class in the framework).
My experience is that Swift therefore is not namespaced in the slightest. In turning one of my apps from Objective-C to Swift, I created an embedded framework because it was so easy and cool to do. Importing the framework, however, imports all the Swift stuff in the framework - so presto, once again there is just one namespace and it's global. And there are no Swift headers so you can't hide any names.
EDIT: In seed 3, this feature is now starting to come online, in the following sense: if your main code contains MyClass and your framework MyFramework contains MyClass, the former overshadows the latter by default, but you can reach the one in the framework by using the syntax MyFramework.MyClass. Thus we do in fact have the rudiments of a distinct namespace!
EDIT 2: In seed 4, we now have access controls! Plus, in one of my apps I have an embedded framework and sure enough, everything was hidden by default and I had to expose all the bits of the public API explicitly. This is a big improvement.
Answered by SevenTenEleven in the Apple dev forum:
Namespaces are not per-file; they're per-target (based on the
"Product Module Name" build setting). So you'd end up with something
like this:
import FrameworkA
import FrameworkB
FrameworkA.foo()
All Swift declarations are considered to be part of
some module, so even when you say "NSLog" (yes, it still exists)
you're getting what Swift thinks of as "Foundation.NSLog".
Also Chris Lattner tweeted about namespacing.
Namespacing is implicit in Swift, all classes (etc) are implicitly
scoped by the module (Xcode target) they are in. no class prefixes
needed
Seems to be very different what I have been thinking.
While doing some experimentation with this I ended up creating these "namespaced" classes in their own files by extending the root "package". Not sure if this is against best practices or if it has any implications I'm mot aware of(?)
AppDelegate.swift
var n1 = PackageOne.Class(name: "Package 1 class")
var n2 = PackageTwo.Class(name: "Package 2 class")
println("Name 1: \(n1.name)")
println("Name 2: \(n2.name)")
PackageOne.swift
import Foundation
struct PackageOne {
}
PackageTwo.swift
import Foundation
struct PackageTwo {
}
PackageOneClass.swift
extension PackageOne {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
PackageTwoClass.swift
extension PackageTwo {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
Edit:
Just found out that creating "subpackages" in above code wont work if using separate files. Maybe someone can hint on why that would be the case?
Adding following files to the above:
PackageOneSubPackage.swift
import Foundation
extension PackageOne {
struct SubPackage {
}
}
PackageOneSubPackageClass.swift
extension PackageOne.SubPackage {
class Class {
var name: String
init(name:String) {
self.name = name
}
}
}
Its throwing a compiler error:
'SubPackage' is not a member type of 'PackageOne'
If I move the code from PackageOneSubPackageClass.swift to PackageOneSubPackage.swift it works. Anyone?
Edit 2:
Fiddling around with this still and found out (in Xcode 6.1 beta 2) that by defining the packages in one file they can be extended in separate files:
public struct Package {
public struct SubPackage {
public struct SubPackageOne {
}
public struct SubPackageTwo {
}
}
}
Here are my files in a gist:
https://gist.github.com/mikajauhonen/d4b3e517122ad6a132b8
I believe this is achieved using:
struct Foo
{
class Bar
{
}
}
Then it can be accessed using:
var dds = Foo.Bar();
Namespaces are useful when you need to define class with the same name as class in existing framework.
Suppose your app has MyApp name, and you need to declare your custom UICollectionViewController.
You don't need to prefix and subclass like this:
class MAUICollectionViewController: UICollectionViewController {}
Do it like this:
class UICollectionViewController {} //no error "invalid redeclaration o..."
Why?. Because what you've declared is declared in current module, which is your current target. And UICollectionViewController from UIKit is declared in UIKit module.
How to use it within current module?
var customController = UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
How to distinguish them from another module?
var customController = MyApp.UICollectionViewController() //your custom class
var uikitController = UIKit.UICollectionViewController() //class from UIKit
Swift uses modules much like in python (see here and here) and as #Kevin Sylvestre suggested you can also use the nested types as namespaces.
And to extend the answer from #Daniel A. White, in WWDC they were talking about the modules in swift.
Also here is explained:
Inferred types make code cleaner and less prone to mistakes, while
modules eliminate headers and provide namespaces.
You can use extension to use the mentioned structs approach for namespacing without having to indent all of your code towards the right. I've been toying with this a bit and I'm not sure I'd go as far as creating Controllers and Views namespaces like in the example below, but it does illustrate how far it can go:
Profiles.swift:
// Define the namespaces
struct Profiles {
struct Views {}
struct ViewControllers {}
}
Profiles/ViewControllers/Edit.swift
// Define your new class within its namespace
extension Profiles.ViewControllers {
class Edit: UIViewController {}
}
// Extend your new class to avoid the extra whitespace on the left
extension Profiles.ViewControllers.Edit {
override func viewDidLoad() {
// Do some stuff
}
}
Profiles/Views/Edit.swift
extension Profiles.Views {
class Edit: UIView {}
}
extension Profiles.Views.Edit {
override func drawRect(rect: CGRect) {
// Do some stuff
}
}
I haven't used this in an app since I haven't needed this level of separation yet but I think it's an interesting idea. This removes the need for even class suffixes such as the ubiquitous *ViewController suffix which is annoyingly long.
However, it doesn't shorten anything when it's referenced such as in method parameters like this:
class MyClass {
func doSomethingWith(viewController: Profiles.ViewControllers.Edit) {
// secret sauce
}
}
Even though it is possible to implement namespaces using Framework and Libraries but the best solution is to use local packages using Swift Package Manager. Besides having access modifiers, this approach has some other benefits. As in Swift Package Manager, the files are managed based on the directory system, not their target member ship, you won't have to struggle with merge conflicts that arise frequently in teamworks. Furthermore, there is no need to set file memberships.
To check how to use local Swift packages refer to the following link:
Organizing Your Code with Local Packages
In case anyone was curious, as of June 10th 2014, this is a known bug in Swift:
From SevenTenEleven
"Known bug, sorry! rdar://problem/17127940 Qualifying Swift types by their module name doesn't work."