Writing a simple app in Xcode 6 in Swift.
class htmlViewController : UIViewController
{
#IBOutlet var webbb: UIWebView
}
class ViewController: UIViewController
{
override func viewDidLoad()
{
let url = NSURL(string: "http://apple.com")
let reqq = NSURLRequest(URL: url)
self.webbb.loadView(reqq)
super.viewDidLoad()
}
}
Have some error on line "self.webbb.loadView(reqq)":
ViewController does not have a member named WebView.
Any ideas?
P.S. Sorry for noob question! :-)
for load a web page in a UIWebView just use this code :
#IBOutlet var web1 : UIWebView
override func viewDidLoad() {
super.viewDidLoad()
var url = NSURL(string: "http://www.google.com")
var request = NSURLRequest(URL: url)
web1.loadRequest(request)
}
and if you want to load a page from main bundle use this code :
#IBOutlet var web1 : UIWebView
override func viewDidLoad() {
super.viewDidLoad()
var url = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("pageName", ofType: "html"))
//var url = NSURL(string: "http://www.google.com")
var request = NSURLRequest(URL: url)
web1.loadRequest(request)
}
You defined webbb in a class called htmlViewController but you're adding functionality to another subclass called ViewController.
The problem you are having is that the ViewController class has no access to the webbb variable. There are a few solutions for this problem.
Solution 1:
When you define the ViewController class make the Superclass htmlViewController. That would look like this:
class ViewController: htmlViewController{...}
This means that the ViewController class will inherit from the htmlViewController class. This allows you to access variables and functions from the htmlViewController class. You can read more about inheritance and swift in this document.
Solution 2:
Why not bring the webbb variable into the ViewController class? I would recommend doing this if you do not plan on using the htmlViewController class anywhere else. Here is an example
class ViewController: htmlViewController{
#IBOutlet var webbb: UIWebView
//Do everything else.
}
You also need to add a ! after UIWebView when you are defining it.
Related
I'm having trouble wrapping my head around how to use Combine in SwiftUI. I'm accustomed to using key-value observation in AppKit an UIKit because view controllers don't need to know about each other and can just react to some global objects that help determine state.
For example, in an AppKit/UIKit app, I would create a global state object like this:
//Global State file
#objc class AppState: NSObject {
#objc dynamic var project: Project?
}
//Create an instance I can access anywhere in my app
let app = AppState()
Then in a view controller, I can get notified of any changes to my app-wide project instance and react accordingly:
//View Controller
class MyViewController: NSViewController{
var observerProject: NSKeyValueObservation?
override func viewDidLoad() {
observerProject = app.observe(\.project) { object, change in
self.refreshData()
}
}
func refreshData(){
//Query my persistent store and update my UI
}
}
What is the Combine/SwiftUI analog to this?
Do I need to create a Publisher and then listen to my global object changes? If so, how do I make my Core Data #FetchRequest (whose predicate includes my global Project object) respond in real-time?
I've done things the old way for so long that this transition to SwiftUI/Combine is rather confusing to me. 🙂
#FetchRequest doesn't work well with a dynamic predicate (There are some workarounds in SO) you will have to use the "old school" NSFetchedResultsController for that and put it into an ObservableObject. Here is a video with a sample. It is a lot of setup and code.
import SwiftUI
import Combine
class AppState: ObservableObject {
static let shared = AppState()
#Published var project: String?
//Just to mimic updates
var count = 0
private init() {
//Mimic getting updates to project
Timer.scheduledTimer(withTimeInterval: 2, repeats: true){ timer in
print("Timer")
self.project = self.count.description
self.count += 1
if self.count >= 15{
timer.invalidate()
}
}
}
}
class MyViewModel: ObservableObject{
#Published var refreshedData: String = "init"
let appState: AppState = AppState.shared
var projectCancellable: AnyCancellable?
init() {
projectCancellable = appState.$project.sink(receiveValue: {
value in
print(value ?? "nil")
self.refreshData()
})
}
func refreshData() {
refreshedData = Int.random(in: 0...100).description
}
}
struct MyView: View {
#StateObject var vm: MyViewModel = MyViewModel()
var body: some View {
VStack{
Text(vm.refreshedData)
}
}
}
struct MyView_Previews: PreviewProvider {
static var previews: some View {
MyView()
}
}
I'm new to Swift and I'm trying to learn how to use Core Data. But I'm getting this error and I'm not sure what I've done wrong. I've searched online and tried a few things but I can't get it right.
Failed to call designated initializer on NSManagedObject class 'FirstCoreData.Course'
When this line executes:
ncvc.currentCourse = newCourse
In this function:
class TableViewController: UITableViewController, AddCourseViewControllerDelegate {
var managedObjectContext = NSManagedObjectContext.init(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "addCourse" {
let ncvc = segue.destinationViewController as! NewCourseViewController
ncvc.delegate = self
let newCourse = NSEntityDescription.insertNewObjectForEntityForName("Course", inManagedObjectContext: self.managedObjectContext) as! Course
ncvc.currentCourse = newCourse
}
}
Class generated by "Create NSManagedObject Subclass..." for Course entity:
import Foundation
import CoreData
class Course: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
}
And:
import Foundation
import CoreData
extension Course {
#NSManaged var title: String?
#NSManaged var author: String?
#NSManaged var releaseDate: NSDate?
}
The problem lies not in the code in your question, but in the snippet you included as comments to the other answer:
var currentCourse = Course()
This doesn't just declare currentCourse to be of type Course, it also creates an instance of the Course entity using the standard init method. This is expressly not allowed: You must use the designated initialiser: init(entity entity: NSEntityDescription,
insertIntoManagedObjectContext context: NSManagedObjectContext?). This is described in the Apple Documentation here.
I suspect you do not ever use the instance created by the above var definition, so just define it as being of type Course?:
var currentCourse : Course?
Since it is optional, you do not need to set an initial value, though you will need to unwrap the value whenever it is used.
The simplest way is this:
Define in the applicationDelegate a reference for the context
Instantiate the variable by passing the context
In the AppDelegate (outside the brackets):
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
And in the code:
let currentCourse = Course(context:context)
Now you have your entity created. But don't forget to save with:
appDelegate.saveContext()
I had the same issue. And instantiating the object like this worked, for your course it would be something like this:
var currentCourse = Course.init(entity: NSEntityDescription.entityForName("Course", inManagedObjectContext:mox)!, insertIntoManagedObjectContext: mox)
instead of:
var currentCourse = Course()
I used this in Xcode 8.3.2 with Swift 3.1.
NSEntityDescription.insertNewObject(forEntityName: String(describing: type(of: Record())), into: managedObjectContext) as! Record
And got the same error message. But this data was inserted into db. So maybe this doesn't matter.
Your currentCourse should be NSManagedObject class
Please refer this CoreData: error: Failed to call designated initializer on NSManagedObject class
When accessing to outlets from my CustomClass : UICollectionViewCell, they are appearing as not initialized and can not set a proper value.
Every example I've seen it uses a plain Class (no XIB) to set the UI.
[Register("CustomCommentCell")]
public partial class CustomCommentCell : UICollectionViewCell
{
public static readonly NSString Identifier = new NSString("CustomCommentCell");
public CustomCommentCell () : base()
{
}
public CustomCommentCell (IntPtr handle) : base (handle)
{
}
public void updateData()
{
this.lblComment.Text = "Test";
}
}
On the other hand, I have registered the Class:
this.tableComments.RegisterClassForCell (typeof(CustomCommentCell),commentCellId);
and have the GetCell properly set.
However, when trying to set the outlets to a specific value, it indicates it is null. (this.lblcomment = null) while it should have been a UILabel initialized.
Any clues?
to create the Custom CollectionViewCell using XIB. do the following
1) create C# class which inherits from UIcollectionViewCell
[Register("MyCustomCell")]
public class MyCustomCell : UICollectionViewCell
{
public static readonly NSString Key = new NSString ("MyCustomCell");
[Export ("initWithFrame:")]
public MyCustomCell(CoreGraphics.CGRect frame) : base (frame)
{
}
public override UIView ContentView {
get {
var arr= NSBundle.MainBundle.LoadNib ("MyCustomCell", this, null);
UIView view =arr.GetItem<UIView> (0);
view.Frame = base.ContentView.Frame;
base.ContentView.AddSubview (view);
return base.ContentView;
}
}
}
2) Add a IphoneView XIB file has the Same Name as that of Class created in step 1
3) Open XIB in XCODE and do the Following Changes
3.1)Select the FileOwner set the Class same name as Step 1
3.2)Select The View Set the Class name UIView
4) Design Your XIB Accordingly
I can't follow quite the problem you are seeing. What is a "Custom XIB outlet"? Why is this question tagged "custom-controls"? Is there some example code or pictures you can show to help explain the problem?
The approach I use for UICollectionViewCell's is the same as I use for UITableViewCell - see the tutorial - http://slodge.blogspot.co.uk/2013/01/uitableviewcell-using-xib-editor.html
Update: From the code you've posted as a comment (not sure if it's complete or not), I think it would be useful for you to follow through that tutorial. There are a few steps to complete including registering the custom class name and including using RegisterNibForCellReuse - one of those will probably fix this for you.
From the documentation of a bound API I'm using:
overrideClassNames
Use this to use specific subclasses instead of the default PSPDF*
classes. e.g. add an entry of [PSPDFAnnotationParser class] /
[MyCustomAnnotationParser class] as key/value pair to use the custom
subclass. (MyCustomAnnotationParser must be a subclass of
PSPDFAnnotationParser) Throws an exception if the overriding class is
not a subclass of the overridden class. Note: does not get serialized
when saved to disk.
#property (nonatomic, strong) NSDictionary *overrideClassNames
Here's what I tried but doesn't work. Appearently not strings are required but actual types or something. How can I use this in MonoTouch?
var oClassDic = new NSMutableDictionary();
oClassDic.Add(new NSString("[PSPDFAnnotationParser class]"), new NSString("[PSPDFKitAnnotationParser class]"));
oDoc.OverrideClassNames = oClassDic;
The PSPDFKitAnnotationParser I created like this:
[Register("PSPDFKitAnnotationParser")]
public class PSPDFKitAnnotationParser : PSPDFAnnotationParser
{
public PSPDFKitAnnotationParser () : base()
{
}
public PSPDFKitAnnotationParser (PSPDFDocumentProvider provider) : base(provider)
{
}
public PSPDFKitAnnotationParser (IntPtr handle) : base(handle)
{
}
public PSPDFKitAnnotationParser (NSObjectFlag t) : base(t)
{
}
public PSPDFKitAnnotationParser (NSCoder coder) : base(coder)
{
}
MonoTouch's own bindings generally hides the class and replace them with, the more .NETy, System.Type.
However the MonoTouch.ObjCRuntime.Class type exists and can also be used. If the native code expects class instances then you should be able to do something like:
var oClassDic = new NSMutableDictionary();
oClassDic.Add(new Class("PSPDFAnnotationParser"), new Class("PSPDFKitAnnotationParser"));
oDoc.OverrideClassNames = oClassDic;
You might have to tweak this a bit since a Class instance is not an NSObject, it's a NativeObject in MonoTouch, so you might have to go one level deeper and use the Handle properties (IntPtr) when adding values/keys to your dictionary.
Following #poupou answer this might work, I have not tested it this is what you have to do, It Works (TM)
var oClassDic = new NSMutableDictionary();
var key = new Class("PSPDFAnnotationParser");
var val = new Class("PSPDFKitAnnotationParser");
IntPtr selSetObjectForKey = Selector.GetHandle ("setObject:forKey:");
Messaging.void_objc_msgSend_IntPtr_IntPtr (oClassDic.Handle, selSetObjectForKey, val.Handle, key.Handle);
oDoc.OverrideClassNames = oClassDic;
Selector setObject: forKey: expects an ObjC id type on both params
"id" its just a special type that can hold a pointer to any object you can construct with ObjC
So this should work :)
Hope this helps
Alex
I have subclassed a ViewController that was created via XCode Interface Builder. my subclass is defined like so
public MyViewControllerGeneric<T> : MyViewController{
public MyViewControllerGeneric(IntPtr handle) : base(handle){}
}
I can use Storyboard.InstantiateViewController("MyViewController") to get an instance of MyViewController. However how do I create an instance of MyViewControllerGeneric and pass a handle to it?
Tried
var vc = new MyViewControllerGeneric<MyType>(this.Handle)
var vc = new MyViewControllerGeneric<MyType>(new IntPtr(DateTime.Now.Ticks)
both throw a SigAbort
Any Help highly appreciated.
The IntPtr handle is not something you should be passing in.
Use this constructor instead:
public MyViewControllerGeneric<T> : MyViewController{
public MyViewControllerGeneric() : base(){ }
}
Or this if you need a NIB loaded, depending on your base class:
public MyViewControllerGeneric<T> : MyViewController{
public MyViewControllerGeneric() : base("MyViewControllerGeneric", null){ }
}