I created an array of ImageViews in a Buttonclicked method:
UIImageView *arrayOfImageViews[10]
I successfully loaded them on the screen using a loop. (Big accomplishment for this beginner!)
But I want to refer to them in other methods (e.g. touchMove).
Where do I declare arrayOfImageViews to be both an array and a class of UIImageView so that I can use them in other methods? From what I can find, I'm to declare them in the .h and above Implementation in the .m. But I can't figure out the code and location to define the object as an array of UIImageViews in anything but the original function.
Try using a property. So in the .h file, you want to define the property something like this:
#interface MyClass: UIView {
NSArray *arrayOfImageViews;
}
#property (nonatomic,retain) NSArray *arrayOfImageViews;
Now in the implementation (.m file) You need to bind this property like this
#implementation MyClass
#synthesize arrayOfImageViews;
//now you need to initialize the array of images like this (look for the method viewDidLoad or //just add it)
- (void)viewDidLoad
{
NSMutableArray *tmpImages = [[NSMutableArray alloc]init];
//initialize images here
[self setArrayOfImageViews:tmpImages];
[tmpImages release];
[super viewDidLoad];
}
That should do it... Sorry I didn't have time to post code that actually compiles but it should help. Basically now you have a property on the class and you can access it like self.arrayOfImages, or even just arrayOfImages (from within MyClass). Also, I used NSArray which I suggest you do too. However you can also use UIImageView* arrayOfImages if you prefer.
Related
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).
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]
I'm new to iOS programming, I read a lot of tutorials and forums but I still can't figure the best way to manage a project.
What I want is the iPad screen to display a CollectionView and a TableView side by side.
Actions in the CollectionView should change TableView content. SplitViewController won't do the job because of the fixed size of the split.
For now I'm using Storyboard, I created a ViewController and added two ContainerViews in it. Each container is linked by an XCode generated segue to a view controller (LeftViewController and RightViewController).
I'm trying to figure the smartest way to manage actions on the LeftViewController and send changes to the RightViewController.
I would like to use Storyboard that seems more elegant, but I'm not sure how to implement this.
Assuming you know the way to establish delegate methods (#protocol, see here for links), the key elements will be grabbing the two viewControllers embedded in containers as they are being loaded, setting the primary viewController as delegate, and sending the messages when something changes. For starters, if communication needs to flow both ways between controllers, set up an instance variable for each VC.
Given VCPrime, CollectionVC, and TableVC:
First, in storyboards, name each of your segues (from the containerViews to the VCs). In VCPrime, implement prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"collection"]) {
self.collectionVC = (CollectionVC *)[segue destinationViewController];
self.collectionVC.delegate = self;
}
if ([segue.identifier isEqualToString:#"table"]) {
self.tableVC = (TableVC *)[segue destinationViewController];
self.tableVC.delegate = self;
}
}
You must also implement the delegate methods in VCPrime, and declare CollectionDelegate, TableDelegate, or however you named them.
In CollectionVC, when someone selects something (or whatever), check that the delegate responds to your delegate method, then send that message:
if ([self.delegate respondsToSelector:#selector(doSomething)]) [self.delegate doSomething];
Then alter TableVC in the method that is called.
This is just a quick rundown. The internets are alive with great code examples.
I think I might have an improvement in Swift (the answer is old but I was facing this problem a day ago). I re-implemented the above in Swift, but with a twist. Instead of setting the VCPrime as a delegate for for both CollectionVC and TableVC, I would make the TableVC a delegate of CollectionVC. That is because CollectionVC needs to control TableVC. In general we can call a "master VC" the one that controls and the "delegate VC" the one that is controlled. In order to make sure that both VC are actually instantiated when I set one as the delegate of the other, I use Swift optionals and optional bindings. Here is a sample of code" (note that the master needs to have a "delegate" property and you might want to declare the appropriate protocols):
import UIKit
class ContainerController: UIViewController {
private var masterViewController: myMasterViewController?
private var delegateViewController: myDelegateViewController?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "myMasterViewController" {
masterViewController = segue.destinationViewController as? myMasterViewController
} else if segue.identifier == "myDelegateViewController" {
delegateViewController = segue.destinationViewController as? myDelegateViewController
}
if let master = masterViewController, delegate = delegateViewController {
println("Master and delegate set")
master.delegate = delegate
}
}
}
I've been trying to subclass UICollectionReusableView in a non-storyboard iPad project. I've built a view in IB and hooked it up to my custom class, registered the class for reuse in the viewController where my collection view lives, and am calling it correctly in
UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
However, nothing shows up in my header areas in the UICollectionView. I think I need too init the view with coder, but am unsure how to do that correctly. I followed a couple of examples I found, but the header view still does not appear in my collection view.
- (id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
[[NSBundle mainBundle] loadNibNamed:#"CVHeaderView" owner:self options:nil];
[self addSubview:self.categoryNameLabel];
}
return self;
}
Can anyone point me in the right direction?
If you use a storyboard and select the header/footer checkmark initWithCoder: will be called.
If you do not use the storyboard (or do not click header/footer) but hook it up manually you have to register your custom classes and initWithFrame: will be called.
[self.collectionView registerClass:[GameCardCell class] forCellWithReuseIdentifier:#"GameCardCell"];
[self.collectionView registerClass:[PlayerHeaderView class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:#"PlayerHeaderView"];
[self.collectionView registerClass:[PlayerFooterView class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:#"PlayerFooterView"];
Note: Both will be called only once. If the view comes out of the cache prepareForReuse will be called.
In my case, initWithFrame: is called automatically when dequeueing it for the first time. Try to implement this method and see if it works.
after my last question, regarding accessing an array from a different class, I ran into an new problem, that's giving me a headache for three days now. Everytime I think I have the correct solution approach, I fail.
Well... I don't have many experience yet regarding Cocoa Programming. But maybe you are able to give me the missing hint.
Let me show you what approach I've chosen:
1) the declaration of an array in the class PortConnection.h/.m
#interface PortConnection : NSObject {
#private
NSMutableArray *baudArray;
}
#property (nonatomic, retain) NSMutableArray *baudArray;
and the synthesize in .m
#implementation PortConnection
#synthesize baudArray;
Next I decided to implement a method in the ViewController that should be in charge of filling the array with data I need for display. The name of the class is "PortTableViewController.h"
#import "PortConnection.h"
#interface PortTableViewController : NSObject <NSTableViewDataSource, NSComboBoxDataSource> {
#private
IBOutlet NSComboBox *baudSelection;
PortConnection *portConnection;
}
#property (assign) IBOutlet NSTableView *portTableView;
- (IBAction)fillBaudSelection:(id)sender;
#end
and the implementation of my method "fillBaudSelection".
- (IBAction)fillBaudSelection:(id)sender {
int baudCount = [portConnection.baudArray count];
int i;
for (i = 0; i <= baudCount; i++){
[baudSelection addItemWithObjectValue:[portConnection.baudArray objectAtIndex:i]];
}
}
Furthermore I implemented the delegate methods for the combobox.
- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(NSInteger)index{
return [portConnection.baudArray objectAtIndex:index];
}
- (NSInteger)numberOfItemsInComboBox:(NSComboBox *)aComboBox{
return [portConnection.baudArray count];
}
My questions are:
1) Do I need to use the Delegate Methods for a combo box at all?
2) the Combobox isn't filled with data at all, though the array is filled with data
3) Am I thinking to complicated??
Thanks so much for every hint I get from you!
best Regards
Sebastian
Are you sure you hooked the combobox correctly? make sure the delegate and the datasource are set to whatever class has the methods implemented.