I would like to create a smalltalk application with a class that has an instance variable that is an array and an instance variable that is the array's size. I would ideally like to initialise these when the object gets created but I have these manually being initialised in a method.
The following is my code:
Object subclass: Student [
| numTests marks |
initialize [
numTests := 0.
marks := Array new: 10.
]
]
student := Student new.
student initialize.
But I get the following error:
Object: Array new: 10 "<0x10b054b80>" error: method is responsibility of a subclass
How can I solve this problem?
You may not really want to do this. I generally use Squeak derivatives and Array new: works but is often not what you want because Arrays are fixed size (i.e. you can't add or remove elements) and so you typically use something like OrderedCollection instead. Also, you generally don't want to store the size in an ivar but rather send #size to your collection whenever you need to know how many elements it contains.
I've modified your code example based on the above suggestions (also notice that you don't need to send #initialize explicitly, it's done for you via #new:):
Object subclass: Student [
| marks |
initialize [
marks := OrderedCollection new: 10.
].
addMark: newMark [
marks add: newMark
].
removeMarkAt: markIdx [
marks removeAt: markIdx
].
size [
^ marks size
]
]
student := Student new.
If you really need to create a fixed size array, please update the question with which Smalltalk variant you are using so that someone with specific knowledge of the implementation can help. The problem you appear to be running into is that your Smalltalk implementation considers Array an abstract class and therefore you need to instantiate a subclass of it to get a fixed size array.
Related
I have solved the issue now, thanks for your help. I shouldn't have tried to save arrays with UITextViews, but I should have saved their text as strings instead. Here was the original question:
I have tried a lot, and googled a lot, but I can't solve this problem on my own. Whenever I try to save an array in userdefaults, it just is not working. I get the following error:
Thread 1: "Attempt to insert non-property list object (\n "<UITextView: 0x14001f800; frame = (0 0; 355 180); text = 'D'; clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600003f01d10>; layer = <CALayer: 0x6000031c83e0>; contentOffset: {0, 0}; contentSize: {355, 30}; adjustedContentInset: {0, 0, 0, 0}>"\n) for key content"
I don't know what a non-property list object is. And I do not know how to solve the problem. Below is the lines of code that do not work.
var contentList: [Any] = []
let cl = defaults.array(forKey: "content")!
if cl.count != 0{
contentList += cl
}
contentList.append(label)
defaults.setValue(contentList, forKey: "content")
If I take out the last line of code by turning it into a comment everything runs just fine. How should I replace that line of code? I essentially want to save an array of UITextViews and make it larger every time I call a fucntion (this code is part of a larger function). The reason why I have created another two lists (cl and contentList) is that it helps me with a problem down the line. What I cannot understand however, is why the last line of code doesn't work. If anyone has any ideas, please help me, it would be much appreciated.
Use only String as stated in comments :
var contentList: [String] = []
let cl = defaults.array(forKey: "content")!
if cl.count != 0{
contentList += cl
}
If lbText = label.text {
contentList.append(lbText)
defaults.setValue(contentList, forKey: "content")
}
You can only store a very limited list of data types into UserDefaults, commonly referred to as "property list objects" (Since property list (or plist) files will only store the same data types.
To quote the Xcode docs on UserDefaults, in the section titled "Storing Default Objects":
A default object must be a property list—that is, an instance of (or for collections, a combination of instances of) NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary [or Data, String, NSNumber, Date, Array, or Dictionary types in Swift.] If you want to store any other type of object, you should typically archive it to create an instance of Data.
(I added the equivalent Swift types to the above quote in square brackets, since it looks like Apple hasn't updated it for Swift.)
That's worded a little awkwardly. The idea is that you can only store data of the types listed. Because the Array and Dictionary types are "container" types, you can store any combination of arrays and dictionaries that contain combinations of any of the above types. For example, you can store an array that contains a dictionary, 3 dates, 2 floats, a Double, some Data, and 2 arrays, and those dictionaries and arrays can contain other dictionaries and/or arrays.)
It is almost always wrong to archive UIView objects like UITextViews. You should save the text properties of your text views instead.
If you want to manage a vertical stack of UITextView objects, I suggest adding a vertical stack view to your user interface, and then writing code that adds or removes UITextView subviews to your stack view. You should be able to find plenty of examples of adding and removing objects from stack views online. (It's really easy.)
If you want to manage a scrolling list of feeds of arbitrary length, you might want to use a table view or collection view instead. Those require that you set up a data model and implement a "data source". That takes a little practice to get right, but is very powerful.
Is there a way to remove a number from an attibute array in an update? For example, if I want to update all of an alchy's booze stashes if he runs out of a particular type of booze:
Alchy has_many :stashes
Stash.available_booze_types = [] (filled with booze.ids)
Booze is also a class
#booze.id = 7
if #booze.is_all_gone
#alchy.stashes.update(available_booze_types: "remove #booze.id")
end
update: #booze.id may or may not be present in the available_booze_types array
... so if #booze.id was in any of the Alchy.stash instances (in the available_booze_types attribute array), it would be removed.
I think you can do what you want in the following way:
if #booze.is_all_gone
#alchy.stashes.each do |stash|
stash.available_booze_types.delete(#booze.id)
end
end
However, it looks to me like there are better ways to do what you are trying to do. Rails gives you something like that array by using relations. Also, the data in the array will be lost if you reset the app (if as I understand available_booze_types is an attribute which is not stored in a database). If your application is correctly set up (an stash has many boozes), an scope like the following in Stash class seems to me like the correct approach:
scope :available_boozes, -> { joins(:boozes).where("number > ?", 0) }
You can use it in the following way:
#alchy.stashes.available_boozes
which would only return the ones that are available.
I have this array where I set the keys on the creation. Now in some point in my view I load some more information based on ids (the keys).
var colors = [
"37027" : UIColor(red:150/255, green:57/255, blue:103/255, alpha:1),
"12183" : UIColor(red:234/255, green:234/255, blue:55/255, alpha:1),
"44146" : UIColor(red:244/255, green:204/255, blue:204/255, alpha:1)
]
I want to add more colors to this array dynamically. How can I insert new items in the array setting the key? Something like
colors["25252"] = UIColor(red:244/255, green:204/255, blue:204/255, alpha:1)
The line above doesn't work, it is just to illustrate what I need.
Thanks for any help
Update: the code above is an example. Below the real code:
var placedBeacons : [BeaconStruct] = []
BeaconModel.fetchBeaconsFromSqlite(completionHandler: {
beacons in
for item in beacons{
self.placedBeacons["\(item.major):\(item.minor)"] = item
}
})
Error: Cannot subscript a value of type '[BeaconStruct]' with an index of type String
To match the key subscripting
self.placedBeacons["\(item.major):\(item.minor)"] = item
you have to declare placedBeacons as dictionary rather than an array
var placedBeacons = [String:BeaconStruct]()
It requires that item is of type BeaconStruct
The code you wrote, it should work. I have used such kind of code and was able to implement successfully. I just tested your code in my end and it's working for me. I declared colors variable globally in my class file and in view did load method added the second code to add another item in my colors array. After printing it out. My output shows full list of array with 4 items and the number of array count return 4 as well.
Please let me know, more details of your scenario so i can help you to figure it out the issue. but looks like it should work.
I want to create an array of JEditorPane depending on the size of a String array.
Is there a possibility to create an array of JEditorPane? If yes, how?
Here is an example:
String [] elements = {"0","1","2","3","4"};
JEditorPane ePane [] = new JEditorPane[5];
I want to to put each String element into the certain JEditPane, i.e
JEditorPane[0].setText(elements[0]);
etc. But I get a nullpointerexception when run I run.
Your problem is, that Java initializes a new array with the default value for the given type. In this case it is null, because the JEditorPane inherits from Object.
You cannot call a method on null - that is where the NullPointerException comes from.
The solution: make a loop in which you initialize the JEditorPane-objects in the array.
Then you can do JEditorPane[0].setText(elements[0]);
I'm learning Delphi Prism, and i don't find how to write the following code with it :
type
TRapportItem = record
Label : String;
Value : Int16;
AnomalieComment : String;
end;
type
TRapportCategorie = record
Label : String;
CategoriesItems : Array of TRapportItem;
end;
type
TRapportContent = record
Categories : array of TRapportCategorie;
end;
Then, somewhere, i try to put items in the array :
rapport.Categories[i].Label:=l.Item(i).InnerText;
But it doesn't work.. Can someone enlight me?
Thanks!
You didn't specify exactly what "didn't work". You should include the error in questions like this.
Arrays are reference types, and they start out with the value nil. They need to be initialized before elements can be accessed.
You can do this with the new operator:
rapport.Categories = new TRapportCategorie[10]; // 0..9
Arrays are quite a low-level type. Usually it's better to work with List<T> instead.
So you'd declare:
Categories: List<TRapportCategorie>;
But lists also need initializing, using the new operator. Also, modifying the return value of the indexer on a list containing a value type will be modifying a copy, not the original, which leads to the next point.
Records are usually not the best data type for representing data, as they are not reference types; it's very easy to end up modifying a copy of the data, rather than the original data. It's usually best to use classes instead, where you can put all the initialization code (such as allocating the array or list) in the constructor.