Objc - Extension - TableView Delegate - objective-c

I am trying to follow the Viper pattern in a small objc project. I get the different roles of each part with no particular issue.
However, the part I have an issue with is when I try to move the delegate/datasource of my tableview to another file, because I read that this is how it's supposed to be done.
I followed that post: iOS using VIPER with UITableView but I can't manage to compile.
This issue here is that I have no idea on how to make an extension in Objc. I tried a lot of syntaxes, but none of them worked.
How (by example) would I properly have in VIPER "MyViewController.m/h" & "MyTableViewController.m/h" where "MyTableViewController" is an extension of "MyViewController"?
Meaning that we would see <UITableViewDelegate> in "MyViewController.h".
Thanks a lot for your help. This is probably a redundant question but I didn't manage to find a clear answer, if any, to my extension issue.

Thanks to #Kamil.S in the comment above, I manage to find what I wanted in the apple documentation!
Indeed, extensions in Objc are called "Categories". I pretty much did what was written on the post I linked in my original question.
So here's a simplified example if anyone needs it:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#property (strong, nonatomic) id<ViewToPresenterProtocol> presenter;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
// All my code, ViewDidLoad, and so on
#end
CollectionViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface ViewController (CollectionViewController) <UICollectionViewDelegate, UICollectionViewDataSource>
#end
CollectionViewController.m
#import <UIKit/UIKit.h>
#import "CollectionViewController.h"
#import "ViewController.h"
#implementation ViewController (CollectionViewController)
- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.presenter getNumberOfItems];
}
// ...
// Here add others functions for CollectionView Delegate/Datasource protocols
#end

Related

Unit Testing in XCode (Obj C) With MVVM

