i'm creating an Xcode app and i need to create an NSMutableArray that gets initialized when my switch are on and when a switch is off the value assigned to the switch that was also assigned to the NSMutableArray gets destroyed from the Array, how the code should be? I already initialized my switch but i don't know how to add/destroy the values from the NSMUtableArray
- (void)changeState:(id)sender
{
UICustomSwitch* currentSwitch = (UICustomSwitch*)sender;
if ([currentSwitch isOn]) {
[myMutableArray addObject:currentSwitch.myCustomValue];
} else {
[myMutableArray removeObject:currentSwitch.myCustomValue];
}
}
if you have to add new object in NSMutableArray
ringsArray.addObject(_ring)
if insert object within NSMutableArray
ringsArray.insertObject("Value", atIndex: position)
Same as work on remove value
ringsArray.removeObject("")
ringsArray.removeObjectAtIndex(position)
Related
Im trying to create an array from NSUserDefaults. The old app is in Obj C, I thought my userdefaults was of file type NSArray with the array containing a custom class called GD_Owed_HistoryObject.
I tried to decode this class and use it in the new app using Swift 3
#objc(GD_Owed_HistoryObject)
class UserDefaultHistory: NSObject, NSCoding {
let saveDate: String?
init(saveDate: String) {
self.saveDate = saveDate
}
required init(coder decoder: NSCoder) {
self.saveDate = (decoder.decodeObject(forKey: "owedSaveDate") as? String)
}
func encode(with coder: NSCoder) {
coder.encode(saveDate, forKey: "owedSaveDate")
}
}
I can get the count of my array, and it has the correct number of objects in it
print("\(statementHistory.count) is the array count") // 3
I also tried to figure out what kind of objects are in my array
print("\(type(of: statementHistory)) type of array") // UserDefaultStatement
UserDefaultStatement is what I assumed I was getting back from NSUserdefaults. So I tried to use this to create the array
import UIKit
#objc(GD_Owed_Bill)
class UserDefaultStatement: NSObject, NSCoding {
var statementHistory: [UserDefaultHistory]
init(statementHistory: UserDefaultHistory) {
self.statementHistory = [statementHistory]
}
required init(coder decoder: NSCoder) {
self.statementHistory = (decoder.decodeObject(forKey: "owedHistoryArray") as! Array)
}
func encode(with coder: NSCoder) {
coder.encode(statementHistory, forKey: "owedHistoryArray")
}
}
But when I try and access a property on UserDefaultHistory I get this error.
fatal error: NSArray element failed to match the Swift Array Element type
2017-03-01 11:58:37.411214 owed[1230:571980] fatal error: NSArray element failed to match the Swift Array Element type
I've been working on this for 2 days with not allot of progress. I think I'm assigning the array type incorrectly, but I don't know how to ask what kind of object am I getting back from my decoding.
Update
After spending some time with the old app it appears that I NSKeyArchived the objects, judging by what I needed to do to use them.
historyArray = [NSArray arrayWithArray:billDetails.historyArray];
NSLog(#"This is the array count for the history log %lu", (unsigned long)historyArray.count);
// check to see if there is history
[self checkHistory];
// un archive the history array objects
for (NSData *historyData in historyArray)
{
// set a instance of the person class to each NSData object found in the temp array
GD_Owed_HistoryObject *historyObject = [[GD_Owed_HistoryObject alloc] init];
historyObject = [NSKeyedUnarchiver unarchiveObjectWithData:historyData];
NSLog(#"This is the history object %#", historyObject);
NSLog(#"This is the save date %#", historyObject.saveDate);
NSLog(#"This is the total before %#", historyObject.beforeTotal);
NSLog(#"This is the total after %#", historyObject.afterTotal);
NSLog(#"This is the amount changed %#", historyObject.amountChanged);
//[decodedHistoryArray addObject: historyObject];
[decodedHistoryArray insertObject:historyObject atIndex:0];
}
I'm just now exactly sure how to take my array with the archived objects in it and unarchive them. statementHistory would be my array with the archived items
Update
var historyArray = statementHistory
let restoredStatement = NSKeyedUnarchiver.unarchiveObject(with: historyArray) as! UserDefaultHistory
restoredStatement.statementHistory[0].saveDate
But I get this error:
Cannot convert value ot type '[UserDefaultHistory]' ot expected argument type 'Data'
The code in the question works basically. The error must be somewhere else.
I tested this code in a Playground, maybe it's a hint how to use the archiver/unarchiver:
let defaultHistory = UserDefaultHistory(saveDate: "2017/3/1")
let statement = UserDefaultStatement(statementHistory: defaultHistory)
// archive the class to Data
let data = NSKeyedArchiver.archivedData(withRootObject: statement)
print(data as NSData) // the type cast prints the raw data rather than "xy bytes"
// unarchive the data to class
let restoredStatement = NSKeyedUnarchiver.unarchiveObject(with: data) as! UserDefaultStatement
restoredStatement.statementHistory[0].saveDate // "2017/3/1"
PS: As mentioned in your previous question you are going to archive [UserDefaultHistory] so you definitely get [UserDefaultHistory] back (decodeObject(forKey: "owedHistoryArray") as! [UserDefaultHistory])). And you will have always a non-optional string in UserDefaultHistory. No need at all to use an optional.
I've seen some examples in Objective-C such as this one, but NSCollectionView.subview uses a property called .indexOfObject which I am assuming has been replaced with .indexOf, but I'm not sure how to use .indexOf.
Context in Objective-C
NSInteger index = [[myCollectionView subviews] indexOfObject:self];
Swift Version
var index = collectionView.subviews.indexOf(element: Self.Generator.Element)
Question:
How do I use indexOf to get the index of a selected NSCollectionView?
The usage of indexOf is straightforward:
let label = UILabel()
let tableView = UITableView()
let subviews: [UIView] = [label, tableView]
print(subviews.indexOf(label)) // Optional(0)
print(subviews.indexOf(tableView)) // Optional(1)
As you can see, it returns an optional which will be nil if the object is not found in the array. You can unwrap the actual index like this
if let index = collectionView.subviews.indexOf(self) {
// do your stuff
} else {
// view not found in subviews
}
var query = new Parse.Query("Order");
query.equalTo("objectId", orederId);
query.include("price");
...
query.include("keyName");
Is it possible in Parse to include all existing object's keys in single query if we don't know keys names?
Assume that object was created dynamically and there is no info about it's keys names, but we need to get this object with all included pointers.
Create a subclass for your object and override the query method like this. Put all includeKeys where the comment says. Use the class method initObject to create and initialize your objects.
#implementation MyPFObject
#dynamic objectUUID;
// Other fields
+ (MyPFObject*) initObject
{
MyPFObject* obj = [self object];
[obj tlObjectInit];
// Other initializations
return obj;
}
+ (NSString*) parseClassName
{
return #"MyPFObject";
}
+ (PFQuery*) query
{
PFQuery* query = [PFQuery queryWithClassName: [self parseClassName]];
// Add includeKeys here
return query;
}
#end
I have an NSTextField bound to a key in the user defaults. When I press enter or leave the field the bound value is properly updated (I have an observer for it). However when I programmatically set the value of the text field the bound value is not updated. The text field however shows the new string I set with:
stockField1.stringValue = [sender representedObject];
(it's set from a menu item handler). Is it necessary to send an additional message to the text field or how else can I make this work?
Manually triggering key-value binding goes like this:
- (void)symbolSelected: (id)sender
{
NSTextField *field;
switch ([sender tag]) {
case 0:
field = stockField1;
break;
case 1:
field = stockField2;
break;
case 2:
field = stockField3;
break;
}
field.stringValue = [sender representedObject];
NSDictionary *bindingInfo = [field infoForBinding: NSValueBinding];
[[bindingInfo valueForKey: NSObservedObjectKey] setValue: field.stringValue
forKeyPath: [bindingInfo valueForKey: NSObservedKeyPathKey]];
}
Here's the Swift version of Mike's answer, for reference:
guard
let bindingInfo = self.infoForBinding(NSBindingName.value),
let observedObject = bindingInfo[NSBindingInfoKey.observedObject] as? NSObject,
let observedKeyPath = bindingInfo[NSBindingInfoKey.observedKeyPath] as? String else {
return
}
observedObject.setValue(self.stringValue, forKeyPath: observedKeyPath)
What is an easy way to set up my NSTableView with multiple columns to only display certain data in one column. I have the IBOutlets set up, but I don't know where to go from there.
Assuming you're not using Cocoa Bindings/Core Data, you can display data in an NSTableView by implementing two methods from the NSTableViewDataSource protocol. Typically your controller will implement the protocol, so open the controller .m file and add these methods to the controller's #implementation:
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
return 25; // fill this out
}
– (id) tableView:(NSTableView*)tableView
objectValueForTableColumn:(NSTableColumn*)column
row:(int)row {
return row % 3 ? #"Tick..." : #"BOOM!"; // fill this out
}
You need to set the table's dataSource property to the controller. In Interface Builder control-drag from the table view to the controller and set dataSource. Now build and run and you should see your data in the table.
If you only want to fill out one column, add an IBOutlet NSTableColumn* to your controller; let's call it explosiveColumn. In Interface Builder, control-drag from the controller to the column you want to fill in and set explosiveColumn. Then, in tableView:objectValueForTableColumn:row: you can test if the column parameter is the same object as the one that the outlet is set to:
– (id) tableView:(NSTableView*)tableView
objectValueForTableColumn:(NSTableColumn*)column
row:(int)row {
if (column == explosiveColumn) {
return row % 3 ? #"Tick..." : #"BOOM!";
} else {
// other columns blank for now
return nil;
}
}
This tutorial might be useful: http://www.cocoadev.com/index.pl?NSTableViewTutorial
Here's an example using multiple table views with data source methods and a document based application:
#pragma mark - Data Source Methods
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tv
{
if (tv == racerTableView)
return [racerList count];
else if (tv == vehicleTableView)
return [vehicleList count];
else
return 0; // something wrong here...
}
- (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)col
row:(NSInteger)rowi
{
NSString *colid = [col identifier];
if (tv == racerTableView){
NHRacers *racer = [racerList objectAtIndex:rowi];
return [racer valueForKey:colid];
}
else if (tv == vehicleTableView){
NHVehicles *vehicle = [vehicleList objectAtIndex:rowi];
return [vehicle valueForKey:colid];
}
else
return 0; // something wrong here...
}
- (void)tableView:(NSTableView *)tv setObjectValue:(id)obj forTableColumn:(NSTableColumn *)col row:(NSInteger)rowi
{
NSString *colid = [col identifier];
if (tv == racerTableView) {
NHRacers *racer = [racerList objectAtIndex:rowi];
[racer setValue:obj forKey:colid];
}
else if (tv == vehicleTableView){
NHVehicles *vehicle = [vehicleList objectAtIndex:rowi];
[vehicle setValue:obj forKey:colid];
}
else
nil; // something wrong here...
[self updateChangeCount:NSChangeDone];
}
The tableview datasource outlets are set to the File's Owner and the File's Owner has set vehicleTableView and racerTableView to their respective "Table View" in the IB. The colid key checks the identifier (set in IB by selecting the table view column under the "Identity" drop down, while the "Identity Inspector" is shown). These values were chosen to be the KVC (key coding compliant) properties of the classes being displayed in the table views: use lower case first letter (see apple docs for rest).
For example:
(in NHVehicles.h)
#interface NHVehicles : NSObject
{
NSUInteger entry;
NSString *name;
NSString *vehicleClass;
}
#property NSUInteger entry;
#property NSString *name, *vehicleClass;
#end
(in NHVehicles.m)
#implementation NHVehicles
#synthesize entry, name, vehicleClass;
#end
for this tableView, "entry", "name" and "vehicleClass" would be typed (w/o ") into the identifier fields for their respective columns.
If you don't want to show some data in the class, simply do not enter the key for the column identifier. A word of caution: I am using Xcode 4.5.1 and I noticed that once I had entered a few keys for a particular column identifiers and then changed my mind about and attempted to clear the text, it complained when I deleted the text from the identifier field (I could no longer leave the field blank for the columns that I had edited). This was not difficult to work around, but it was a surprise.