Trouble getting the book's code to work using Swift 4.1


#1

I’ve entered the code for printing RaiseMan from the book and made changes to get it to compile with Swift 4.1. When I run it, I get error messages when I try to print. Here is what I have so far:

In EmployeesPrintingView.Swift:

import Cocoa

private let font: NSFont = NSFont.userFixedPitchFont(ofSize: 12.0)!
// textAttrubutes is defined in the book as [String : AnyObject]  This did not work, I chnged it to:
private let textAttributes: [NSAttributedStringKey : AnyObject] = [NSAttributedStringKey.font : font]
private let lineHeight: CGFloat = font.capHeight * 2.0

class EmployeesPrintingView: NSView {

let employees: [Employee]

var pageRect = NSRect()
var linesPerPage: Int = 0
var currentPage: Int = 0

// MARK: - Lifecycle

init(employees: [Employee]) {
	self.employees = employees
	super.init(frame: NSRect())
}

required init?(coder: NSCoder) {
	fatalError("EmployeePrintingView cannot be instantiated from a nib.")
}

// MARK: - Pagination

override func knowsPageRange(_ range: NSRangePointer) -> Bool {
	let printOperation = NSPrintOperation.current!
	let printInfo: NSPrintInfo = printOperation.printInfo
	
	// Where can I draw?
	pageRect = printInfo.imageablePageBounds
	let newFrame = NSRect(origin: CGPoint(), size: printInfo.paperSize)
	frame = newFrame
	
	// How many lines per page?
	linesPerPage = Int(pageRect.height / lineHeight)
	
	// Construct the range to return
	var rangeOut = NSRange(location: 0, length: 0)
	
	// Pages are 1-based.  That is, the first page is page 1
	rangeOut.location = 1
	
	// How many pages will it take?
	rangeOut.length = employees.count / linesPerPage
	if employees.count % linesPerPage > 0 {
		rangeOut.length = rangeOut.length + 1		// different from book
	}
	
	// Return the newly constructed range, rangeOut, via the range pointer
	range.pointee = rangeOut
	
	return true
}

override func rectForPage(_ page: Int) -> NSRect {
	// Note the current page
	// Although Cocoa uses 1-based indexing for the page number
	// 		it's easier not to do that here.
	
	currentPage = page - 1
	
	// return the same page rect every time
	return pageRect
}

// MARK: - Drawing

// The origin of the view is at the upper-left corner
override var isFlipped: Bool {
	return true
}

override func draw(_ dirtyRect: NSRect) {
    var nameRect = NSRect(x: pageRect.minX,
						  y: 0,
						  width: 200.0,
						  height: lineHeight)
	var raiseRect = NSRect(x: nameRect.maxX,
						   y: 0,
						   width: 100.0,
						   height: lineHeight)
	
	for indexOnPage in 0..<linesPerPage {
		let indexInEmployees = currentPage * linesPerPage + indexOnPage
		if indexInEmployees >= employees.count {
			break
		}
		
		let employee = employees[indexInEmployees]
		
		// Draw index and name
		// Note textAttrutes definition has been changed - see definition at top
		nameRect.origin.y = pageRect.minY + CGFloat(indexOnPage) * lineHeight
		let employeeName = (employee.name ?? "")
		let indexAndName = "\(indexInEmployees) \(employeeName)"
		indexAndName.draw(in: nameRect, withAttributes: textAttributes)
		
		// Draw raise
		raiseRect.origin.y = nameRect.minY
		let raise = String(format: "%4.1f%%", employee.raise * 100)
		let raiseString = raise
		raiseString.draw(in: raiseRect, withAttributes: textAttributes)
	}
    }
}

Then in Document.Swift I have:

override func printOperation(withSettings printSettings: [NSPrintInfo.AttributeKey : Any])
	throws -> NSPrintOperation {
		let employeesPrintingView = EmployeesPrintingView(employees: employees)
		let printInfo: NSPrintInfo = self.printInfo
		let printOperation = NSPrintOperation(view: employeesPrintingView, printInfo: printInfo)
		return printOperation
}

When I run it and click on Print… these are the error messages I receive:

2018-05-27 11:52:44.323204-0500 RaiseMan[5393:747635] Could not find image named 'GenericPostscriptPrinter'.
2018-05-27 11:52:44.326832-0500 RaiseMan[5393:747635] Failed to connect (_appIconImage) outlet from (PMPrintWindowController) to (NSImageView): missing setter or instance variable
2018-05-27 11:52:44.326958-0500 RaiseMan[5393:747635] Failed to connect (_simplePrintView) outlet from (PMPrintWindowController) to (NSView): missing setter or instance variable

I have had no luck finding answered online yet. Still looking.
Unless I’ve found the wrong Programming Guide, the Printing Programming Guide for Mac uses Objective-C, not Swift.


#2

Once again, I found the answer shortly after posting the question (and I had been looking for a while now!).

Step 1. Select the Top level ‘RaiseMan’ in the Project Navigator:

Then click on ‘RaiseMan’ that is just above ‘customize’ and select ‘RaiseMan’ under Targets:

Select ‘Capabilities’, turn on ‘App Sandbox’ and select the ‘Printing’ checkbox

That’s it. Run RaiseMan and printing will now work.

FYI, this is the same place you had to allow Users to read/write