I'm testing out some MVVM pattern stuff and seem to have gotten myself confused. Hoping someone here can clarify things for me.
So, what I did was set up a project and added a class that is a subclass of NSObject and called it RootViewModel.
Gave it one method:
- (void) rootTest {
NSLog(#"Booyeah!");
}
In ViewController I imported RootViewModel and made an IBOutlet for it.
#import "ViewController.h"
#import "RootViewModel.h"
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIButton *btnRunModel;
#property IBOutlet RootViewModel* myModel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.myModel rootTest];
}
#end
Then in Storyboard I dragged an Object into the ViewController scene, named it RootModel and connected it to the myModel property in ViewController.
Run the app and it works as expected, Booyeah gets logged.
So now here's where I got messed up. I wanted to set up a unit test. So working in the default unit test file I imported ViewController and made it a property and instantiated it in the set up.
#import <XCTest/XCTest.h>
#import "ViewController.h"
#interface ObjectiveVMMVTests : XCTestCase
#property (nonatomic, strong) ViewController* myViewController;
#end
#implementation ObjectiveVMMVTests
- (void)setUp {
[super setUp];
self.myViewController = [[ViewController alloc] init];
}
Then I tried to create a test where I call the rootTest method.
- (void) testRootModel {
[self.myViewController.myModel rootTest];
}
But I get a compiler error saying myViewController has no property myModel. I assumed it would be there, not sure where I messed this up.
In your unit test, you are saying:
#import "ViewController.h"
That's great. So now the unit test knows that this is a class. But that is not where the myModel property is declared. It is declared in ViewController.m, making this a private property.
Move the property declaration into ViewController.h to make it public so the unit test can see it.
Like #matt said, the IBOutlet is not part of the public interface of ViewController. It's private, hidden in the implementation (.m) file.
You have at least two viable options:
Add #property IBOutlet RootViewModel* myModel; to the ViewController.h file to make it part of the public interface;
Add an interface definition to the ObjectiveVMMVTests unit test file that'll satisfy the compiler:
#interface ViewController ()
#property IBOutlet RootViewModel* myModel;
#end
The implementation of the -(RootViewModel*)myModel getter is there anyway, the compiler just needs to know that ViewController does respond to the message. (You could use performSelector if you weren't interested in the returned object.)

Setting label stringValue of NSTextField using Objective-C, property IBOutlet NSTextField exist in separate class

To start off with I am very new, (about 2.5 weeks) to programming in Objective-C and even newer to writing code for OS X cocoa apps. I am attempting to set the value of a NSTextField label in AppDelegate.m whose IBOutlet property exists in another class. I'm attempting to place this in the - (void)applicationDidFinishLaunching:(NSNotification *)aNotification{} section of AppDelegate.m so that the value of the NSTextField is set before the MainMenu.xib file is loaded and displayed on screen. Here is the following code that I have so far:
AppDelegate.m:
#import "AppDelegate.h"
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
// Get Physical memory in MB
MemoryMonitoring *physicalMemoryObj = [[MemoryMonitoring alloc]init];
unsigned long long physicalMemoryValue = [physicalMemoryObj getPhysicalMemoryValue];
// Set the labels on the slider
RamdiskSize *sizeLabels = [[RamdiskSize alloc]init];
NSString *maxValue = [[NSString alloc] initWithFormat:#"%lluGB",(physicalMemoryValue / 1024)];
// This line is not doing what I had expected
[sizeLabels.textLabelSizeMax setStringValue:maxValue];
}
#end
MemoryMonitoring.h:
#import <Foundation/Foundation.h>
#interface MemoryMonitoring : NSObject
-(unsigned long long)getPhysicalMemoryValue;
#end
MemoryMonitoring.m:
#import "MemoryMonitoring.h"
#implementation MemoryMonitoring
-(unsigned long long)getPhysicalMemoryValue{
NSProcessInfo *pinfo = [NSProcessInfo processInfo];
return ([pinfo physicalMemory] /1024/1024);
}
#end
RamdiskSize.h:
#import <Foundation/Foundation.h>
#interface RamdiskSize : NSObject
#property (weak) IBOutlet NSTextField *textLabelSizeMax;
#end
RamdiskSize.m:
#import "RamdiskSize.h"
#import "MemoryMonitoring.h"
#implementation RamdiskSize
#synthesize textLabelSizeMax;
#end
As commented in my AppDelegate.m, the line in question is [sizeLabels.textLabelSizeMax setStringValue:maxValue];. My only other programming experience is from VBScript and as far as I can tell Objective-C uses dot syntaxing to access properties, so this line doesn't seem to be doing what I had expected it to do. If anyone could shed some light on how this is to be done properly, I would greatly appreciate the input.
There needs to be a UIViewController or a subclass of one involved. The textField must be part of a view hierarchy rooted with a view controller's view. Maybe start with a single view application template and add the text field to that view.
Then when that view controller sees viewWillAppear fire, it can ask the MemoryMonitoring class for the value and carry on setting it's own text field.
A good sign that you're on the right track is that you'll need to add virtually nothing to your app delegate code.

Duplicating Objective C files?

I'm working on my project in Xcode writing in Objective C & I like to know, is there a way to duplicate files? I keep looking it up on the internet & in my books, I can't fond anything. Whenever I try to #include, it doesn't seem to work.
This is what I have so far, this is the .h file.
#import <UIKit/UIKit.h>
#interface ViewController :UIViewController {
}
- (IBAction)link;
#end
#include <UIKit/UIKit.h>
#interface ViewController2 :UIViewController {
}
- (IBAction)link;
#end
This is the /m file which doesn't want to work.
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)link {
[[UIApplication sharedApplication]
openURL:[NSURL URLWithString:#"https://twitter.com/sexybeast914"]];
}
#end
#include "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)link {
[[UIApplication sharedApplication]
openURL:[NSURL URLWithString:#"https://twitter.com/sexybeast914"]];
}
#end
I always get the same to errors, "Cannot declare class extension for "ViewController", & "Reimplementation of class "ViewController"
If someone could help, it would be nice.
Thanks, :)
You are declaring the class ViewController twice. You can't have two classes of the same name.
I'm betting that second copy of ViewController was meant to be ViewController2 and you forgot to rename it in the file after copy/pasting the code from the first file?

Semantic Issue "Property implementation must have its declaration in interface" while following Apple’s “Your First Mac App” tutorial

I have been following Apple’s “Your First Mac App” tutorial with Xcode 4.4 (4F250).
After creating an outlet for the slider, I cannot compile the app any more. There is the semantic issue: “Property implementation must have its declaration in interface.”
Similar questions on Stack Overflow seemed to be caused by wrong or missing #property declarations. However I have double- and triple-checked with the tutorial. The declaration reads:
#property (weak) IBOutlet NSSlider *slider;
I would appreciate any help because I am totally stuck. I believe I have been following the tutorial to the letter and yet things go wrong. That’s not a good way to get started. :-/
In case it matters, here is the complete code of the header and the implementation.
AppDelegate.h
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (assign) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSSlider *slider;
- (IBAction)mute:(id)sender;
- (IBAction)takeFloatValueforVolumeFrom:(id)sender;
#end
AppDelegate.m
#import "AppDelegate.h"
#implementation AppDelegate
#synthesize slider;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
}
- (IBAction)mute:(id)sender {
}
- (IBAction)takeFloatValueforVolumeFrom:(id)sender {
}
#end
Your comment says to me that you have not properly linked the slider property with the xib file. You need to have a circle and not an exclamation point next to the properly. In my experience this usually causes a runtime error... so I am not 100% positive this will fix your compilation issue.
It seems that my problem was just some hiccup on the part of Xcode. Today, I did just the same things, and everything worked out.
Thanks to everybody who tried to help me.

Errors when making circular reference imports

My program was running fine, but I changed something and now it has over 48 errors.
I think I know the problem, but I don't know how to fix it. I created a class called mViewBase for all my UIViewControllers to derive from.
I decided to have a navigtion bar at the bottom of all my views, to go to other view controllers called cakes2. So cakes2.h imports mViewBase, and mViewBase import cakes2.h
You must be able to do this in Objective-C. Does anybody have any idea of what I can do?
My mViewBase.h file:
#import <UIKit/UIKit.h>
#import "Cakes2.h"
#interface mViewBase : UIViewController {
UIView *mBackground;
UIView *mBackArrow;
UITextView *mTitle;
// Cakes2 *mCakes;
}
-(void) aSetTitle: (NSString *) NewTitle;
-(IBAction) aBack: (id) tender;
-(IBAction) aHome: (id) sender;
-(IBAction) aCakes: (id) sender;
-(IBAction) aCall: (id) sender;
-(IBAction) aDirections: (id) sender;
#end
My Cakes2.h file:
#import <UIKit/UIKit.h>
#import "Gallery.h"
#import "WebView.h"
#import "mViewBase.h" // Circular reference! But I need it
#interface Cakes2 : mViewBase <UITableViewDelegate, UITableViewDataSource> {
// Gallery *mGallery;
IBOutlet UITableView *mMenu;
// WebView *mWebView;
}
-(IBAction) aOpenWeb;
#end
You can use a forward declaration in one of your header files to avoid the need to import the other header. For example, in mViewBase.h, you can say:
#class Cakes2;
Now the compiler knows that "Cakes2" refers to a class, and you don't need to import the entire Cakes2.h file.
I think you should perhaps consider using a UITabBarController. It is made specifically for managing several view controllers from a bar at the bottom of the screen.