Swift: Cannot add element in Array from another object - arrays

I am struggeling with swift syntax . I want to add objects to an array but I have syntax errors.
The array is located in class Document, and the class that should add objects is in class Viewcontroller.
The array is of type Content:
public class Content: NSObject {
#objc var bankAccSender: String?
#objc var bankAccReceiver: String?
Declaration snippest in Document:
class Document: NSDocument {
var content=[Content]()
override init() {
super.init()
self.content = [Content]()
// force one data record to insert into content
content += [Content (… )] // checked with debugger
The ViewController has assigned the represented Object
contentVC.representedObject = content
But adding data in ViewController gives a compiler error „Type of expression is ambiguous without more context“:
var posting = Content(…)
self.representedObject.append(posting)
Hope you can help..

You can't append an element to an object of type Any. What you need is to replace the existing value with a new collection:
representedObject = (representedObject as? [Content] ?? []) + CollectionOfOne(posting)

representedObject is of type Any?, which is a very difficult type to work with in Swift. Since you already have a content property, I would probably adjust that, and then re-assign it to representedObject.
You can also try this (untested), as long as you are certain that the type is always [Content]:
(self.representedObject as! [Content]).append(posting)
It's possible you'll need some more complex like this:
(self.representedObject as! [Content]?)!.append(posting)
As I said, Any? is an incredibly obnoxious type. You probably want to wrap this up into a function. Or I you can avoid using representedObject, then I would recommend that. In many cases you don't need it. It's often just a convenience (in ObjC; in Swift, it's very hard to use).

Related

Filtering an array of objects by class not working

I have a UIStackView that contains UIViews or objects of a class I have created called MyView.
MyView is a subclass of UIView.
I want to extract from that array, all objects of class MyView.
This is what I have tried and the respective errors:
let views = Array< MyView >(allViews).filter { $0 is MyView }
type of expression is ambiguous without more context
I love these messages that say nothing.
let views = Array<Any>(allViews).filter { $0 is MyView }
I love how this compiles with Any.
No error in this case, but views contains the same objects as myViews, nothing is being filtered.
I understand that MyView is a subclass of UIView, so what swift is testing here is if the object is of class UIView. If this is true, why bothering allowing programmers to specify any class on the filter, if it can only filter some classes?
Is there a way to test for subclasses?
I'm guessing allViews is an array of UIView.
You should use compactMap, which will map to an array of the subclass, throwing away any nil values (which result from the as?):
let views = allViews.compactMap { $0 as? MyView }
Note here views is already of type [MyView]; take a look at compactMap's method signature to understand:
func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]

Why can't I add items to an array if it is inside a singleton class?

I have a singleton class which looks like this:
class DataAccess {
var teamUrl = NSArray()
}
let sharedData = DataAccess()
This is saved as a .swift file.
I am trying to add an item to that array from one of my view controllers. The code I am using to try and add the item to the array is this:
sharedData.teamUrl.append(teamUrl.text)
I am receiving an error message though. The error message is:
'NSArray' does not have member names 'append'
I know that it is something to do with my singleton because I created an array in the view controller and changed the code correspondingly and it worked.
I also tried to change the Singleton class to this:
class DataAccess {
var teamUrl = []
}
let sharedData = DataAccess()
I received the same error though.
I'm not sure why this isn't working. Please would somebody be able to explain where I have gone wrong?
Just to add, although I have referred to these as singletons, I'm not 100% sure that they are - its just the name they were referred to on a tutorial when I was learning about transferring data between different views.
Instead of var teamUrl = [], try var teamUrl: [String] = []. This will create a native Swift array, instead of an NSArray, and that has a .append method.

SWIFT - How to get the type of an Array?

i'm writing a generic method who take a Dictionary and a given type in parameters for build an object.
For example, if you make a SOAP request for get a movie and put away the response in Dictionary you can make:
var movie : Movie = myGenericMethod(dic : Dictionary, objectToIntrospect : Movie()) as Movie
It's work with:
Simple Object
Complex Object
But i have a problem if you have an array of object.
So imagine your movie object contains an Array of Actors...
With reflection, i get all type of my class's attributes.
With this, i build an Array of Any object which contains my types.
For example, an object contained in other object (Actor in a Movie):
//All type of attributes of my movie object, at index [i] i have my "Actor" object
var anyType : Any = typesOfProperties[i]
//I cast it in object
var objectType : NSObject = anyType as NSObject
//Dont worry about this method, it's just for get the dictionary
var otherDico : NSDictionary = ConverterUtilities.extractDictionaryFromOtherDictionary(dict, dicoName: property, soapAction: soapAction) as NSDictionary
//I build the Actor object with the data of the dictionary. objectType.self give the Actor type
var propertyObject: NSObject = self.buildAnyObjectWithDictionary(otherDico, soapAction: "", objectToIntrospect:objectType.self) as NSObject
//I set the property Actor in my Movie object (myObjectToReturn)... The "property" parameter is the key
ConverterUtilities.setPropertyValue(property, value: propertyObject, objectToReturn : myObjectToReturn, isObject : true)
It's work perfectly... If i have just one actor in my movie object, the "propertyObject" will be an Actor type, and this cause objectType is an Actor object.
But, if i have an array, i'm redirect in method who treat Array, and my objectType return "Swift._NSSwiftArrayImpl" and my anyType object return "([myproject.Actor])".
I dont need to know this is just an Array, cause i know it. But i need to know that's an Array of Actor for build some Actor object dynamicly !
This is what i have for the moment:
var objToAdd: NSObject = self.buildAnyObjectWithDictionary(newDic, soapAction: "", objectToIntrospect: Actor()) as NSObject
arraySpecific.append(objToAdd)
As you can see, this work perfectly if i hardcode the type. But i need to make it like the previous example ! Like that:
var objToAdd: NSObject = self.buildAnyObjectWithDictionary(newDic, soapAction: "", objectToIntrospect: anObjectWithActorType) as NSObject
arraySpecific.append(objToAdd)
(Difference between first and second version is the objectToIntrospect parameter)
Do you know how can i use my Any object (contains: ([myproject.Actor]) for build an instance of one Actor ?
I really need ur help for this ! Regards !
PS: sorry for my bad english, i hope u understand me :)
Ok guys, i come back on my post cause i found a solution:
i create a master class, and all of my classes herit of this class.
This super-class have a method name getArrayType.
If one of my children-class need to be used with my generic method and if she contain a Array, they need to override the getArrayType.
Like that:
override func getArrayType(anyType : Any) -> String {
var className = " "
if(anyType as? NSObject == rows){
className = Properties.PROJECT_NAME + ".SimpleRow"
}
return className
}
And i call this method like that (TObject is my super-class):
var className = (objectToIntrospect as TObject).getArrayType(anyType)
var obj: AnyClass! = NSClassFromString(className)
This work perfectly, but you need to override a method. I hope this help u if u got the same problem !

Save my own class as an array in Parse

I have a class named Pet. I collect it in an array. Then I try to save it like below code. I also tried inheriting NSObject to the Pet class with no use. Is it not possible to save my own class of arrays in Parse or am I doing something really wrong? Note that the current user exists and valid.
Somewhere in code defined:
var pets : [Pet] = [Pet]()
populated:
pets.append(newPet)
and tried to save:
#IBAction func saveTapped(sender: UIBarButtonItem) {
PFUser.currentUser().setObject(pets, forKey: "pets")
user.saveInBackgroundWithBlock({ (success, error) -> Void in
if error == nil {
DLog("Suceess saving")
} else {
displayAlertWithTitle(self, nil, error.description)
DLog(error)
}
})
}
The error I am getting is:
2015-02-17 18:28:59.906 Patikoy[38292:2121589] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Patikoy.Pet)'
p.s. I am a beginner in Swift as well as Parse. Any help is appreciated.
Parse is likely trying to serialize the "pets" array into JSON. However, your "Pet" class is not serializable to JSON.
From the NSJSONSerialization Class Reference:
An object that may be converted to JSON must have the following
properties:
The top level object is an NSArray or NSDictionary.
All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
All dictionary keys are instances of NSString.
Numbers are not NaN or infinity.
You need to create a method on your Pet class that converts it to a Dictionary, as described in this Stack Overflow answer.

Access one specific object from class name?

I want to access a specific object with the class name. This object may change, so it is not a singleton.
Like:
MyClass.actualView
or
MyClass.actualView()
Since I get class var are not yet supported as an error, any good short ways in your mind?
I used a global variable and a calculated type property. Only the constant type property are not supported yet.
private var globalVar: MyClass? = nil
class MyClass {
internal class var sharedInstance : MyClass {
get {
return globalVar
set {
globalVar = newValue
}
}
}
Before using it, it must be set from any of the instances:
MyClass.sharedInstance = self
Now I could set and get the type property like I could in every other language, until Apple makes it easier and supports constant type properties.
I can get the sharedInstance from anywhere inside the project (even accessible from Objective-C, when you add #objc before the internal-keyword
Swift:
MyClass.sharedInstance
Objective-C:
[MyClass sharedInstance];

Resources